2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2016 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
20 * Major refactoring of ACL code written by:
22 * Radosław Korzeniewski, MMXVI
23 * radoslaw@korzeniewski.net, radekk@inteos.pl
24 * Inteos Sp. z o.o. http://www.inteos.pl/
32 #if defined(HAVE_DARWIN_OS)
34 /* check if ACL support is enabled */
38 * Define the supported ACL streams for this OS
40 static const int os_acl_streams[] = {
41 STREAM_XACL_DARWIN_ACCESS,
45 static const int os_default_acl_streams[] = {
50 * OS specific constructor
54 set_acl_streams(os_acl_streams, os_default_acl_streams);
58 * Translates Bacula internal acl representation into
62 * bacltype - internal Bacula acl type (BACL_type)
64 * acl_type_t - os dependent acl type
65 * when failed - ACL_TYPE_NONE is returned
67 acl_type_t BACL_OSX::get_acltype(BACL_type bacltype){
72 case BACL_TYPE_ACCESS:
73 acltype = ACL_TYPE_ACCESS;
75 #ifdef HAVE_ACL_TYPE_EXTENDED
76 case BACL_TYPE_EXTENDED:
77 acltype = ACL_TYPE_EXTENDED;
82 * sanity check for acl's not supported by OS
84 acltype = (acl_type_t)ACL_TYPE_NONE;
91 * Counts a number of acl entries
96 * int - number of entries in acl object
97 * when no acl entry available or any error then return zero '0'
99 int BACL_OSX::acl_nrentries(acl_t acl){
105 rc = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
108 rc = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
115 * Perform OS specific ACL backup
117 * in/out - check API at bacl.h
119 bRC_BACL BACL_OSX::os_backup_acl (JCR *jcr, FF_PKT *ff_pkt){
121 /* check input data */
122 if (jcr == NULL || ff_pkt == NULL){
123 return bRC_BACL_inval;
126 #if defined(HAVE_ACL_TYPE_EXTENDED)
128 * Use BACL_TYPE_EXTENDED only when available
130 Dmsg0(400, "MacOSX Extended ACL computed\n");
131 if (os_get_acl(jcr, BACL_TYPE_EXTENDED) == bRC_BACL_fatal){
132 return bRC_BACL_fatal;
135 Dmsg0(400, "MacOSX standard ACL computed\n");
136 if (os_get_acl(jcr, BACL_TYPE_ACCESS) == bRC_BACL_fatal){
137 return bRC_BACL_fatal;
141 return send_acl_stream(jcr, STREAM_XACL_DARWIN_ACCESS);
145 * Perform OS specific ACL restore
147 * in/out - check API at bacl.h
149 bRC_BACL BACL_OSX::os_restore_acl (JCR *jcr, int stream, char *content, uint32_t length){
151 #if defined(HAVE_ACL_TYPE_EXTENDED)
152 return os_set_acl(jcr, BACL_TYPE_EXTENDED, content, length);
154 return os_set_acl(jcr, BACL_TYPE_ACCESS, content, length);
159 * Low level OS specific runtime to get ACL data from file. The ACL data is set in internal content buffer
161 * in/out - check API at bacl.h
163 bRC_BACL BACL_OSX::os_get_acl(JCR *jcr, BACL_type bacltype){
168 bRC_BACL rc = bRC_BACL_ok;
170 /* check input data */
172 return bRC_BACL_inval;
175 acltype = get_acltype(bacltype);
176 acl = acl_get_file(jcr->last_fname, acltype);
179 Dmsg1(400, "OS_ACL read from file: %s\n",jcr->last_fname);
180 if (acl_nrentries(acl) == 0){
184 if ((acltext = acl_to_text(acl, NULL)) != NULL){
185 set_content(acltext);
193 Mmsg2(jcr->errmsg, _("acl_to_text error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
194 Dmsg2(100, "acl_to_text error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
202 /* fs does not support acl, skip it */
203 Dmsg0(400, "Wow, ACL is not supported on this filesystem\n");
204 clear_flag(BACL_FLAG_NATIVE);
209 /* Some real error */
210 Mmsg2(jcr->errmsg, _("acl_get_file error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
211 Dmsg2(100, "acl_get_file error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
222 * it is a bit of hardcore to clear a poolmemory with a NULL pointer,
223 * but it is working, hehe :)
224 * you may ask why it is working? it is simple, a pm_strcpy function is handling
225 * a null pointer with a substitiution of empty string.
232 * Low level OS specific runtime to set ACL data on file
234 * in/out - check API at bacl.h
236 bRC_BACL BACL_OSX::os_set_acl(JCR *jcr, BACL_type bacltype, char *content, uint32_t length){
241 /* check input data */
242 if (jcr == NULL || content == NULL){
243 return bRC_BACL_inval;
246 acl = acl_from_text(content);
250 Mmsg2(jcr->errmsg, _("acl_from_text error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
251 Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n", content, jcr->last_fname, be.bstrerror());
252 return bRC_BACL_error;
255 acltype = get_acltype(bacltype);
258 * Restore the ACLs, but don't complain about links which really should
259 * not have attributes, and the file it is linked to may not yet be restored.
260 * This is only true for the old acl streams as in the new implementation we
261 * don't save acls of symlinks (which cannot have acls anyhow)
263 if (acl_set_file(jcr->last_fname, acltype, acl) != 0 && jcr->last_type != FT_LNK){
271 * If the filesystem reports it doesn't support ACLs we clear the
272 * BACL_FLAG_NATIVE flag so we skip ACL restores on all other files
273 * on the same filesystem. The BACL_FLAG_NATIVE flag gets set again
274 * when we change from one filesystem to an other.
276 clear_flag(BACL_FLAG_NATIVE);
277 Mmsg1(jcr->errmsg, _("acl_set_file error on file \"%s\": filesystem doesn't support ACLs\n"), jcr->last_fname);
278 Dmsg2(100, "acl_set_file error acl=%s file=%s filesystem doesn't support ACLs\n", content, jcr->last_fname);
280 return bRC_BACL_error;
282 Mmsg2(jcr->errmsg, _("acl_set_file error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
283 Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n", content, jcr->last_fname, be.bstrerror());
285 return bRC_BACL_error;
292 #endif /* HAVE_ACL */
294 #endif /* HAVE_DARWIN_OS */