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 and XATTR 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 * Define the supported ACL streams for this OS
36 static const int os_acl_streams[] = {
37 STREAM_XACL_DARWIN_ACCESS,
41 static const int os_default_acl_streams[] = {
46 * Define the supported XATTR streams for this OS
48 static const int os_xattr_streams[] = {
49 STREAM_XACL_DARWIN_XATTR,
53 static const char *os_xattr_acl_skiplist[] = {
54 "com.apple.system.Security",
58 static const char *os_xattr_skiplist[] = {
59 "com.apple.system.extendedsecurity",
60 "com.apple.ResourceFork",
65 * OS Specyfic constructor
69 set_acl_streams(os_acl_streams, os_default_acl_streams);
70 set_xattr_streams(os_xattr_streams);
71 set_xattr_skiplists(os_xattr_skiplist, os_xattr_acl_skiplist);
75 * Translates Bacula internal acl representation into
79 * xacltype - internal Bacula acl type (XACL_type)
81 * acl_type_t - os dependent acl type
82 * when failed - ACL_TYPE_NONE is returned
84 acl_type_t XACL_OSX::get_acltype(XACL_type xacltype){
89 case XACL_TYPE_ACCESS:
90 acltype = ACL_TYPE_ACCESS;
92 #ifdef HAVE_ACL_TYPE_EXTENDED
93 case XACL_TYPE_EXTENDED:
94 acltype = ACL_TYPE_EXTENDED;
99 * sanity check for acl's not supported by OS
101 acltype = (acl_type_t)ACL_TYPE_NONE;
108 * Counts a number of acl entries
113 * int - number of entries in acl object
114 * when no acl entry available or any error then return zero '0'
116 int XACL_OSX::acl_nrentries(acl_t acl){
122 rc = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
125 rc = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
132 * Perform OS specyfic ACL backup
134 * in/out - check API at xacl.h
136 bRC_XACL XACL_OSX::os_backup_acl (JCR *jcr, FF_PKT *ff_pkt){
138 /* check input data */
139 if (jcr == NULL || ff_pkt == NULL){
140 return bRC_XACL_inval;
143 #if defined(HAVE_ACL_TYPE_EXTENDED)
145 * Use XACL_TYPE_EXTENDED only when available
147 Dmsg0(400, "MacOSX Extended ACL computed\n");
148 if (os_get_acl(jcr, XACL_TYPE_EXTENDED) == bRC_XACL_fatal){
149 return bRC_XACL_fatal;
152 Dmsg0(400, "MacOSX standard ACL computed\n");
153 if (os_get_acl(jcr, XACL_TYPE_ACCESS) == bRC_XACL_fatal){
154 return bRC_XACL_fatal;
158 return send_acl_stream(jcr, STREAM_XACL_DARWIN_ACCESS);
162 * Perform OS specyfic ACL restore
164 * in/out - check API at xacl.h
166 bRC_XACL XACL_OSX::os_restore_acl (JCR *jcr, int stream, char *content, uint32_t length){
168 #if defined(HAVE_ACL_TYPE_EXTENDED)
169 return os_set_acl(jcr, XACL_TYPE_EXTENDED, content, length);
171 return os_set_acl(jcr, XACL_TYPE_ACCESS, content, length);
176 * Perform OS specyfic extended attribute backup
178 * in/out - check API at xacl.h
180 bRC_XACL XACL_OSX::os_backup_xattr (JCR *jcr, FF_PKT *ff_pkt){
181 return generic_backup_xattr(jcr, ff_pkt);
185 * Perform OS specyfic XATTR restore. Runtime is called only when stream is supported by OS.
187 * in/out - check API at xacl.h
189 bRC_XACL XACL_OSX::os_restore_xattr (JCR *jcr, int stream, char *content, uint32_t length){
190 return generic_restore_xattr(jcr, stream);
194 * Low level OS specyfic runtime to get ACL data from file. The ACL data is set in internal content buffer
196 * in/out - check API at xacl.h
198 bRC_XACL XACL_OSX::os_get_acl(JCR *jcr, XACL_type xacltype){
203 bRC_XACL rc = bRC_XACL_ok;
205 /* check input data */
207 return bRC_XACL_inval;
210 acltype = get_acltype(xacltype);
211 acl = acl_get_file(jcr->last_fname, acltype);
214 Dmsg1(400, "OS_ACL read from file: %s\n",jcr->last_fname);
215 if (acl_nrentries(acl) == 0){
219 if ((acltext = acl_to_text(acl, NULL)) != NULL){
220 set_content(acltext);
228 Mmsg2(jcr->errmsg, _("acl_to_text error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
229 Dmsg2(100, "acl_to_text error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
237 /* fs does not support acl, skip it */
238 Dmsg0(400, "Wow, ACL is not supported on this filesystem\n");
239 clear_flag(XACL_FLAG_NATIVE);
244 /* Some real error */
245 Mmsg2(jcr->errmsg, _("acl_get_file error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
246 Dmsg2(100, "acl_get_file error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
257 * it is a bit of hardcore to clear a poolmemory with a NULL pointer,
258 * but it is working, hehe :)
259 * you may ask why it is working? it is simple, a pm_strcpy function is handling
260 * a null pointer with a substitiution of empty string.
267 * Low level OS specyfic runtime to set ACL data on file
269 * in/out - check API at xacl.h
271 bRC_XACL XACL_OSX::os_set_acl(JCR *jcr, XACL_type xacltype, char *content, uint32_t length){
276 /* check input data */
277 if (jcr == NULL || content == NULL){
278 return bRC_XACL_inval;
281 acl = acl_from_text(content);
285 Mmsg2(jcr->errmsg, _("acl_from_text error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
286 Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n", content, jcr->last_fname, be.bstrerror());
287 return bRC_XACL_error;
290 acltype = get_acltype(xacltype);
293 * Restore the ACLs, but don't complain about links which really should
294 * not have attributes, and the file it is linked to may not yet be restored.
295 * This is only true for the old acl streams as in the new implementation we
296 * don't save acls of symlinks (which cannot have acls anyhow)
298 if (acl_set_file(jcr->last_fname, acltype, acl) != 0 && jcr->last_type != FT_LNK){
306 * If the filesystem reports it doesn't support ACLs we clear the
307 * XACL_FLAG_NATIVE flag so we skip ACL restores on all other files
308 * on the same filesystem. The XACL_FLAG_NATIVE flag gets set again
309 * when we change from one filesystem to an other.
311 clear_flag(XACL_FLAG_NATIVE);
312 Mmsg1(jcr->errmsg, _("acl_set_file error on file \"%s\": filesystem doesn't support ACLs\n"), jcr->last_fname);
313 Dmsg2(100, "acl_set_file error acl=%s file=%s filesystem doesn't support ACLs\n", content, jcr->last_fname);
315 return bRC_XACL_error;
317 Mmsg2(jcr->errmsg, _("acl_set_file error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
318 Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n", content, jcr->last_fname, be.bstrerror());
320 return bRC_XACL_error;
328 * Return a list of xattr names in newly allocated pool memory and a length of the allocated buffer.
329 * It allocates a memory with poolmem subroutines every time a function is called, so it must be freed
332 * in/out - check API at xacl.h
334 bRC_XACL XACL_OSX::os_get_xattr_names (JCR *jcr, POOLMEM ** pxlist, uint32_t * xlen){
339 /* check input data */
340 if (jcr == NULL || xlen == NULL || pxlist == NULL){
341 return bRC_XACL_inval;
343 /* get the length of the extended attributes */
344 len = listxattr(jcr->last_fname, NULL, 0, XATTR_NOFOLLOW);
351 /* no file available, skip it */
352 return bRC_XACL_skip;
354 /* no xattr supported on filesystem, clear a flag and skip it */
355 clear_flag(XACL_FLAG_NATIVE);
357 return bRC_XACL_skip;
359 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
360 Dmsg2(100, "llistxattr error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
361 return bRC_XACL_error;
366 /* xattr available but empty, skip it */
367 return bRC_XACL_skip;
373 * allocate memory for the extented attribute list
374 * default size is a 4k for PM_BSOCK, which should be sufficient on almost all
375 * Linux system where xattrs a limited in size to single filesystem block ~4kB
376 * so we need to check required size
378 list = get_pool_memory(PM_BSOCK);
379 list = check_pool_memory_size(list, len + 1);
380 memset(list, 0, len + 1);
382 /* get the list of extended attributes names for a file */
383 len = listxattr(jcr->last_fname, list, len, XATTR_NOFOLLOW);
390 /* no file available, skip it, first release allocated memory */
391 free_pool_memory(list);
392 return bRC_XACL_skip;
394 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
395 Dmsg2(100, "llistxattr error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
396 free_pool_memory(list);
397 return bRC_XACL_error;
404 /* ensure a list is nul terminated */
406 /* setup return data */
413 * Return a value of the requested attribute name and a length of the allocated buffer.
414 * It allocates a memory with poolmem subroutines every time a function is called, so it must be freed
417 * in/out - check API at xacl.h
419 bRC_XACL XACL_OSX::os_get_xattr_value (JCR *jcr, char * name, char ** pvalue, uint32_t * plen){
424 /* check input data */
425 if (jcr == NULL || name == NULL || plen == NULL || pvalue == NULL){
426 return bRC_XACL_inval;
429 /* get the length of the value for extended attribute */
430 len = getxattr(jcr->last_fname, name, NULL, 0, 0, XATTR_NOFOLLOW);
437 /* no file available, skip it */
438 return bRC_XACL_skip;
440 /* XXX: what about ENOATTR error value? */
441 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
442 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
443 return bRC_XACL_error;
453 * allocate memory for the extented attribute value
454 * default size is a 256B for PM_MESSAGE, so we need to check required size
456 value = get_pool_memory(PM_MESSAGE);
457 value = check_pool_memory_size(value, len + 1);
458 memset(value, 0, len + 1);
459 /* value is not empty, get a data */
460 len = getxattr(jcr->last_fname, name, value, len, 0, XATTR_NOFOLLOW);
467 /* no file available, skip it, first release allocated memory */
468 free_pool_memory(value);
469 return bRC_XACL_skip;
471 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
472 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
473 free_pool_memory(value);
474 return bRC_XACL_error;
481 /* ensure a value is nul terminated */
488 /* setup return data */
495 * Low level OS specyfic runtime to set extended attribute on file
497 * in/out - check API at xacl.h
499 bRC_XACL XACL_OSX::os_set_xattr (JCR *jcr, XACL_xattr *xattr){
501 /* check input data */
502 if (jcr == NULL || xattr == NULL){
503 return bRC_XACL_inval;
506 /* set extattr on file */
507 if (setxattr(jcr->last_fname, xattr->name, xattr->value, xattr->value_len, 0, XATTR_NOFOLLOW) != 0){
515 * If the filesystem reports it doesn't support XATTR we clear the
516 * XACL_FLAG_NATIVE flag so we skip XATTR restores on all other files
517 * on the same filesystem. The XACL_FLAG_NATIVE flag gets set again
518 * when we change from one filesystem to an other.
520 clear_flag(XACL_FLAG_NATIVE);
521 Mmsg1(jcr->errmsg, _("setxattr error on file \"%s\": filesystem doesn't support XATTR\n"), jcr->last_fname);
522 Dmsg3(100, "setxattr error name=%s value=%s file=%s filesystem doesn't support XATTR\n", xattr->name, xattr->value, jcr->last_fname);
525 Mmsg2(jcr->errmsg, _("setxattr error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
526 Dmsg2(100, "setxattr error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
527 return bRC_XACL_error;
533 #endif /* HAVE_DARWIN_OS */