2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2017 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/
27 * A specialized class to handle ACL and XATTR in Bacula Enterprise.
28 * The runtime consist of two parts:
29 * 1. OS independent class: XACL
30 * 2. OS dependent subclass: XACL_*
32 * OS dependent subclasses are available for the following OS:
34 * - FreeBSD (POSIX and NFSv4/ZFS acls)
36 * - Solaris (POSIX and NFSv4/ZFS acls)
38 * OS dependend subclasses in progress:
39 * - AIX (pre-5.3 and post 5.3 acls, acl_get and aclx_get interface)
44 * OS independent class support AFS acls using the pioctl interface.
46 * ACLs are saved in OS native text format provided by acl(3) API and uses
47 * different streams for all different platforms.
48 * XATTRs are saved in OS independent format (Bacula own) and uses different streams
49 * for all different platforms. In theory it is possible to restore XATTRs from
50 * particular OS on different OS platform. But this functionality is not available.
51 * Above behavior is a backward compatibility with previous Bacula implementation
52 * we need to maintain.
54 * During OS specyfic implementation of XACL you need to implement a following methods:
56 * [xacl] - indicates xacl function/method to call
57 * [os] - indicates OS specyfic function, which could be different on specyfic OS
58 * (we use a Linux api calls as an example)
60 * ::os_get_acl(JCR *jcr, XACL_type xacltype)
62 * 1. get binary form of the acl - acl_get_file[os]
63 * 2. check if acl is trivial if required - call acl_issimple[xacl]
64 * 3. translate binary form into text representation - acl_to_text[os]
65 * 4. save acl text into content - set_content[xacl]
66 * 5. if acl not supported on filesystem - call clear_flag(XACL_FLAG_NATIVE)[xacl]
68 * ::os_backup_acl (JCR *jcr, FF_PKT *ff_pkt)
70 * 1. call os_get_acl[xacl] for all supported ACL_TYPES
71 * 2. call send_acl_stream[xacl] for all supported ACL_STREAMS
73 * ::os_set_acl(JCR *jcr, XACL_type xacltype, char *content, uint32_t length)
75 * 1. prepare acl binary form from text representation stored in content - acl_from_text[os]
76 * 2. set acl on file - acl_set_file[os]
77 * 3. if acl not supported on filesystem, clear_flag(XACL_FLAG_NATIVE)
79 * ::os_restore_acl (JCR *jcr, int stream, char *content, uint32_t length)
81 * 1. call os_set_acl for all supported ACL_TYPES
83 * ::os_get_xattr_names (JCR *jcr, int namespace, POOLMEM ** pxlist, uint32_t * xlen)
85 * 1. get a size of the extended attibutes list for the file - llistxattr[os]
86 * in most os'es it is required to have a sufficient space for attibutes list
87 * and we wont allocate too much and too low space
88 * 2. allocate the buffer of required space
89 * 3. get an extended attibutes list for file - llistxattr[os]
90 * 4. return allocated space buffer in pxlist and length of the buffer in xlen
92 * ::os_get_xattr_value (JCR *jcr, char * name, char ** pvalue, uint32_t * plen)
94 * 1. get a size of the extended attibute value for the file - lgetxattr[os]
95 * in most os'es it is required to have a sufficient space for attibute value
96 * and we wont allocate too much and too low space
97 * 2. allocate the buffer of required space
98 * 3. get an extended attibute value for file - lgetxattr[os]
99 * 4. return allocated space buffer in pvalue and length of the buffer in plen
101 * ::os_backup_xattr (JCR *jcr, FF_PKT *ff_pkt)
103 * 1. get a list of extended attributes (name and value) for a file; in most implementations
104 * it require to get a separate list of attributes names and separate values for every name,
106 * 1A. get a list of xattr attribute names available on file - os_get_xattr_names[xacl]
107 * 1B. for every attribute name get a value - os_get_xattr_value[xacl]
108 * You should skip some OS specyfic attributes like ACL attributes or NFS4; you can use
109 * check_xattr_skiplists[xacl] for this
110 * 1C. build a list [type alist] of name/value pairs stored in XACL_xattr struct
111 * 2. if the xattr list is not empty then serialize the list using serialize_xattr_stream[xacl]
112 * 3. call send_xattr_stream[xacl]
114 * ::os_set_xattr (JCR *jcr, XACL_xattr *xattr)
116 * 1. set xattr on file using name/value in xattr - lsetxattr[os]
117 * 2. if xattr not supported on filesystem - call clear_flag(XACL_FLAG_NATIVE)[xacl]
119 * ::os_restore_xattr (JCR *jcr, int stream, char *content, uint32_t length)
121 * 1. unserialize backup stream
122 * 2. for every extended attribute restored call os_set_xattr[xacl] to set this attribute on file
129 * This is a constructor of the base XACL class which is OS independent
131 * - for initialization it uses ::init()
139 * This is a destructor of the XACL class
142 free_pool_memory(content);
146 * Initialization routine
147 * - initializes all variables to required status
148 * - allocates required memory
151 #if defined(HAVE_ACL)
157 #if defined(HAVE_XATTR)
163 /* generic variables */
164 flags = XACL_FLAG_NONE;
166 content = get_pool_memory(PM_BSOCK); /* it is better to have a 4k buffer */
171 default_acl_streams = NULL;
172 xattr_streams = NULL;
173 xattr_skiplist = NULL;
174 xattr_acl_skiplist = NULL;
178 * Enables ACL handling in runtime, could be disabled with disable_acl
179 * when ACL is not configured then cannot change status
181 void XACL::enable_acl(){
182 #if defined(HAVE_ACL)
188 * Disables ACL handling in runtime, could be enabled with enable_acl
189 * when ACL is configured
191 void XACL::disable_acl(){
196 * Enables XATTR handling in runtime, could be disabled with disable_xattr
197 * when XATTR is not configured then cannot change status
199 void XACL::enable_xattr(){
206 * Disables XATTR handling in runtime, could be enabled with enable_xattr
207 * when XATTR is configured
209 void XACL::disable_xattr(){
214 * Copies a text into a content variable and sets a constent_len respectively
217 * text - a standard null terminated string
219 * pointer to content variable to use externally
221 POOLMEM * XACL::set_content(char *text){
222 content_len = pm_strcpy(&content, text);
227 * Copies a data with length of len into a content variable
230 * data - data pointer to copy into content buffer
232 * pointer to content variable to use externally
234 POOLMEM * XACL::set_content(char *data, int len){
235 content_len = pm_memcpy(&content, data, len);
240 * Check if we changed the device,
241 * if so setup a flags
244 * jcr - Job Control Record
246 * bRC_XACL_ok - change of device checked and finish succesful
247 * bRC_XACL_error - encountered error
248 * bRC_XACL_skip - cannot verify device - no file found
249 * bRC_XACL_inval - invalid input data
251 bRC_XACL XACL::check_dev (JCR *jcr){
256 /* sanity check of input variables */
257 if (jcr == NULL || jcr->last_fname == NULL){
258 return bRC_XACL_inval;
261 lst = lstat(jcr->last_fname, &st);
267 return bRC_XACL_skip;
269 Mmsg2(jcr->errmsg, _("Unable to stat file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
270 Dmsg2(100, "Unable to stat file \"%s\": ERR=%s\n", jcr->last_fname, be.bstrerror());
271 return bRC_XACL_error;
279 check_dev(jcr, st.st_dev);
285 * Check if we changed the device, if so setup a flags
288 * jcr - Job Control Record
290 * internal flags status set
292 void XACL::check_dev (JCR *jcr, uint32_t dev){
294 /* sanity check of input variables */
295 if (jcr == NULL || jcr->last_fname == NULL){
299 if (current_dev != dev){
300 flags = XACL_FLAG_NONE;
301 #if defined(HAVE_AFS_ACL)
302 /* handle special fs: AFS */
303 if (fstype_equals(jcr->last_fname, "afs")){
304 set_flag(XACL_FLAG_AFS);
306 set_flag(XACL_FLAG_NATIVE);
309 set_flag(XACL_FLAG_NATIVE);
316 * It sends a stream located in this->content to Storage Daemon, so the main Bacula
317 * backup loop is free from this. It sends a header followed by data.
320 * jcr - Job Control Record
321 * stream - a stream number to save
323 * bRC_XACL_inval - when supplied variables are incorrect
324 * bRC_XACL_fatal - when we can't send data to the SD
325 * bRC_XACL_ok - send finish without errors
327 bRC_XACL XACL::send_acl_stream(JCR *jcr, int stream){
331 #ifdef FD_NO_SEND_TEST
335 /* sanity check of input variables */
336 if (jcr == NULL || jcr->store_bsock == NULL){
337 return bRC_XACL_inval;
339 if (content_len <= 0){
343 sd = jcr->store_bsock;
345 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)){
346 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), sd->bstrerror());
347 return bRC_XACL_fatal;
350 /* send the buffer to the storage deamon */
351 Dmsg1(400, "Backing up ACL <%s>\n", content);
354 sd->msglen = content_len + 1;
358 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), sd->bstrerror());
359 return bRC_XACL_fatal;
362 jcr->JobBytes += sd->msglen;
364 if (!sd->signal(BNET_EOD)){
365 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), sd->bstrerror());
366 return bRC_XACL_fatal;
369 Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
374 * It sends a stream located in this->content to Storage Daemon, so the main Bacula
375 * backup loop is free from this. It sends a header followed by data.
378 * jcr - Job Control Record
379 * stream - a stream number to save
381 * bRC_XACL_inval - when supplied variables are incorrect
382 * bRC_XACL_fatal - when we can't send data to the SD
383 * bRC_XACL_ok - send finish without errors
385 bRC_XACL XACL::send_xattr_stream(JCR *jcr, int stream){
389 #ifdef FD_NO_SEND_TEST
393 /* sanity check of input variables */
394 if (jcr == NULL || jcr->store_bsock == NULL){
395 return bRC_XACL_inval;
397 if (content_len <= 0){
401 sd = jcr->store_bsock;
403 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)){
404 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), sd->bstrerror());
405 return bRC_XACL_fatal;
408 /* send the buffer to the storage deamon */
409 Dmsg1(400, "Backing up XATTR <%s>\n", content);
412 sd->msglen = content_len;
416 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), sd->bstrerror());
417 return bRC_XACL_fatal;
420 jcr->JobBytes += sd->msglen;
422 if (!sd->signal(BNET_EOD)){
423 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), sd->bstrerror());
424 return bRC_XACL_fatal;
426 Dmsg1(200, "XATTR of file: %s successfully backed up!\n", jcr->last_fname);
431 * The main public backup method for ACL
434 * jcr - Job Control Record
435 * ff_pkt - file backup record
437 * bRC_XACL_fatal - when ACL backup is not compiled in Bacula
438 * bRC_XACL_ok - backup finish without problems
439 * bRC_XACL_error - when you can't backup acl data because some error
441 bRC_XACL XACL::backup_acl (JCR *jcr, FF_PKT *ff_pkt){
443 #if !defined(HAVE_ACL) && !defined(HAVE_AFS_ACL)
444 Jmsg(jcr, M_FATAL, 0, "ACL backup requested but not configured in Bacula.\n");
445 return bRC_XACL_fatal;
447 /* sanity check of input variables and verify if engine is enabled */
448 if (acl_ena && jcr != NULL && ff_pkt != NULL){
449 /* acl engine enabled, proceed */
452 * No acl request for link or plugin
454 * TODO: it should be possible to handle ACL/XATTR for cmd plugins
456 if (!(ff_pkt->flags & FO_ACL && ff_pkt->type != FT_LNK && !ff_pkt->cmd_plugin)){
461 check_dev(jcr, ff_pkt->statp.st_dev);
463 #if defined(HAVE_AFS_ACL)
464 if (flags & XACL_FLAG_AFS){
465 Dmsg0(400, "make AFS ACL call\n");
466 rc = afs_backup_acl(jcr, ff_pkt);
471 #if defined(HAVE_ACL)
472 if (flags & XACL_FLAG_NATIVE){
473 Dmsg0(400, "make Native ACL call\n");
474 rc = os_backup_acl(jcr, ff_pkt);
476 /* skip acl backup */
481 #if defined(HAVE_AFS_ACL)
484 if (rc == bRC_XACL_error){
485 if (acl_nr_errors < ACL_MAX_ERROR_PRINT_PER_JOB){
486 if (!jcr->errmsg[0]){
487 Jmsg(jcr, M_WARNING, 0, "No OS ACL configured.\n");
489 Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
502 * The main public restore method for ACL
505 * jcr - Job Control Record
506 * stream - a backup stream type number to restore_acl
507 * data - a potinter to the data stream to restore
508 * length - a data stream length
510 * bRC_XACL_fatal - when ACL restore is not compiled in Bacula
511 * bRC_XACL_ok - restore finish without problems
512 * bRC_XACL_error - when you can't restore a stream because some error
514 bRC_XACL XACL::restore_acl (JCR *jcr, int stream, char *data, uint32_t length){
516 #if !defined(HAVE_ACL) && !defined(HAVE_AFS_ACL)
517 Jmsg(jcr, M_FATAL, 0, "ACL retore requested but not configured in Bacula.\n");
518 return bRC_XACL_fatal;
520 /* sanity check of input variables and verify if engine is enabled */
521 if (acl_ena && jcr != NULL && data != NULL){
522 /* acl engine enabled, proceed */
524 bRC_XACL rc = check_dev(jcr);
535 /* copy a data into a content buffer */
536 set_content(data, length);
539 #if defined(HAVE_AFS_ACL)
540 case STREAM_XACL_AFS_TEXT:
541 if (flags & XACL_FLAG_AFS){
542 return afs_restore_acl(jcr, stream);
545 * Increment error count but don't log an error again for the same filesystem.
551 #if defined(HAVE_ACL)
552 case STREAM_UNIX_ACCESS_ACL:
553 case STREAM_UNIX_DEFAULT_ACL:
554 if (flags & XACL_FLAG_NATIVE){
555 return os_restore_acl(jcr, stream, content, content_len);
562 if (flags & XACL_FLAG_NATIVE){
563 for (a = 0; acl_streams[a] > 0; a++){
564 if (acl_streams[a] == stream){
565 return os_restore_acl(jcr, stream, content, content_len);
568 for (a = 0; default_acl_streams[a] > 0; a++){
569 if (default_acl_streams[a] == stream){
570 return os_restore_acl(jcr, stream, content, content_len);
583 /* cannot find a valid stream to support */
584 Qmsg2(jcr, M_WARNING, 0, _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"), jcr->last_fname, stream);
585 return bRC_XACL_error;
592 * The main public backup method for XATTR
595 * jcr - Job Control Record
596 * ff_pkt - file backup record
598 * bRC_XACL_fatal - when XATTR backup is not compiled in Bacula
599 * bRC_XACL_ok - backup finish without problems
600 * bRC_XACL_error - when you can't backup xattr data because some error
602 bRC_XACL XACL::backup_xattr (JCR *jcr, FF_PKT *ff_pkt){
604 #if !defined(HAVE_XATTR)
605 Jmsg(jcr, M_FATAL, 0, "XATTR backup requested but not configured in Bacula.\n");
606 return bRC_XACL_fatal;
608 /* sanity check of input variables and verify if engine is enabled */
609 if (xattr_ena && jcr != NULL && ff_pkt != NULL){
610 /* xattr engine enabled, proceed */
613 * No xattr request for plugin
615 * TODO: it should be possible to handle ACL/XATTR for cmd plugins
617 if (!(ff_pkt->flags & FO_XATTR && !ff_pkt->cmd_plugin)){
622 check_dev(jcr, ff_pkt->statp.st_dev);
624 if (flags & XACL_FLAG_NATIVE){
625 Dmsg0(400, "make Native XATTR call\n");
626 rc = os_backup_xattr(jcr, ff_pkt);
628 /* skip xattr backup */
632 if (rc == bRC_XACL_error){
633 if (xattr_nr_errors < XATTR_MAX_ERROR_PRINT_PER_JOB){
634 if (!jcr->errmsg[0]){
635 Jmsg(jcr, M_WARNING, 0, "No OS XATTR configured.\n");
637 Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
650 * The main public restore method for XATTR
653 * jcr - Job Control Record
654 * stream - a backup stream type number to restore_acl
655 * data - a potinter to the data stream to restore
656 * length - a data stream length
658 * bRC_XACL_fatal - when XATTR restore is not compiled in Bacula
659 * bRC_XACL_ok - restore finish without problems
660 * bRC_XACL_error - when you can't restore a stream because some error
662 bRC_XACL XACL::restore_xattr (JCR *jcr, int stream, char *data, uint32_t length){
664 #if !defined(HAVE_XATTR)
665 Jmsg(jcr, M_FATAL, 0, "XATTR retore requested but not configured in Bacula.\n");
666 return bRC_XACL_fatal;
668 /* sanity check of input variables and verify if engine is enabled */
669 if (xattr_ena && jcr != NULL && data != NULL){
670 /* xattr engine enabled, proceed */
672 bRC_XACL rc = check_dev(jcr);
683 /* copy a data into a content buffer */
684 set_content(data, length);
686 if (flags & XACL_FLAG_NATIVE){
687 for (a = 0; xattr_streams[a] > 0; a++){
688 if (xattr_streams[a] == stream){
689 return os_restore_xattr(jcr, stream, content, content_len);
696 /* cannot find a valid stream to support */
697 Qmsg2(jcr, M_WARNING, 0, _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"), jcr->last_fname, stream);
698 return bRC_XACL_error;
705 * Performs a generic ACL backup using OS specyfic methods for
706 * getting acl data from file
709 * jcr - Job Control Record
710 * ff_pkt - file to backup control package
712 * bRC_XACL_ok - backup of acl's was successful
713 * bRC_XACL_fatal - was an error during acl backup
715 bRC_XACL XACL::generic_backup_acl (JCR *jcr, FF_PKT *ff_pkt){
717 /* sanity check of input variables */
718 if (jcr == NULL || ff_pkt == NULL){
719 return bRC_XACL_inval;
722 if (os_get_acl(jcr, XACL_TYPE_ACCESS) == bRC_XACL_fatal){
723 /* XXX: check if os_get_acl return fatal and decide what to do when error is returned */
724 return bRC_XACL_fatal;
727 if (content_len > 0){
728 if (send_acl_stream(jcr, acl_streams[0]) == bRC_XACL_fatal){
729 return bRC_XACL_fatal;
733 if (ff_pkt->type == FT_DIREND){
734 if (os_get_acl(jcr, XACL_TYPE_DEFAULT) == bRC_XACL_fatal){
735 return bRC_XACL_fatal;
737 if (content_len > 0){
738 if (send_acl_stream(jcr, default_acl_streams[0]) == bRC_XACL_fatal){
739 return bRC_XACL_fatal;
747 * Performs a generic ACL restore using OS specyfic methods for
748 * setting acl data on file.
751 * jcr - Job Control Record
752 * stream - a stream number to restore
754 * bRC_XACL_ok - backup of acl's was successful
755 * bRC_XACL_error - was an error during acl backup
756 * bRC_XACL_fatal - was a fatal error during acl backup or input data is invalid
758 bRC_XACL XACL::generic_restore_acl (JCR *jcr, int stream){
762 /* sanity check of input variables */
764 return bRC_XACL_inval;
768 case STREAM_UNIX_ACCESS_ACL:
769 return os_set_acl(jcr, XACL_TYPE_ACCESS, content, content_len);
770 case STREAM_UNIX_DEFAULT_ACL:
771 return os_set_acl(jcr, XACL_TYPE_DEFAULT, content, content_len);
773 for (count = 0; acl_streams[count] > 0; count++){
774 if (acl_streams[count] == stream){
775 return os_set_acl(jcr, XACL_TYPE_ACCESS, content, content_len);
778 for (count = 0; default_acl_streams[count] > 0; count++){
779 if (default_acl_streams[count] == stream){
780 return os_set_acl(jcr, XACL_TYPE_DEFAULT, content, content_len);
785 return bRC_XACL_error;
789 * Checks if supplied xattr attribute name is indicated on OS specyfic lists
792 * jcr - Job Control Record
793 * ff_pkt - file to backup control package
794 * name - a name of the attribute to check
796 * TRUE - the attribute name is found on OS specyfic skip lists and should be skipped during backup
797 * FALSE - the attribute should be saved on backup stream
799 bool XACL::check_xattr_skiplists (JCR *jcr, FF_PKT *ff_pkt, char * name){
804 /* sanity check of input variables */
805 if (jcr == NULL || ff_pkt == NULL || name == NULL){
810 * On some OSes you also get the acls in the extented attribute list.
811 * So we check if we are already backing up acls and if we do we
812 * don't store the extended attribute with the same info.
814 if (ff_pkt->flags & FO_ACL){
815 for (count = 0; xattr_acl_skiplist[count] != NULL; count++){
816 if (bstrcmp(name, xattr_acl_skiplist[count])){
822 /* on some OSes we want to skip certain xattrs which are in the xattr_skiplist array. */
824 for (count = 0; xattr_skiplist[count] != NULL; count++){
825 if (bstrcmp(name, xattr_skiplist[count])){
837 * Performs generic XATTR backup using OS specyfic methods for
838 * getting xattr data from files - os_get_xattr_names and os_get_xattr_value
841 * jcr - Job Control Record
842 * ff_pkt - file to backup control package
844 * bRC_XACL_ok - xattr backup ok or no xattr to backup found
845 * bRC_XACL_error/fatal - an error or fatal error occurred
846 * bRC_XACL_inval - input variables was invalid
848 bRC_XACL XACL::generic_backup_xattr (JCR *jcr, FF_PKT *ff_pkt){
858 alist *xattr_list = NULL;
863 /* sanity check of input variables */
864 if (jcr == NULL || ff_pkt == NULL){
865 return bRC_XACL_inval;
868 /* xlist is allocated as POOLMEM by os_get_xattr_names */
869 rc = os_get_xattr_names(jcr, &xlist, &xlen);
872 /* it's ok, so go further */
876 /* no xattr available, so skip rest of it */
882 /* follow the list of xattr names and get the values
883 * TODO: change a standard NULL-terminated list of names into alist of structures */
884 for (name = xlist; (name - xlist) + 1 < xlen; name = strchr(name, '\0') + 1){
886 name_len = strlen(name);
887 skip = check_xattr_skiplists(jcr, ff_pkt, name);
888 if (skip || name_len == 0){
889 Dmsg1(100, "Skipping xattr named \"%s\"\n", name);
893 /* value is allocated as POOLMEM by os_get_xattr_value */
894 rc = os_get_xattr_value(jcr, name, &value, &value_len);
897 /* it's ok, so go further */
900 /* no xattr available, so skip rest of it */
901 free_pool_memory(xlist);
905 free_pool_memory(xlist);
910 * we have a name of the extended attribute in the name variable
911 * and value of the extended attribute in the value variable
912 * so we need to build a list
914 xattr = (XACL_xattr*)malloc(sizeof(XACL_xattr));
915 xattr->name_len = name_len;
917 xattr->value_len = value_len;
918 xattr->value = value;
919 /* magic name_len name value_len value */
920 len += sizeof(uint32_t) + sizeof(uint32_t) + name_len + sizeof(uint32_t) + value_len;
922 if (xattr_list == NULL){
923 xattr_list = New(alist(10, not_owned_by_alist));
925 xattr_list->append(xattr);
928 if (xattr_count > 0){
929 /* serialize the stream */
930 rc = serialize_xattr_stream(jcr, len, xattr_list);
931 if (rc != bRC_XACL_ok){
932 Mmsg(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"), jcr->last_fname);
933 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n", jcr->last_fname);
936 /* send data to SD */
937 rc = send_xattr_stream(jcr, xattr_streams[0]);
944 /* free allocated data */
945 if (xattr_list != NULL){
946 foreach_alist(xattr, xattr_list){
951 free_pool_memory(xattr->value);
958 free_pool_memory(xlist);
965 * Performs a generic XATTR restore using OS specyfic methods for
966 * setting XATTR data on file.
969 * jcr - Job Control Record
970 * stream - a stream number to restore
972 * bRC_XACL_ok - restore of acl's was successful
973 * bRC_XACL_error - was an error during xattr restore
974 * bRC_XACL_fatal - was a fatal error during xattr restore
975 * bRC_XACL_inval - input variables was invalid
977 bRC_XACL XACL::generic_restore_xattr (JCR *jcr, int stream){
979 bRC_XACL rc = bRC_XACL_ok;
983 /* sanity check of input variables */
985 return bRC_XACL_inval;
989 xattr_list = New(alist(10, not_owned_by_alist));
991 /* unserialize data */
992 unserialize_xattr_stream(jcr, content, content_len, xattr_list);
994 /* follow the list to set all attributes */
995 foreach_alist(xattr, xattr_list){
996 rc = os_set_xattr(jcr, xattr);
997 if (rc != bRC_XACL_ok){
998 Dmsg2(100, "Failed to set extended attribute %s on file \"%s\"\n", xattr->name, jcr->last_fname);
1004 /* free allocated data */
1005 if (xattr_list != NULL){
1006 foreach_alist(xattr, xattr_list){
1024 * Initialize variables acl_streams and default_acl_streams for a specified OS.
1025 * The rutine should be called from object instance constructor
1028 * pacl - acl streams supported for specyfic OS
1029 * pacl_def - default (directory) acl streams supported for specyfic OS
1031 void XACL::set_acl_streams (const int *pacl, const int *pacl_def){
1034 default_acl_streams = pacl_def;
1038 * Initialize a variable xattr_streams for a specified OS.
1039 * The rutine should be called from object instance constructor
1042 * pxattr - xattr streams supported for specyfic OS
1044 void XACL::set_xattr_streams (const int *pxattr){
1046 xattr_streams = pxattr;
1050 * Initialize variables xattr_skiplist and xattr_acl_skiplist for a specified OS.
1051 * The rutine should be called from object instance constructor
1054 * pxattr - xattr skip list for specyfic OS
1055 * pxattr_acl - xattr acl names skip list for specyfic OS
1057 void XACL::set_xattr_skiplists (const char **pxattr, const char **pxattr_acl){
1059 xattr_skiplist = pxattr;
1060 xattr_acl_skiplist = pxattr_acl;
1064 * Serialize the XATTR stream which will be saved into archive. Serialization elements cames from
1065 * a list and for backward compatibility we produce the same stream as prievous Bacula versions.
1067 * serialized stream consists of the following elements:
1068 * magic - A magic string which makes it easy to detect any binary incompatabilites
1069 * required for backward compatibility
1070 * name_len - The length of the following xattr name
1071 * name - The name of the extended attribute
1072 * value_len - The length of the following xattr data
1073 * value - The actual content of the extended attribute only if value_len is greater then zero
1076 * jcr - Job Control Record
1077 * len - expected serialize length
1078 * list - a list of xattr elements to serialize
1080 * bRC_XACL_ok - when serialization was perfect
1081 * bRC_XACL_inval - when we have invalid variables
1082 * bRC_XACL_error - illegal attribute name
1084 bRC_XACL XACL::serialize_xattr_stream(JCR *jcr, uint32_t len, alist *list){
1089 /* sanity check of input variables */
1090 if (jcr == NULL || list == NULL){
1091 return bRC_XACL_inval;
1094 /* we serialize data direct to content buffer, so check if data fits */
1095 content = check_pool_memory_size(content, len + 20);
1096 ser_begin(content, len + 20);
1098 foreach_alist(xattr, list){
1105 * we have to start with the XATTR_MAGIC for backward compatibility (the magic is silly)
1107 ser_uint32(XATTR_MAGIC);
1108 /* attribute name length and name itself */
1109 if (xattr->name_len > 0 && xattr->name){
1110 ser_uint32(xattr->name_len);
1111 ser_bytes(xattr->name, xattr->name_len);
1113 /* error - name cannot be empty */
1114 Mmsg0(jcr->errmsg, _("Illegal empty xattr attribute name\n"));
1115 Dmsg0(100, "Illegal empty xattr attribute name\n");
1116 return bRC_XACL_error;
1118 /* attibute value length and value itself */
1119 ser_uint32(xattr->value_len);
1120 if (xattr->value_len > 0 && xattr->value){
1121 ser_bytes(xattr->value, xattr->value_len);
1122 Dmsg3(100, "Backup xattr named %s, value %*.s\n", xattr->name, xattr->value_len, xattr->value);
1124 Dmsg1(100, "Backup empty xattr named %s\n", xattr->name);
1128 ser_end(content, len + 20);
1129 content_len = ser_length(content);
1135 * Unserialize XATTR stream on *content and produce a xattr *list which contain
1136 * key => value pairs
1139 * jcr - Job Control Record
1140 * content - a stream content to unserialize
1141 * length - a content length
1142 * list - a pointer to the xattr list to populate
1144 * bRC_XACL_ok - when unserialize was perfect
1145 * bRC_XACL_inval - when we have invalid variables
1146 * list - key/value pairs populated xattr list
1148 bRC_XACL XACL::unserialize_xattr_stream(JCR *jcr, char *content, uint32_t length, alist *list){
1154 /* sanity check of input variables */
1155 if (jcr == NULL || content == NULL || list == NULL){
1156 return bRC_XACL_inval;
1159 unser_begin(content, length);
1160 while (unser_length(content) < length){
1162 * Sanity check of correct stream magic number
1163 * Someone was too paranoid to implement this kind of verification in original Bacula code
1164 * Unfortunate for backward compatibility we have to follow this insane implementation
1166 * XXX: design a new xattr stream format
1168 unser_uint32(magic);
1169 if (magic != XATTR_MAGIC){
1170 Mmsg(jcr->errmsg, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"), jcr->last_fname);
1171 Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n", jcr->last_fname);
1172 return bRC_XACL_error;
1174 /* first attribute name length */
1175 xattr = (XACL_xattr *)malloc(sizeof(XACL_xattr));
1176 unser_uint32(xattr->name_len);
1177 if (xattr->name_len == 0){
1178 /* attribute name cannot be empty */
1179 Mmsg(jcr->errmsg, _("Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n"), jcr->last_fname);
1180 Dmsg1(100, "Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n", jcr->last_fname);
1182 return bRC_XACL_error;
1184 /* followed by attribute name itself */
1185 xattr->name = (char *)malloc(xattr->name_len + 1);
1186 unser_bytes(xattr->name, xattr->name_len);
1187 xattr->name[xattr->name_len] = '\0';
1188 /* attribute value */
1189 unser_uint32(xattr->value_len);
1190 if (xattr->value_len > 0){
1191 /* we have a value */
1192 xattr->value = (char *)malloc(xattr->value_len + 1);
1193 unser_bytes(xattr->value, xattr->value_len);
1194 xattr->value[xattr->value_len] = '\0';
1195 Dmsg3(100, "Restoring xattr named %s, value %.*s\n", xattr->name, xattr->value_len, xattr->value);
1197 /* value is empty */
1198 xattr->value = NULL;
1199 Dmsg1(100, "Restoring empty xattr named %s\n", xattr->name);
1201 list->append(xattr);
1203 unser_end(content, length);
1208 #if defined(HAVE_AFS_ACL)
1210 #if defined(HAVE_AFS_AFSINT_H) && defined(HAVE_AFS_VENUS_H)
1211 #include <afs/afsint.h>
1212 #include <afs/venus.h>
1214 #error "configure failed to detect availability of afs/afsint.h and/or afs/venus.h"
1218 * External references to functions in the libsys library function not in current include files.
1221 long pioctl(char *pathp, long opcode, struct ViceIoctl *blobp, int follow);
1225 * Backup ACL data of AFS
1228 * jcr - Job Control Record
1229 * ff_pkt - file backup record
1231 * bRC_XACL_inval - input variables are invalid (NULL)
1232 * bRC_XACL_ok - backup finish without problems
1233 * bRC_XACL_error - when you can't backup acl data because some error
1235 bRC_XACL XACL::afs_backup_acl (JCR *jcr, FF_PKT *ff_pkt){
1238 struct ViceIoctl vip;
1241 /* sanity check of input variables */
1242 if (jcr == NULL || ff_pkt == NULL){
1243 return bRC_XACL_inval;
1246 /* AFS ACLs can only be set on a directory, so no need to try other files */
1247 if (ff_pkt->type != FT_DIREND){
1254 vip.out_size = BUFSIZE;
1255 memset(data, 0, BUFSIZE);
1257 if ((rc = pioctl(jcr->last_fname, VIOCGETAL, &vip, 0)) < 0){
1260 Mmsg2(jcr->errmsg, _("pioctl VIOCGETAL error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
1261 Dmsg2(100, "pioctl VIOCGETAL error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
1262 return bRC_XACL_error;
1265 return send_acl_stream(jcr, STREAM_XACL_AFS_TEXT);
1269 * Restore ACL data of AFS
1271 * jcr - Job Control Record
1272 * stream - a backup stream type number to restore_acl
1274 * bRC_XACL_inval - input variables are invalid (NULL)
1275 * bRC_XACL_ok - backup finish without problems
1276 * bRC_XACL_error - when you can't backup acl data because some error
1278 bRC_XACL XACL::afs_restore_acl (JCR *jcr, int stream){
1281 struct ViceIoctl vip;
1283 /* sanity check of input variables */
1284 if (jcr == NULL || ff_pkt == NULL){
1285 return bRC_XACL_inval;
1289 vip.in_size = content_len;
1293 if ((rc = pioctl(jcr->last_fname, VIOCSETAL, &vip, 0)) < 0){
1296 Mmsg2(jcr->errmsg, _("pioctl VIOCSETAL error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
1297 Dmsg2(100, "pioctl VIOCSETAL error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
1299 return bRC_XACL_error;
1303 #endif /* HAVE_AFS_ACL */
1305 #include "xacl_osx.h"
1306 #include "xacl_linux.h"
1307 #include "xacl_freebsd.h"
1308 #include "xacl_solaris.h"
1309 // #include "xacl_aix.h"
1312 * Creating the corrent instance of the XACL for a supported OS
1316 #if defined(HAVE_DARWIN_OS)
1317 return new XACL_OSX();
1318 #elif defined(HAVE_LINUX_OS)
1319 return new XACL_Linux();
1320 #elif defined(HAVE_FREEBSD_OS)
1321 return new XACL_FreeBSD();
1322 #elif defined(HAVE_HURD_OS)
1323 return new XACL_Hurd();
1324 #elif defined(HAVE_AIX_OS)
1325 return new XACL_AIX();
1326 #elif defined(HAVE_IRIX_OS)
1327 return new XACL_IRIX();
1328 #elif defined(HAVE_OSF1_OS)
1329 return new XACL_OSF1();
1330 #elif defined(HAVE_SUN_OS)
1331 return new XACL_Solaris();