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 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 in Bacula Enterprise.
28 * The runtime consist of two parts:
29 * 1. OS independent class: BACL
30 * 2. OS dependent subclass: BACL_*
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 dependent 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 * Above behavior is a backward compatibility with previous Bacula implementation
49 * we need to maintain.
51 * During OS specific implementation of BACL you need to implement a following methods:
53 * [bacl] - indicates bacl function/method to call
54 * [os] - indicates OS specific function, which could be different on specific OS
55 * (we use a Linux API calls as an example)
57 * ::os_get_acl(JCR *jcr, BACL_type bacltype)
59 * 1. get binary form of the acl - acl_get_file[os]
60 * 2. check if acl is trivial if required - call acl_issimple[bacl]
61 * 3. translate binary form into text representation - acl_to_text[os]
62 * 4. save acl text into content - set_content[bacl]
63 * 5. if acl not supported on filesystem - call clear_flag(BACL_FLAG_NATIVE)[bacl]
65 * ::os_backup_acl (JCR *jcr, FF_PKT *ff_pkt)
67 * 1. call os_get_acl[bacl] for all supported ACL_TYPES
68 * 2. call send_acl_stream[bacl] for all supported ACL_STREAMS
70 * ::os_set_acl(JCR *jcr, BACL_type bacltype, char *content, uint32_t length)
72 * 1. prepare acl binary form from text representation stored in content - acl_from_text[os]
73 * 2. set acl on file - acl_set_file[os]
74 * 3. if acl not supported on filesystem, clear_flag(BACL_FLAG_NATIVE)
76 * ::os_restore_acl (JCR *jcr, int stream, char *content, uint32_t length)
78 * 1. call os_set_acl for all supported ACL_TYPES
83 #include "fd_plugins.h"
85 /* check if ACL support is enabled */
89 * This is a constructor of the base BACL class which is OS independent
91 * - for initialization it uses ::init()
99 * This is a destructor of the BACL class
102 free_pool_memory(content);
106 * Initialization routine
107 * - initializes all variables to required status
108 * - allocates required memory
111 #if defined(HAVE_ACL)
117 /* generic variables */
118 flags = BACL_FLAG_NONE;
120 content = get_pool_memory(PM_BSOCK); /* it is better to have a 4k buffer */
124 default_acl_streams = NULL;
128 * Enables ACL handling in runtime, could be disabled with disable_acl
129 * when ACL is not configured then cannot change status
131 void BACL::enable_acl(){
132 #if defined(HAVE_ACL)
138 * Disables ACL handling in runtime, could be enabled with enable_acl
139 * when ACL is configured
141 void BACL::disable_acl(){
146 * Copies a text into a content variable and sets a content_len respectively
149 * text - a standard null terminated string
151 * pointer to content variable to use externally
153 POOLMEM * BACL::set_content(char *text){
154 content_len = pm_strcpy(&content, text);
155 if (content_len > 0){
156 /* count the nul terminated char */
159 // Dmsg2(400, "BACL::set_content: %p %i\n", text, content_len);
164 * Copies a data with length of len into a content variable
167 * data - data pointer to copy into content buffer
169 * pointer to content variable to use externally
171 POOLMEM * BACL::set_content(char *data, int len){
172 content_len = pm_memcpy(&content, data, len);
177 * Check if we changed the device,
178 * if so setup a flags
181 * jcr - Job Control Record
183 * bRC_BACL_ok - change of device checked and finish successful
184 * bRC_BACL_error - encountered error
185 * bRC_BACL_skip - cannot verify device - no file found
186 * bRC_BACL_inval - invalid input data
188 bRC_BACL BACL::check_dev (JCR *jcr){
193 /* sanity check of input variables */
194 if (jcr == NULL || jcr->last_fname == NULL){
195 return bRC_BACL_inval;
198 lst = lstat(jcr->last_fname, &st);
204 return bRC_BACL_skip;
206 Mmsg2(jcr->errmsg, _("Unable to stat file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
207 Dmsg2(100, "Unable to stat file \"%s\": ERR=%s\n", jcr->last_fname, be.bstrerror());
208 return bRC_BACL_error;
216 check_dev(jcr, st.st_dev);
222 * Check if we changed the device, if so setup a flags
225 * jcr - Job Control Record
227 * internal flags status set
229 void BACL::check_dev (JCR *jcr, uint32_t dev){
231 /* sanity check of input variables */
232 if (jcr == NULL || jcr->last_fname == NULL){
236 if (current_dev != dev){
237 flags = BACL_FLAG_NONE;
238 #if defined(HAVE_AFS_ACL)
239 /* handle special fs: AFS */
240 if (fstype_equals(jcr->last_fname, "afs")){
241 set_flag(BACL_FLAG_AFS);
243 set_flag(BACL_FLAG_NATIVE);
246 set_flag(BACL_FLAG_NATIVE);
253 * It sends a stream located in this->content to Storage Daemon, so the main Bacula
254 * backup loop is free from this. It sends a header followed by data.
257 * jcr - Job Control Record
258 * stream - a stream number to save
260 * bRC_BACL_inval - when supplied variables are incorrect
261 * bRC_BACL_fatal - when we can't send data to the SD
262 * bRC_BACL_ok - send finish without errors
264 bRC_BACL BACL::send_acl_stream(JCR *jcr, int stream){
268 #ifdef FD_NO_SEND_TEST
272 /* sanity check of input variables */
273 if (jcr == NULL || jcr->store_bsock == NULL){
274 return bRC_BACL_inval;
276 if (content_len <= 0){
280 sd = jcr->store_bsock;
282 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)){
283 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), sd->bstrerror());
284 return bRC_BACL_fatal;
287 /* send the buffer to the storage daemon */
288 Dmsg1(400, "Backing up ACL: %i\n", content_len);
290 POOL_MEM tmp(PM_FNAME);
291 pm_memcpy(tmp, content, content_len);
292 Dmsg2(400, "Backing up ACL: (%i) <%s>\n", strlen(tmp.addr()), tmp.c_str());
296 sd->msglen = content_len;
300 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), sd->bstrerror());
301 return bRC_BACL_fatal;
304 jcr->JobBytes += sd->msglen;
306 if (!sd->signal(BNET_EOD)){
307 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), sd->bstrerror());
308 return bRC_BACL_fatal;
311 Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
316 * The main public backup method for ACL
319 * jcr - Job Control Record
320 * ff_pkt - file backup record
322 * bRC_BACL_fatal - when ACL backup is not compiled in Bacula
323 * bRC_BACL_ok - backup finish without problems
324 * bRC_BACL_error - when you can't backup acl data because some error
326 bRC_BACL BACL::backup_acl (JCR *jcr, FF_PKT *ff_pkt)
328 #if !defined(HAVE_ACL) && !defined(HAVE_AFS_ACL)
329 Jmsg(jcr, M_FATAL, 0, "ACL backup requested but not configured in Bacula.\n");
330 return bRC_BACL_fatal;
332 /* sanity check of input variables and verify if engine is enabled */
333 if (acl_ena && jcr != NULL && ff_pkt != NULL){
334 /* acl engine enabled, proceed */
338 /* check if we have a plugin generated backup */
339 if (ff_pkt->cmd_plugin){
340 rc = backup_plugin_acl(jcr, ff_pkt);
342 /* Check for aclsupport flag and no acl request for link */
343 if (!(ff_pkt->flags & FO_ACL && ff_pkt->type != FT_LNK)){
347 check_dev(jcr, ff_pkt->statp.st_dev);
349 #if defined(HAVE_AFS_ACL)
350 if (flags & BACL_FLAG_AFS){
351 Dmsg0(400, "make AFS ACL call\n");
352 rc = afs_backup_acl(jcr, ff_pkt);
357 #if defined(HAVE_ACL)
358 if (flags & BACL_FLAG_NATIVE){
359 Dmsg0(400, "make Native ACL call\n");
360 rc = os_backup_acl(jcr, ff_pkt);
362 /* skip acl backup */
367 #if defined(HAVE_AFS_ACL)
370 if (rc == bRC_BACL_error){
371 if (acl_nr_errors < ACL_MAX_ERROR_PRINT_PER_JOB){
372 if (!jcr->errmsg[0]){
373 Jmsg(jcr, M_WARNING, 0, "No OS ACL configured.\n");
375 Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
388 * The main public restore method for ACL
391 * jcr - Job Control Record
392 * stream - a backup stream type number to restore_acl
393 * data - a pointer to the data stream to restore
394 * length - a data stream length
396 * bRC_BACL_fatal - when ACL restore is not compiled in Bacula
397 * bRC_BACL_ok - restore finish without problems
398 * bRC_BACL_error - when you can't restore a stream because some error
400 bRC_BACL BACL::restore_acl (JCR *jcr, int stream, char *data, uint32_t length)
402 #if !defined(HAVE_ACL) && !defined(HAVE_AFS_ACL)
403 Jmsg(jcr, M_FATAL, 0, "ACL restore requested but not configured in Bacula.\n");
404 return bRC_BACL_fatal;
406 /* sanity check of input variables and verify if engine is enabled */
407 if (acl_ena && jcr != NULL && data != NULL){
408 /* acl engine enabled, proceed */
412 /* check_dev supported on real fs only */
413 if (stream != STREAM_XACL_PLUGIN_ACL){
426 /* copy a data into a content buffer */
427 set_content(data, length);
430 #if defined(HAVE_AFS_ACL)
431 case STREAM_BACL_AFS_TEXT:
432 if (flags & BACL_FLAG_AFS){
433 return afs_restore_acl(jcr, stream);
436 * Increment error count but don't log an error again for the same filesystem.
442 #if defined(HAVE_ACL)
443 case STREAM_UNIX_ACCESS_ACL:
444 case STREAM_UNIX_DEFAULT_ACL:
445 if (flags & BACL_FLAG_NATIVE){
446 return os_restore_acl(jcr, stream, content, content_len);
452 case STREAM_XACL_PLUGIN_ACL:
453 return restore_plugin_acl(jcr);
455 if (flags & BACL_FLAG_NATIVE){
456 for (a = 0; acl_streams[a] > 0; a++){
457 if (acl_streams[a] == stream){
458 return os_restore_acl(jcr, stream, content, content_len);
461 for (a = 0; default_acl_streams[a] > 0; a++){
462 if (default_acl_streams[a] == stream){
463 return os_restore_acl(jcr, stream, content, content_len);
476 /* cannot find a valid stream to support */
477 Qmsg2(jcr, M_WARNING, 0, _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"), jcr->last_fname, stream);
478 return bRC_BACL_error;
485 * Performs a generic ACL backup using OS specific methods for
486 * getting acl data from file
489 * jcr - Job Control Record
490 * ff_pkt - file to backup control package
492 * bRC_BACL_ok - backup of acl's was successful
493 * bRC_BACL_fatal - was an error during acl backup
495 bRC_BACL BACL::generic_backup_acl (JCR *jcr, FF_PKT *ff_pkt)
497 /* sanity check of input variables */
498 if (jcr == NULL || ff_pkt == NULL){
499 return bRC_BACL_inval;
502 if (os_get_acl(jcr, BACL_TYPE_ACCESS) == bRC_BACL_fatal){
503 /* XXX: check if os_get_acl return fatal and decide what to do when error is returned */
504 return bRC_BACL_fatal;
507 if (content_len > 0){
508 if (send_acl_stream(jcr, acl_streams[0]) == bRC_BACL_fatal){
509 return bRC_BACL_fatal;
513 if (ff_pkt->type == FT_DIREND){
514 if (os_get_acl(jcr, BACL_TYPE_DEFAULT) == bRC_BACL_fatal){
515 return bRC_BACL_fatal;
517 if (content_len > 0){
518 if (send_acl_stream(jcr, default_acl_streams[0]) == bRC_BACL_fatal){
519 return bRC_BACL_fatal;
527 * Performs a generic ACL restore using OS specific methods for
528 * setting acl data on file.
531 * jcr - Job Control Record
532 * stream - a stream number to restore
534 * bRC_BACL_ok - restore of acl's was successful
535 * bRC_BACL_error - was an error during acl restore
536 * bRC_BACL_fatal - was a fatal error during acl restore or input data
539 bRC_BACL BACL::generic_restore_acl (JCR *jcr, int stream){
543 /* sanity check of input variables */
545 return bRC_BACL_inval;
549 case STREAM_UNIX_ACCESS_ACL:
550 return os_set_acl(jcr, BACL_TYPE_ACCESS, content, content_len);
551 case STREAM_UNIX_DEFAULT_ACL:
552 return os_set_acl(jcr, BACL_TYPE_DEFAULT, content, content_len);
554 for (count = 0; acl_streams[count] > 0; count++){
555 if (acl_streams[count] == stream){
556 return os_set_acl(jcr, BACL_TYPE_ACCESS, content, content_len);
559 for (count = 0; default_acl_streams[count] > 0; count++){
560 if (default_acl_streams[count] == stream){
561 return os_set_acl(jcr, BACL_TYPE_DEFAULT, content, content_len);
566 return bRC_BACL_error;
570 * Perform a generic ACL backup using a plugin. It calls the plugin API to
571 * get required acl data from plugin.
574 * jcr - Job Control Record
575 * ff_pkt - file to backup control package
577 * bRC_BACL_ok - backup of acls was successful
578 * bRC_BACL_fatal - was an error during acl backup
580 bRC_BACL BACL::backup_plugin_acl (JCR *jcr, FF_PKT *ff_pkt)
585 /* sanity check of input variables */
586 if (jcr == NULL || ff_pkt == NULL){
587 return bRC_BACL_inval;
590 while ((status = plugin_backup_acl(jcr, ff_pkt, &data)) > 0){
591 /* data is a plugin buffer which contains data to backup
592 * and status is a length of the buffer when > 0 */
593 set_content(data, status);
594 if (send_acl_stream(jcr, STREAM_XACL_PLUGIN_ACL) == bRC_BACL_fatal){
595 return bRC_BACL_fatal;
600 return bRC_BACL_error;
607 * Perform a generic ACL restore using a plugin. It calls the plugin API to
608 * send acl data to plugin.
611 * jcr - Job Control Record
612 * stream - a stream number to restore
614 * bRC_BACL_ok - restore of acls was successful
615 * bRC_BACL_error - was an error during acls restore
616 * bRC_BACL_fatal - was a fatal error during acl restore or input data
619 bRC_BACL BACL::restore_plugin_acl (JCR *jcr)
621 /* sanity check of input variables */
623 return bRC_BACL_inval;
626 if (!plugin_restore_acl(jcr, content, content_len)){
628 return bRC_BACL_error;
635 * Initialize variables acl_streams and default_acl_streams for a specified OS.
636 * The rutine should be called from object instance constructor
639 * pacl - acl streams supported for specific OS
640 * pacl_def - default (directory) acl streams supported for specific OS
642 void BACL::set_acl_streams (const int *pacl, const int *pacl_def){
645 default_acl_streams = pacl_def;
648 #if defined(HAVE_AFS_ACL)
649 #if defined(HAVE_AFS_AFSINT_H) && defined(HAVE_AFS_VENUS_H)
650 #include <afs/afsint.h>
651 #include <afs/venus.h>
653 #error "configure failed to detect availability of afs/afsint.h and/or afs/venus.h"
657 * External references to functions in the libsys library function not in current include files.
660 long pioctl(char *pathp, long opcode, struct ViceIoctl *blobp, int follow);
664 * Backup ACL data of AFS
667 * jcr - Job Control Record
668 * ff_pkt - file backup record
670 * bRC_BACL_inval - input variables are invalid (NULL)
671 * bRC_BACL_ok - backup finish without problems
672 * bRC_BACL_error - when you can't backup acl data because some error
674 bRC_BACL BACL::afs_backup_acl (JCR *jcr, FF_PKT *ff_pkt){
677 struct ViceIoctl vip;
680 /* sanity check of input variables */
681 if (jcr == NULL || ff_pkt == NULL){
682 return bRC_BACL_inval;
685 /* AFS ACLs can only be set on a directory, so no need to try other files */
686 if (ff_pkt->type != FT_DIREND){
693 vip.out_size = BUFSIZE;
694 memset(data, 0, BUFSIZE);
696 if ((rc = pioctl(jcr->last_fname, VIOCGETAL, &vip, 0)) < 0){
699 Mmsg2(jcr->errmsg, _("pioctl VIOCGETAL error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
700 Dmsg2(100, "pioctl VIOCGETAL error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
701 return bRC_BACL_error;
704 return send_acl_stream(jcr, STREAM_BACL_AFS_TEXT);
708 * Restore ACL data of AFS
710 * jcr - Job Control Record
711 * stream - a backup stream type number to restore_acl
713 * bRC_BACL_inval - input variables are invalid (NULL)
714 * bRC_BACL_ok - backup finish without problems
715 * bRC_BACL_error - when you can't backup acl data because some error
717 bRC_BACL BACL::afs_restore_acl (JCR *jcr, int stream){
720 struct ViceIoctl vip;
722 /* sanity check of input variables */
723 if (jcr == NULL || ff_pkt == NULL){
724 return bRC_BACL_inval;
728 vip.in_size = content_len;
732 if ((rc = pioctl(jcr->last_fname, VIOCSETAL, &vip, 0)) < 0){
735 Mmsg2(jcr->errmsg, _("pioctl VIOCSETAL error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
736 Dmsg2(100, "pioctl VIOCSETAL error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
738 return bRC_BACL_error;
742 #endif /* HAVE_AFS_ACL */
744 #include "bacl_osx.h"
745 #include "bacl_linux.h"
746 #include "bacl_freebsd.h"
747 #include "bacl_solaris.h"
748 // #include "bacl_aix.h"
751 * Creating the correct instance of the BACL for a supported OS
755 #if defined(HAVE_DARWIN_OS)
756 return new BACL_OSX();
757 #elif defined(HAVE_LINUX_OS)
758 return new BACL_Linux();
759 #elif defined(HAVE_FREEBSD_OS)
760 return new BACL_FreeBSD();
761 #elif defined(HAVE_HURD_OS)
762 return new BACL_Hurd();
763 #elif defined(HAVE_AIX_OS)
764 return new BACL_AIX();
765 #elif defined(HAVE_IRIX_OS)
766 return new BACL_IRIX();
767 #elif defined(HAVE_OSF1_OS)
768 return new BACL_OSF1();
769 #elif defined(HAVE_SUN_OS)
770 return new BACL_Solaris();
776 #endif /* HAVE_ACL */