]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/xacl.c
baculum: Improve slow reloading config resource list
[bacula/bacula] / bacula / src / filed / xacl.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2017 Kern Sibbald
5
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.
8
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.
13
14    This notice must be preserved when any source code is
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18  */
19 /**
20  * Major refactoring of ACL and XATTR code written by:
21  *
22  *  RadosÅ‚aw Korzeniewski, MMXVI
23  *  radoslaw@korzeniewski.net, radekk@inteos.pl
24  *  Inteos Sp. z o.o. http://www.inteos.pl/
25  *
26  *
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_*
31  *
32  * OS dependent subclasses are available for the following OS:
33  *   - Darwin (OSX)
34  *   - FreeBSD (POSIX and NFSv4/ZFS acls)
35  *   - Linux
36  *   - Solaris (POSIX and NFSv4/ZFS acls)
37  *
38  * OS dependend subclasses in progress:
39  *   - AIX (pre-5.3 and post 5.3 acls, acl_get and aclx_get interface)
40  *   - HPUX
41  *   - IRIX
42  *   - Tru64
43  *
44  * OS independent class support AFS acls using the pioctl interface.
45  *
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.
53  *
54  * During OS specyfic implementation of XACL you need to implement a following methods:
55  *
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)
59  *
60  * ::os_get_acl(JCR *jcr, XACL_type xacltype)
61  *
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]
67  *
68  * ::os_backup_acl (JCR *jcr, FF_PKT *ff_pkt)
69  *
70  *   1. call os_get_acl[xacl] for all supported ACL_TYPES
71  *   2. call send_acl_stream[xacl] for all supported ACL_STREAMS
72  *
73  * ::os_set_acl(JCR *jcr, XACL_type xacltype, char *content, uint32_t length)
74  *
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)
78  *
79  * ::os_restore_acl (JCR *jcr, int stream, char *content, uint32_t length)
80  *
81  *   1. call os_set_acl for all supported ACL_TYPES
82  *
83  * ::os_get_xattr_names (JCR *jcr, int namespace, POOLMEM ** pxlist, uint32_t * xlen)
84  *
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
91  *
92  * ::os_get_xattr_value (JCR *jcr, char * name, char ** pvalue, uint32_t * plen)
93  *
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
100  *
101  * ::os_backup_xattr (JCR *jcr, FF_PKT *ff_pkt)
102  *
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,
105  *       so it is:
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]
113  *
114  * ::os_set_xattr (JCR *jcr, XACL_xattr *xattr)
115  *
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]
118  *
119  * ::os_restore_xattr (JCR *jcr, int stream, char *content, uint32_t length)
120  *
121  *    1. unserialize backup stream
122  *    2. for every extended attribute restored call os_set_xattr[xacl] to set this attribute on file
123  */
124
125 #include "bacula.h"
126 #include "filed.h"
127
128 /*
129  * This is a constructor of the base XACL class which is OS independent
130  *
131  * - for initialization it uses ::init()
132  *
133  */
134 XACL::XACL (){
135    init();
136 };
137
138 /*
139  * This is a destructor of the XACL class
140  */
141 XACL::~XACL (){
142    free_pool_memory(content);
143 };
144
145 /*
146  * Initialization routine
147  * - initializes all variables to required status
148  * - allocates required memory
149  */
150 void XACL::init(){
151 #if defined(HAVE_ACL)
152    acl_ena = TRUE;
153 #else
154    acl_ena = FALSE;
155 #endif
156
157 #if defined(HAVE_XATTR)
158    xattr_ena = TRUE;
159 #else
160    xattr_ena = FALSE;
161 #endif
162
163    /* generic variables */
164    flags = XACL_FLAG_NONE;
165    current_dev = 0;
166    content = get_pool_memory(PM_BSOCK);   /* it is better to have a 4k buffer */
167    content_len = 0;
168    acl_nr_errors = 0;
169    xattr_nr_errors = 0;
170    acl_streams = NULL;
171    default_acl_streams = NULL;
172    xattr_streams = NULL;
173    xattr_skiplist = NULL;
174    xattr_acl_skiplist = NULL;
175 };
176
177 /*
178  * Enables ACL handling in runtime, could be disabled with disable_acl
179  *    when ACL is not configured then cannot change status
180  */
181 void XACL::enable_acl(){
182 #if defined(HAVE_ACL)
183    acl_ena = TRUE;
184 #endif
185 };
186
187 /*
188  * Disables ACL handling in runtime, could be enabled with enable_acl
189  *    when ACL is configured
190  */
191 void XACL::disable_acl(){
192    acl_ena = FALSE;
193 };
194
195 /*
196  * Enables XATTR handling in runtime, could be disabled with disable_xattr
197  *    when XATTR is not configured then cannot change status
198  */
199 void XACL::enable_xattr(){
200 #ifdef HAVE_XATTR
201    xattr_ena = TRUE;
202 #endif
203 };
204
205 /*
206  * Disables XATTR handling in runtime, could be enabled with enable_xattr
207  *    when XATTR is configured
208  */
209 void XACL::disable_xattr(){
210    xattr_ena = FALSE;
211 };
212
213 /*
214  * Copies a text into a content variable and sets a constent_len respectively
215  *
216  * in:
217  *    text - a standard null terminated string
218  * out:
219  *    pointer to content variable to use externally
220  */
221 POOLMEM * XACL::set_content(char *text){
222    content_len = pm_strcpy(&content, text);
223    return content;
224 };
225
226 /*
227  * Copies a data with length of len into a content variable
228  *
229  * in:
230  *    data - data pointer to copy into content buffer
231  * out:
232  *    pointer to content variable to use externally
233  */
234 POOLMEM * XACL::set_content(char *data, int len){
235    content_len = pm_memcpy(&content, data, len);
236    return content;
237 };
238
239 /*
240  * Check if we changed the device,
241  * if so setup a flags
242  *
243  * in:
244  *    jcr - Job Control Record
245  * out:
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
250  */
251 bRC_XACL XACL::check_dev (JCR *jcr){
252
253    int lst;
254    struct stat st;
255
256    /* sanity check of input variables */
257    if (jcr == NULL || jcr->last_fname == NULL){
258       return bRC_XACL_inval;
259    }
260
261    lst = lstat(jcr->last_fname, &st);
262    switch (lst){
263       case -1: {
264          berrno be;
265          switch (errno){
266          case ENOENT:
267             return bRC_XACL_skip;
268          default:
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;
272          }
273          break;
274       }
275       case 0:
276          break;
277    }
278
279    check_dev(jcr, st.st_dev);
280
281    return bRC_XACL_ok;
282 };
283
284 /*
285  * Check if we changed the device, if so setup a flags
286  *
287  * in:
288  *    jcr - Job Control Record
289  * out:
290  *    internal flags status set
291  */
292 void XACL::check_dev (JCR *jcr, uint32_t dev){
293
294    /* sanity check of input variables */
295    if (jcr == NULL || jcr->last_fname == NULL){
296       return;
297    }
298
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);
305       } else {
306          set_flag(XACL_FLAG_NATIVE);
307       }
308 #else
309       set_flag(XACL_FLAG_NATIVE);
310 #endif
311       current_dev = dev;
312    }
313 };
314
315 /*
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.
318  *
319  * in:
320  *    jcr - Job Control Record
321  *    stream - a stream number to save
322  * out:
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
326  */
327 bRC_XACL XACL::send_acl_stream(JCR *jcr, int stream){
328
329    BSOCK * sd;
330    POOLMEM * msgsave;
331 #ifdef FD_NO_SEND_TEST
332    return bRC_XACL_ok;
333 #endif
334
335    /* sanity check of input variables */
336    if (jcr == NULL || jcr->store_bsock == NULL){
337       return bRC_XACL_inval;
338    }
339    if (content_len <= 0){
340       return bRC_XACL_ok;
341    }
342
343    sd = jcr->store_bsock;
344    /* send header */
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;
348    }
349
350    /* send the buffer to the storage deamon */
351    Dmsg1(400, "Backing up ACL <%s>\n", content);
352    msgsave = sd->msg;
353    sd->msg = content;
354    sd->msglen = content_len + 1;
355    if (!sd->send()){
356       sd->msg = msgsave;
357       sd->msglen = 0;
358       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), sd->bstrerror());
359       return bRC_XACL_fatal;
360    }
361
362    jcr->JobBytes += sd->msglen;
363    sd->msg = msgsave;
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;
367    }
368
369    Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
370    return bRC_XACL_ok;
371 };
372
373 /*
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.
376  *
377  * in:
378  *    jcr - Job Control Record
379  *    stream - a stream number to save
380  * out:
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
384  */
385 bRC_XACL XACL::send_xattr_stream(JCR *jcr, int stream){
386
387    BSOCK * sd;
388    POOLMEM * msgsave;
389 #ifdef FD_NO_SEND_TEST
390    return bRC_XACL_ok;
391 #endif
392
393    /* sanity check of input variables */
394    if (jcr == NULL || jcr->store_bsock == NULL){
395       return bRC_XACL_inval;
396    }
397    if (content_len <= 0){
398       return bRC_XACL_ok;
399    }
400
401    sd = jcr->store_bsock;
402    /* send header */
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;
406    }
407
408    /* send the buffer to the storage deamon */
409    Dmsg1(400, "Backing up XATTR <%s>\n", content);
410    msgsave = sd->msg;
411    sd->msg = content;
412    sd->msglen = content_len;
413    if (!sd->send()){
414       sd->msg = msgsave;
415       sd->msglen = 0;
416       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), sd->bstrerror());
417       return bRC_XACL_fatal;
418    }
419
420    jcr->JobBytes += sd->msglen;
421    sd->msg = msgsave;
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;
425    }
426    Dmsg1(200, "XATTR of file: %s successfully backed up!\n", jcr->last_fname);
427    return bRC_XACL_ok;
428 };
429
430 /*
431  * The main public backup method for ACL
432  *
433  * in:
434  *    jcr - Job Control Record
435  *    ff_pkt - file backup record
436  * out:
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
440  */
441 bRC_XACL XACL::backup_acl (JCR *jcr, FF_PKT *ff_pkt){
442
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;
446 #else
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 */
450       bRC_XACL rc;
451       /*
452        * No acl request for link or plugin
453        *
454        * TODO: it should be possible to handle ACL/XATTR for cmd plugins
455        */
456       if (!(ff_pkt->flags & FO_ACL && ff_pkt->type != FT_LNK && !ff_pkt->cmd_plugin)){
457          return bRC_XACL_ok;
458       }
459
460       jcr->errmsg[0] = 0;
461       check_dev(jcr, ff_pkt->statp.st_dev);
462
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);
467          goto bail_out;
468       }
469 #endif
470
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);
475       } else {
476          /* skip acl backup */
477          return bRC_XACL_ok;
478       }
479 #endif
480
481 #if defined(HAVE_AFS_ACL)
482    bail_out:
483 #endif
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");
488             } else {
489                Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
490             }
491             inc_acl_errors();
492          }
493          return bRC_XACL_ok;
494       }
495       return rc;
496    }
497    return bRC_XACL_ok;
498 #endif
499 };
500
501 /*
502  * The main public restore method for ACL
503  *
504  * in:
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
509  * out:
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
513  */
514 bRC_XACL XACL::restore_acl (JCR *jcr, int stream, char *data, uint32_t length){
515
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;
519 #else
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 */
523       int a;
524       bRC_XACL rc = check_dev(jcr);
525
526       switch (rc){
527          case bRC_XACL_skip:
528             return bRC_XACL_ok;
529          case bRC_XACL_ok:
530             break;
531          default:
532             return rc;
533       }
534
535       /* copy a data into a content buffer */
536       set_content(data, length);
537
538       switch (stream){
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);
543             } else {
544                /*
545                 * Increment error count but don't log an error again for the same filesystem.
546                 */
547                inc_acl_errors();
548                return bRC_XACL_ok;
549             }
550 #endif
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);
556             } else {
557                inc_acl_errors();
558                return bRC_XACL_ok;
559             }
560             break;
561          default:
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);
566                   }
567                }
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);
571                   }
572                }
573             } else {
574                inc_acl_errors();
575                return bRC_XACL_ok;
576             }
577             break;
578 #else
579          default:
580             break;
581 #endif
582       }
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;
586    }
587    return bRC_XACL_ok;
588 #endif
589 };
590
591 /*
592  * The main public backup method for XATTR
593  *
594  * in:
595  *    jcr - Job Control Record
596  *    ff_pkt - file backup record
597  * out:
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
601  */
602 bRC_XACL XACL::backup_xattr (JCR *jcr, FF_PKT *ff_pkt){
603
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;
607 #else
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 */
611       bRC_XACL rc;
612       /*
613        * No xattr request for plugin
614        *
615        * TODO: it should be possible to handle ACL/XATTR for cmd plugins
616        */
617       if (!(ff_pkt->flags & FO_XATTR && !ff_pkt->cmd_plugin)){
618          return bRC_XACL_ok;
619       }
620
621       jcr->errmsg[0] = 0;
622       check_dev(jcr, ff_pkt->statp.st_dev);
623
624       if (flags & XACL_FLAG_NATIVE){
625          Dmsg0(400, "make Native XATTR call\n");
626          rc = os_backup_xattr(jcr, ff_pkt);
627       } else {
628          /* skip xattr backup */
629          return bRC_XACL_ok;
630       }
631
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");
636             } else {
637                Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
638             }
639             inc_xattr_errors();
640          }
641          return bRC_XACL_ok;
642       }
643       return rc;
644    }
645    return bRC_XACL_ok;
646 #endif
647 };
648
649 /*
650  * The main public restore method for XATTR
651  *
652  * in:
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
657  * out:
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
661  */
662 bRC_XACL XACL::restore_xattr (JCR *jcr, int stream, char *data, uint32_t length){
663
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;
667 #else
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 */
671       int a;
672       bRC_XACL rc = check_dev(jcr);
673
674       switch (rc){
675          case bRC_XACL_skip:
676             return bRC_XACL_ok;
677          case bRC_XACL_ok:
678             break;
679          default:
680             return rc;
681       }
682
683       /* copy a data into a content buffer */
684       set_content(data, length);
685
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);
690             }
691          }
692       } else {
693          inc_xattr_errors();
694          return bRC_XACL_ok;
695       }
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;
699    }
700    return bRC_XACL_ok;
701 #endif
702 };
703
704 /*
705  * Performs a generic ACL backup using OS specyfic methods for
706  * getting acl data from file
707  *
708  * in:
709  *    jcr - Job Control Record
710  *    ff_pkt - file to backup control package
711  * out:
712  *    bRC_XACL_ok - backup of acl's was successful
713  *    bRC_XACL_fatal - was an error during acl backup
714  */
715 bRC_XACL XACL::generic_backup_acl (JCR *jcr, FF_PKT *ff_pkt){
716
717    /* sanity check of input variables */
718    if (jcr == NULL || ff_pkt == NULL){
719       return bRC_XACL_inval;
720    }
721
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;
725    }
726
727    if (content_len > 0){
728       if (send_acl_stream(jcr, acl_streams[0]) == bRC_XACL_fatal){
729          return bRC_XACL_fatal;
730       }
731    }
732
733    if (ff_pkt->type == FT_DIREND){
734       if (os_get_acl(jcr, XACL_TYPE_DEFAULT) == bRC_XACL_fatal){
735          return bRC_XACL_fatal;
736       }
737       if (content_len > 0){
738          if (send_acl_stream(jcr, default_acl_streams[0]) == bRC_XACL_fatal){
739             return bRC_XACL_fatal;
740          }
741       }
742    }
743    return bRC_XACL_ok;
744 };
745
746 /*
747  * Performs a generic ACL restore using OS specyfic methods for
748  * setting acl data on file.
749  *
750  * in:
751  *    jcr - Job Control Record
752  *    stream - a stream number to restore
753  * out:
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
757  */
758 bRC_XACL XACL::generic_restore_acl (JCR *jcr, int stream){
759
760    unsigned int count;
761
762    /* sanity check of input variables */
763    if (jcr == NULL){
764       return bRC_XACL_inval;
765    }
766
767    switch (stream){
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);
772       default:
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);
776             }
777          }
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);
781             }
782          }
783          break;
784    }
785    return bRC_XACL_error;
786 };
787
788 /*
789  * Checks if supplied xattr attribute name is indicated on OS specyfic lists
790  *
791  * in:
792  *    jcr - Job Control Record
793  *    ff_pkt - file to backup control package
794  *    name - a name of the attribute to check
795  * out:
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
798  */
799 bool XACL::check_xattr_skiplists (JCR *jcr, FF_PKT *ff_pkt, char * name){
800
801    bool skip = FALSE;
802    int count;
803
804    /* sanity check of input variables */
805    if (jcr == NULL || ff_pkt == NULL || name ==  NULL){
806       return false;
807    }
808
809    /*
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.
813     */
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])){
817             skip = true;
818             break;
819          }
820       }
821    }
822    /* on some OSes we want to skip certain xattrs which are in the xattr_skiplist array. */
823    if (!skip){
824       for (count = 0; xattr_skiplist[count] != NULL; count++){
825          if (bstrcmp(name, xattr_skiplist[count])){
826             skip = true;
827             break;
828          }
829       }
830    }
831
832    return skip;
833 };
834
835
836 /*
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
839  *
840  * in:
841  *    jcr - Job Control Record
842  *    ff_pkt - file to backup control package
843  * out:
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
847  */
848 bRC_XACL XACL::generic_backup_xattr (JCR *jcr, FF_PKT *ff_pkt){
849
850    bRC_XACL rc;
851    POOLMEM *xlist;
852    uint32_t xlen;
853    char *name;
854    uint32_t name_len;
855    POOLMEM *value;
856    uint32_t value_len;
857    bool skip;
858    alist *xattr_list = NULL;
859    int xattr_count = 0;
860    uint32_t len = 0;
861    XACL_xattr *xattr;
862
863    /* sanity check of input variables */
864    if (jcr == NULL || ff_pkt == NULL){
865       return bRC_XACL_inval;
866    }
867
868    /* xlist is allocated as POOLMEM by os_get_xattr_names */
869    rc = os_get_xattr_names(jcr, &xlist, &xlen);
870    switch (rc){
871       case bRC_XACL_ok:
872          /* it's ok, so go further */
873          break;
874       case bRC_XACL_skip:
875       case bRC_XACL_cont:
876          /* no xattr available, so skip rest of it */
877          return bRC_XACL_ok;
878       default:
879          return rc;
880    }
881
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){
885
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);
890          continue;
891       }
892
893       /* value is allocated as POOLMEM by os_get_xattr_value */
894       rc = os_get_xattr_value(jcr, name, &value, &value_len);
895       switch (rc){
896          case bRC_XACL_ok:
897             /* it's ok, so go further */
898             break;
899          case bRC_XACL_skip:
900             /* no xattr available, so skip rest of it */
901             free_pool_memory(xlist);
902             return bRC_XACL_ok;
903          default:
904             /* error / fatal */
905             free_pool_memory(xlist);
906             return rc;
907       }
908
909       /*
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
913        */
914       xattr = (XACL_xattr*)malloc(sizeof(XACL_xattr));
915       xattr->name_len = name_len;
916       xattr->name = name;
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;
921
922       if (xattr_list == NULL){
923          xattr_list = New(alist(10, not_owned_by_alist));
924       }
925       xattr_list->append(xattr);
926       xattr_count++;
927    }
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);
934          goto bailout;
935       } else {
936          /* send data to SD */
937          rc = send_xattr_stream(jcr, xattr_streams[0]);
938       }
939    } else {
940       rc = bRC_XACL_ok;
941    }
942
943 bailout:
944    /* free allocated data */
945    if (xattr_list != NULL){
946       foreach_alist(xattr, xattr_list){
947          if (xattr == NULL){
948             break;
949          }
950          if (xattr->value){
951             free_pool_memory(xattr->value);
952          }
953          free(xattr);
954       }
955       delete xattr_list;
956    }
957    if (xlist != NULL){
958       free_pool_memory(xlist);
959    }
960
961    return rc;
962 };
963
964 /*
965  * Performs a generic XATTR restore using OS specyfic methods for
966  * setting XATTR data on file.
967  *
968  * in:
969  *    jcr - Job Control Record
970  *    stream - a stream number to restore
971  * out:
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
976  */
977 bRC_XACL XACL::generic_restore_xattr (JCR *jcr, int stream){
978
979    bRC_XACL rc = bRC_XACL_ok;
980    alist *xattr_list;
981    XACL_xattr *xattr;
982
983    /* sanity check of input variables */
984    if (jcr == NULL){
985       return bRC_XACL_inval;
986    }
987
988    /* empty list */
989    xattr_list = New(alist(10, not_owned_by_alist));
990
991    /* unserialize data */
992    unserialize_xattr_stream(jcr, content, content_len, xattr_list);
993
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);
999          goto bailout;
1000       }
1001    }
1002
1003 bailout:
1004    /* free allocated data */
1005    if (xattr_list != NULL){
1006       foreach_alist(xattr, xattr_list){
1007          if (xattr == NULL){
1008             break;
1009          }
1010          if (xattr->name){
1011             free(xattr->name);
1012          }
1013          if (xattr->value){
1014             free(xattr->value);
1015          }
1016          free(xattr);
1017       }
1018       delete xattr_list;
1019    }
1020    return rc;
1021 };
1022
1023 /*
1024  * Initialize variables acl_streams and default_acl_streams for a specified OS.
1025  * The rutine should be called from object instance constructor
1026  *
1027  * in:
1028  *    pacl - acl streams supported for specyfic OS
1029  *    pacl_def - default (directory) acl streams supported for specyfic OS
1030  */
1031 void XACL::set_acl_streams (const int *pacl, const int *pacl_def){
1032
1033    acl_streams = pacl;
1034    default_acl_streams = pacl_def;
1035 };
1036
1037 /*
1038  * Initialize a variable xattr_streams for a specified OS.
1039  * The rutine should be called from object instance constructor
1040  *
1041  * in:
1042  *    pxattr - xattr streams supported for specyfic OS
1043  */
1044 void XACL::set_xattr_streams (const int *pxattr){
1045
1046    xattr_streams = pxattr;
1047 };
1048
1049 /*
1050  * Initialize variables xattr_skiplist and xattr_acl_skiplist for a specified OS.
1051  * The rutine should be called from object instance constructor
1052  *
1053  * in:
1054  *    pxattr - xattr skip list for specyfic OS
1055  *    pxattr_acl - xattr acl names skip list for specyfic OS
1056  */
1057 void XACL::set_xattr_skiplists (const char **pxattr, const char **pxattr_acl){
1058
1059    xattr_skiplist = pxattr;
1060    xattr_acl_skiplist = pxattr_acl;
1061 };
1062
1063 /*
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.
1066  *
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
1074  *
1075  * in:
1076  *    jcr - Job Control Record
1077  *    len - expected serialize length
1078  *    list - a list of xattr elements to serialize
1079  * out:
1080  *    bRC_XACL_ok - when serialization was perfect
1081  *    bRC_XACL_inval - when we have invalid variables
1082  *    bRC_XACL_error - illegal attribute name
1083  */
1084 bRC_XACL XACL::serialize_xattr_stream(JCR *jcr, uint32_t len, alist *list){
1085
1086    ser_declare;
1087    XACL_xattr *xattr;
1088
1089    /* sanity check of input variables */
1090    if (jcr == NULL || list == NULL){
1091       return bRC_XACL_inval;
1092    }
1093
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);
1097
1098    foreach_alist(xattr, list){
1099       if (xattr == NULL){
1100          break;
1101       }
1102       /*
1103        * serialize data
1104        *
1105        * we have to start with the XATTR_MAGIC for backward compatibility (the magic is silly)
1106        */
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);
1112       } else {
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;
1117       }
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);
1123       } else {
1124          Dmsg1(100, "Backup empty xattr named %s\n", xattr->name);
1125       }
1126    }
1127
1128    ser_end(content, len + 20);
1129    content_len = ser_length(content);
1130
1131    return bRC_XACL_ok;
1132 };
1133
1134 /*
1135  * Unserialize XATTR stream on *content and produce a xattr *list which contain
1136  * key => value pairs
1137  *
1138  * in:
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
1143  * out:
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
1147  */
1148 bRC_XACL XACL::unserialize_xattr_stream(JCR *jcr, char *content, uint32_t length, alist *list){
1149
1150    unser_declare;
1151    uint32_t magic;
1152    XACL_xattr *xattr;
1153
1154    /* sanity check of input variables */
1155    if (jcr == NULL || content == NULL || list == NULL){
1156       return bRC_XACL_inval;
1157    }
1158
1159    unser_begin(content, length);
1160    while (unser_length(content) < length){
1161       /*
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
1165        *
1166        * XXX: design a new xattr stream format
1167        */
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;
1173       }
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);
1181          free(xattr);
1182          return bRC_XACL_error;
1183       }
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);
1196       } else {
1197          /* value is empty */
1198          xattr->value = NULL;
1199          Dmsg1(100, "Restoring empty xattr named %s\n", xattr->name);
1200       }
1201       list->append(xattr);
1202    }
1203    unser_end(content, length);
1204
1205    return bRC_XACL_ok;
1206 };
1207
1208 #if defined(HAVE_AFS_ACL)
1209
1210 #if defined(HAVE_AFS_AFSINT_H) && defined(HAVE_AFS_VENUS_H)
1211 #include <afs/afsint.h>
1212 #include <afs/venus.h>
1213 #else
1214 #error "configure failed to detect availability of afs/afsint.h and/or afs/venus.h"
1215 #endif
1216
1217 /*
1218  * External references to functions in the libsys library function not in current include files.
1219  */
1220 extern "C" {
1221 long pioctl(char *pathp, long opcode, struct ViceIoctl *blobp, int follow);
1222 }
1223
1224 /*
1225  * Backup ACL data of AFS
1226  *
1227  * in:
1228  *    jcr - Job Control Record
1229  *    ff_pkt - file backup record
1230  * out:
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
1234  */
1235 bRC_XACL XACL::afs_backup_acl (JCR *jcr, FF_PKT *ff_pkt){
1236
1237    int rc;
1238    struct ViceIoctl vip;
1239    char data[BUFSIZ];
1240
1241    /* sanity check of input variables */
1242    if (jcr == NULL || ff_pkt == NULL){
1243       return bRC_XACL_inval;
1244    }
1245
1246    /* AFS ACLs can only be set on a directory, so no need to try other files */
1247    if (ff_pkt->type != FT_DIREND){
1248       return bRC_XACL_ok;
1249    }
1250
1251    vip.in = NULL;
1252    vip.in_size = 0;
1253    vip.out = data;
1254    vip.out_size = BUFSIZE;
1255    memset(data, 0, BUFSIZE);
1256
1257    if ((rc = pioctl(jcr->last_fname, VIOCGETAL, &vip, 0)) < 0){
1258       berrno be;
1259
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;
1263    }
1264    set_content(data);
1265    return send_acl_stream(jcr, STREAM_XACL_AFS_TEXT);
1266 };
1267
1268 /*
1269  * Restore ACL data of AFS
1270  * in:
1271  *    jcr - Job Control Record
1272  *    stream - a backup stream type number to restore_acl
1273  * out:
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
1277  */
1278 bRC_XACL XACL::afs_restore_acl (JCR *jcr, int stream){
1279
1280    int rc;
1281    struct ViceIoctl vip;
1282
1283    /* sanity check of input variables */
1284    if (jcr == NULL || ff_pkt == NULL){
1285       return bRC_XACL_inval;
1286    }
1287
1288    vip.in = content;
1289    vip.in_size = content_len;
1290    vip.out = NULL;
1291    vip.out_size = 0;
1292
1293    if ((rc = pioctl(jcr->last_fname, VIOCSETAL, &vip, 0)) < 0){
1294       berrno be;
1295
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());
1298
1299       return bRC_XACL_error;
1300    }
1301    return bRC_XACL_ok;
1302 };
1303 #endif /* HAVE_AFS_ACL */
1304
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"
1310
1311 /*
1312  * Creating the corrent instance of the XACL for a supported OS
1313  */
1314 void *new_xacl()
1315 {
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();
1332 #else
1333    return NULL;
1334 #endif
1335 };