2 Bacula® - The Network Backup Solution
4 Copyright (C) 2004-2009 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Functions to handle ACLs for bacula.
31 * We handle two different types of ACLs: access and default ACLS.
32 * On most systems that support default ACLs they only apply to directories.
34 * On some systems (eg. linux and FreeBSD) we must obtain the two ACLs
35 * independently, while others (eg. Solaris) provide both in one call.
37 * The Filed saves ACLs in their native format and uses different streams
38 * for all different platforms. Currently we only allow ACLs to be restored
39 * which were saved in the native format of the platform they are extracted
40 * on. Later on we might add conversion functions for mapping from one
41 * platform to an other or allow restores of systems that use the same
44 * Its also interesting to see what the exact format of acl text is on
45 * certain platforms and if they use they same encoding we might allow
46 * different platform streams to be decoded on an other similar platform.
48 * Original written by Preben 'Peppe' Guldberg, December MMIV
49 * Major rewrite by Marco van Wieringen, November MMVIII
58 #if !defined(HAVE_ACL)
60 * Entry points when compiled without support for ACLs or on an unsupported platform.
62 bsub_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
64 return bsub_exit_fatal;
67 bsub_exit_code parse_acl_stream(JCR *jcr, int stream)
69 return bsub_exit_fatal;
73 * Send an ACL stream to the SD.
75 static bsub_exit_code send_acl_stream(JCR *jcr, int stream)
77 BSOCK *sd = jcr->store_bsock;
79 #ifdef FD_NO_SEND_TEST
86 if (jcr->acl_data_len <= 0)
92 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
93 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
95 return bsub_exit_fatal;
99 * Send the buffer to the storage deamon
101 Dmsg1(400, "Backing up ACL <%s>\n", jcr->acl_data);
103 sd->msg = jcr->acl_data;
104 sd->msglen = jcr->acl_data_len + 1;
108 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
110 return bsub_exit_fatal;
113 jcr->JobBytes += sd->msglen;
115 if (!sd->signal(BNET_EOD)) {
116 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
118 return bsub_exit_fatal;
121 Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
125 #if defined(HAVE_AIX_OS)
127 #include <sys/access.h>
130 * Define the supported ACL streams for this OS
132 static int os_access_acl_streams[1] = { STREAM_ACL_AIX_TEXT };
133 static int os_default_acl_streams[1] = { -1 };
135 static bsub_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
139 if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
140 jcr->acl_data_len = pm_strcpy(jcr->acl_data, acl_text);
141 actuallyfree(acl_text);
142 return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT);
144 return bsub_exit_nok;
147 static bsub_exit_code aix_parse_acl_streams(JCR *jcr, int stream)
149 if (acl_put(jcr->last_fname, jcr->acl_data, 0) != 0) {
150 return bsub_exit_nok;
156 * For this OS setup the build and parse function pointer to the OS specific functions.
158 static bsub_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = aix_build_acl_streams;
159 static bsub_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = aix_parse_acl_streams;
161 #elif defined(HAVE_DARWIN_OS) || \
162 defined(HAVE_FREEBSD_OS) || \
163 defined(HAVE_IRIX_OS) || \
164 defined(HAVE_OSF1_OS) || \
165 defined(HAVE_LINUX_OS)
167 #include <sys/types.h>
169 #ifdef HAVE_SYS_ACL_H
172 #error "configure failed to detect availability of sys/acl.h"
175 /* On IRIX we can get shortened ACLs */
176 #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
177 #define acl_to_text(acl,len) acl_to_short_text((acl), (len))
180 /* In Linux we can get numeric and/or shorted ACLs */
181 #if defined(HAVE_LINUX_OS)
182 #if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
183 #define BACL_ALTERNATE_TEXT (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
184 #elif defined(BACL_WANT_SHORT_ACLS)
185 #define BACL_ALTERNATE_TEXT TEXT_ABBREVIATE
186 #elif defined(BACL_WANT_NUMERIC_IDS)
187 #define BACL_ALTERNATE_TEXT TEXT_NUMERIC_IDS
189 #ifdef BACL_ALTERNATE_TEXT
190 #include <acl/libacl.h>
191 #define acl_to_text(acl,len) (acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
196 * Some generic functions used by multiple OSes.
198 static acl_type_t bac_to_os_acltype(bacl_type acltype)
203 case BACL_TYPE_ACCESS:
204 ostype = ACL_TYPE_ACCESS;
206 case BACL_TYPE_DEFAULT:
207 ostype = ACL_TYPE_DEFAULT;
210 #ifdef ACL_TYPE_DEFAULT_DIR
211 case BACL_TYPE_DEFAULT_DIR:
213 * OSF1 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
215 ostype = ACL_TYPE_DEFAULT_DIR;
218 #ifdef ACL_TYPE_EXTENDED
219 case BACL_TYPE_EXTENDED:
221 * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
223 ostype = ACL_TYPE_EXTENDED;
228 * This should never happen, as the per OS version function only tries acl
229 * types supported on a certain platform.
231 ostype = (acl_type_t)ACL_TYPE_NONE;
237 #if !defined(HAVE_DARWIN_OS)
239 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
240 * There is no need to store those acls as we already store the stat bits too.
242 static bool acl_is_trivial(acl_t acl)
245 * acl is trivial if it has only the following entries:
252 #if defined(HAVE_FREEBSD_OS) || \
253 defined(HAVE_LINUX_OS)
256 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
257 while (entry_available == 1) {
259 * Get the tag type of this acl entry.
260 * If we fail to get the tagtype we call the acl non-trivial.
262 if (acl_get_tag_type(ace, &tag) < 0)
265 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
267 if (tag != ACL_USER_OBJ &&
268 tag != ACL_GROUP_OBJ &&
271 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
274 #elif defined(HAVE_IRIX_OS)
277 for (n = 0; n < acl->acl_cnt; n++) {
278 ace = &acl->acl_entry[n];
282 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
284 if (tag != ACL_USER_OBJ &&
285 tag != ACL_GROUP_OBJ &&
286 tag != ACL_OTHER_OBJ)
290 #elif defined(HAVE_OSF1_OS)
293 ace = acl->acl_first;
294 count = acl->acl_num;
297 tag = ace->entry->acl_type;
299 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
301 if (tag != ACL_USER_OBJ &&
302 tag != ACL_GROUP_OBJ &&
306 * On Tru64, perm can also contain non-standard bits such as
307 * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
309 if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
320 * Generic wrapper around acl_get_file call.
322 static bsub_exit_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
329 ostype = bac_to_os_acltype(acltype);
330 acl = acl_get_file(jcr->last_fname, ostype);
332 #if defined(HAVE_IRIX_OS)
334 * From observation, IRIX's acl_get_file() seems to return a
335 * non-NULL acl with a count field of -1 when a file has no ACL
336 * defined, while IRIX's acl_to_text() returns NULL when presented
339 * Checking the count in the acl structure before calling
340 * acl_to_text() lets us avoid error messages about files
341 * with no ACLs, without modifying the flow of the code used for
342 * other operating systems, and it saves making some calls
343 * to acl_to_text() besides.
345 if (acl->acl_cnt <= 0) {
346 pm_strcpy(jcr->acl_data, "");
347 jcr->acl_data_len = 0;
353 #if !defined(HAVE_DARWIN_OS)
355 * Make sure this is not just a trivial ACL.
357 if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
359 * The ACLs simply reflect the (already known) standard permissions
360 * So we don't send an ACL stream to the SD.
362 pm_strcpy(jcr->acl_data, "");
363 jcr->acl_data_len = 0;
369 if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
370 jcr->acl_data_len = pm_strcpy(jcr->acl_data, acl_text);
376 Mmsg2(jcr->errmsg, _("acl_to_text error on file \"%s\": ERR=%s\n"),
377 jcr->last_fname, be.bstrerror());
378 Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",
379 jcr->last_fname, be.bstrerror());
381 pm_strcpy(jcr->acl_data, "");
382 jcr->acl_data_len = 0;
384 return bsub_exit_nok;
388 * Handle errors gracefully.
390 if (acl == (acl_t)NULL) {
392 #if defined(BACL_ENOTSUP)
394 break; /* not supported */
397 pm_strcpy(jcr->acl_data, "");
398 jcr->acl_data_len = 0;
401 /* Some real error */
402 Mmsg2(jcr->errmsg, _("acl_get_file error on file \"%s\": ERR=%s\n"),
403 jcr->last_fname, be.bstrerror());
404 Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",
405 jcr->last_fname, be.bstrerror());
407 pm_strcpy(jcr->acl_data, "");
408 jcr->acl_data_len = 0;
409 return bsub_exit_nok;
413 * Not supported, just pretend there is nothing to see
415 pm_strcpy(jcr->acl_data, "");
416 jcr->acl_data_len = 0;
421 * Generic wrapper around acl_set_file call.
423 static bsub_exit_code generic_set_acl_on_os(JCR *jcr, bacl_type acltype)
430 * If we get empty default ACLs, clear ACLs now
432 ostype = bac_to_os_acltype(acltype);
433 if (ostype == ACL_TYPE_DEFAULT && strlen(jcr->acl_data) == 0) {
434 if (acl_delete_def_file(jcr->last_fname) == 0) {
441 Mmsg2(jcr->errmsg, _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
442 jcr->last_fname, be.bstrerror());
443 return bsub_exit_nok;
447 acl = acl_from_text(jcr->acl_data);
449 Mmsg2(jcr->errmsg, _("acl_from_text error on file \"%s\": ERR=%s\n"),
450 jcr->last_fname, be.bstrerror());
451 Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",
452 jcr->acl_data, jcr->last_fname, be.bstrerror());
453 return bsub_exit_nok;
456 #ifndef HAVE_FREEBSD_OS
458 * FreeBSD always fails acl_valid() - at least on valid input...
459 * As it does the right thing, given valid input, just ignore acl_valid().
461 if (acl_valid(acl) != 0) {
462 Mmsg2(jcr->errmsg, _("acl_valid error on file \"%s\": ERR=%s\n"),
463 jcr->last_fname, be.bstrerror());
464 Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",
465 jcr->acl_data, jcr->last_fname, be.bstrerror());
467 return bsub_exit_nok;
472 * Restore the ACLs, but don't complain about links which really should
473 * not have attributes, and the file it is linked to may not yet be restored.
474 * This is only true for the old acl streams as in the new implementation we
475 * don't save acls of symlinks (which cannot have acls anyhow)
477 if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
481 return bsub_exit_nok;
483 Mmsg2(jcr->errmsg, _("acl_set_file error on file \"%s\": ERR=%s\n"),
484 jcr->last_fname, be.bstrerror());
485 Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
486 jcr->acl_data, jcr->last_fname, be.bstrerror());
488 return bsub_exit_nok;
496 * OS specific functions for handling different types of acl streams.
498 #if defined(HAVE_DARWIN_OS)
500 * Define the supported ACL streams for this OS
502 static int os_access_acl_streams[1] = { STREAM_ACL_DARWIN_ACCESS_ACL };
503 static int os_default_acl_streams[1] = { -1 };
505 static bsub_exit_code darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
507 #if defined(ACL_TYPE_EXTENDED)
509 * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
510 * and acl_get_file (name, ACL_TYPE_DEFAULT)
511 * always return NULL / EINVAL. There is no point in making
512 * these two useless calls. The real ACL is retrieved through
513 * acl_get_file (name, ACL_TYPE_EXTENDED).
515 * Read access ACLs for files, dirs and links
517 if (generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED) == bsub_exit_fatal)
518 return bsub_exit_fatal;
521 * Read access ACLs for files, dirs and links
523 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bsub_exit_fatal)
524 return bsub_exit_fatal;
527 if (jcr->acl_data_len > 0) {
528 return send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL);
533 static bsub_exit_code darwin_parse_acl_streams(JCR *jcr, int stream)
535 #if defined(ACL_TYPE_EXTENDED)
536 return generic_set_acl_on_os(jcr, BACL_TYPE_EXTENDED);
538 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
543 * For this OS setup the build and parse function pointer to the OS specific functions.
545 static bsub_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = darwin_build_acl_streams;
546 static bsub_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = darwin_parse_acl_streams;
548 #elif defined(HAVE_FREEBSD_OS) || \
549 defined(HAVE_IRIX_OS) || \
550 defined(HAVE_LINUX_OS)
553 * Define the supported ACL streams for these OSes
555 #if defined(HAVE_FREEBSD_OS)
556 static int os_access_acl_streams[1] = { STREAM_ACL_FREEBSD_ACCESS_ACL };
557 static int os_default_acl_streams[1] = { STREAM_ACL_FREEBSD_DEFAULT_ACL };
558 #elif defined(HAVE_IRIX_OS)
559 static int os_access_acl_streams[1] = { STREAM_ACL_IRIX_ACCESS_ACL };
560 static int os_default_acl_streams[1] = { STREAM_ACL_IRIX_DEFAULT_ACL };
561 #elif defined(HAVE_LINUX_OS)
562 static int os_access_acl_streams[1] = { STREAM_ACL_LINUX_ACCESS_ACL };
563 static int os_default_acl_streams[1] = { STREAM_ACL_LINUX_DEFAULT_ACL };
566 static bsub_exit_code generic_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
569 * Read access ACLs for files, dirs and links
571 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bsub_exit_fatal)
572 return bsub_exit_fatal;
574 if (jcr->acl_data_len > 0) {
575 if (send_acl_stream(jcr, os_access_acl_streams[0]) == bsub_exit_fatal)
576 return bsub_exit_fatal;
580 * Directories can have default ACLs too
582 if (ff_pkt->type == FT_DIREND) {
583 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bsub_exit_fatal)
584 return bsub_exit_fatal;
585 if (jcr->acl_data_len > 0) {
586 if (send_acl_stream(jcr, os_default_acl_streams[0]) == bsub_exit_fatal)
587 return bsub_exit_fatal;
593 static bsub_exit_code generic_parse_acl_streams(JCR *jcr, int stream)
598 case STREAM_UNIX_ACCESS_ACL:
599 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
600 case STREAM_UNIX_DEFAULT_ACL:
601 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
604 * See what type of acl it is.
606 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
607 if (os_access_acl_streams[cnt] == stream) {
608 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
611 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
612 if (os_default_acl_streams[cnt] == stream) {
613 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
618 return bsub_exit_nok;
622 * For this OSes setup the build and parse function pointer to the OS specific functions.
624 static bsub_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_build_acl_streams;
625 static bsub_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = generic_parse_acl_streams;
627 #elif defined(HAVE_OSF1_OS)
630 * Define the supported ACL streams for this OS
632 static int os_access_acl_streams[1] = { STREAM_ACL_TRU64_ACCESS_ACL };
633 static int os_default_acl_streams[2] = { STREAM_ACL_TRU64_DEFAULT_ACL, STREAM_ACL_TRU64_DEFAULT_DIR_ACL };
635 static bsub_exit_code tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
638 * Read access ACLs for files, dirs and links
640 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
641 return bsub_exit_nok;
642 if (jcr->acl_data_len > 0) {
643 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL))
644 return bsub_exit_nok;
647 * Directories can have default ACLs too
649 if (ff_pkt->type == FT_DIREND) {
650 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
651 return bsub_exit_nok;
652 if (jcr->acl_data_len > 0) {
653 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL))
654 return bsub_exit_nok;
657 * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
658 * This is an inherited acl for all subdirs.
659 * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
660 * Section 21.5 Default ACLs
662 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR)) < 0)
663 return bsub_exit_nok;
664 if (jcr->acl_data_len > 0) {
665 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL))
666 return bsub_exit_nok;
672 static bsub_exit_code tru64_parse_acl_streams(JCR *jcr, int stream)
675 case STREAM_UNIX_ACCESS_ACL:
676 case STREAM_ACL_TRU64_ACCESS_ACL:
677 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
678 case STREAM_UNIX_DEFAULT_ACL:
679 case STREAM_ACL_TRU64_DEFAULT_ACL:
680 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
681 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
682 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR);
686 * For this OS setup the build and parse function pointer to the OS specific functions.
688 static bsub_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = tru64_build_acl_streams;
689 static bsub_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = tru64_parse_acl_streams;
693 #elif defined(HAVE_HPUX_OS)
694 #ifdef HAVE_SYS_ACL_H
697 #error "configure failed to detect availability of sys/acl.h"
703 * Define the supported ACL streams for this OS
705 static int os_access_acl_streams[1] = { STREAM_ACL_HPUX_ACL_ENTRY };
706 static int os_default_acl_streams[1] = { -1 };
709 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
710 * There is no need to store those acls as we already store the stat bits too.
712 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
717 for (n = 0; n < count; n++) {
720 * See if this acl just is the stat mode in acl form.
722 if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
723 (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
724 (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
731 * OS specific functions for handling different types of acl streams.
733 static bsub_exit_code hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
736 struct acl_entry acls[NACLENTRIES];
740 if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
742 #if defined(BACL_ENOTSUP)
745 * Not supported, just pretend there is nothing to see
747 pm_strcpy(jcr->acl_data, "");
748 jcr->acl_data_len = 0;
752 pm_strcpy(jcr->acl_data, "");
753 jcr->acl_data_len = 0;
756 Mmsg2(jcr->errmsg, _("getacl error on file \"%s\": ERR=%s\n"),
757 jcr->last_fname, be.bstrerror());
758 Dmsg2(100, "getacl error file=%s ERR=%s\n",
759 jcr->last_fname, be.bstrerror());
761 pm_strcpy(jcr->acl_data, "");
762 jcr->acl_data_len = 0;
763 return bsub_exit_nok;
767 pm_strcpy(jcr->acl_data, "");
768 jcr->acl_data_len = 0;
771 if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
772 if (acl_is_trivial(n, acls, ff_pkt->statp)) {
774 * The ACLs simply reflect the (already known) standard permissions
775 * So we don't send an ACL stream to the SD.
777 pm_strcpy(jcr->acl_data, "");
778 jcr->acl_data_len = 0;
781 if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
782 jcr->acl_data_len = pm_strcpy(jcr->acl_data, acl_text);
783 actuallyfree(acl_text);
785 return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
787 Mmsg2(jcr->errmsg, _("acltostr error on file \"%s\": ERR=%s\n"),
788 jcr->last_fname, be.bstrerror());
789 Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",
790 jcr->acl_data, jcr->last_fname, be.bstrerror());
791 return bsub_exit_nok;
793 return bsub_exit_nok;
796 static bsub_exit_code hpux_parse_acl_streams(JCR *jcr, int stream)
799 struct acl_entry acls[NACLENTRIES];
802 n = strtoacl(jcr->acl_data, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
804 Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
805 jcr->last_fname, be.bstrerror());
806 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
807 jcr->acl_data, jcr->last_fname, be.bstrerror());
808 return bsub_exit_nok;
810 if (strtoacl(jcr->acl_data, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
811 Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
812 jcr->last_fname, be.bstrerror());
813 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
814 jcr->acl_data, jcr->last_fname, be.bstrerror());
816 return bsub_exit_nok;
819 * Restore the ACLs, but don't complain about links which really should
820 * not have attributes, and the file it is linked to may not yet be restored.
821 * This is only true for the old acl streams as in the new implementation we
822 * don't save acls of symlinks (which cannot have acls anyhow)
824 if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
827 return bsub_exit_nok;
829 Mmsg2(jcr->errmsg, _("setacl error on file \"%s\": ERR=%s\n"),
830 jcr->last_fname, be.bstrerror());
831 Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
832 jcr->acl_data, jcr->last_fname, be.bstrerror());
833 return bsub_exit_nok;
840 * For this OS setup the build and parse function pointer to the OS specific functions.
842 static bsub_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = hpux_build_acl_streams;
843 static bsub_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = hpux_parse_acl_streams;
845 #elif defined(HAVE_SUN_OS)
846 #ifdef HAVE_SYS_ACL_H
849 #error "configure failed to detect availability of sys/acl.h"
852 #if defined(HAVE_EXTENDED_ACL)
854 * We define some internals of the Solaris acl libs here as those
855 * are not exposed yet. Probably because they want us to see the
856 * acls as opague data. But as we need to support different platforms
857 * and versions of Solaris we need to expose some data to be able
858 * to determine the type of acl used to stuff it into the correct
859 * data stream. I know this is far from portable, but maybe the
860 * proper interface is exposed later on and we can get ride of
861 * this kludge. Newer versions of Solaris include sys/acl_impl.h
862 * which has implementation details of acls, if thats included we
863 * don't have to define it ourself.
865 #if !defined(_SYS_ACL_IMPL_H)
866 typedef enum acl_type {
873 * Two external references to functions in the libsec library function not in current include files.
876 int acl_type(acl_t *);
877 char *acl_strerror(int);
881 * Define the supported ACL streams for this OS
883 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT, STREAM_ACL_SOLARIS_ACE };
884 static int os_default_acl_streams[1] = { -1 };
887 * As the new libsec interface with acl_totext and acl_fromtext also handles
888 * the old format from acltotext we can use the new functions even
889 * for acls retrieved and stored in the database with older fd versions. If the
890 * new interface is not defined (Solaris 9 and older we fall back to the old code)
892 static bsub_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
894 int acl_enabled, flags;
897 bsub_exit_code stream_status = bsub_exit_nok;
901 * See if filesystem supports acls.
903 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
904 switch (acl_enabled) {
906 pm_strcpy(jcr->acl_data, "");
907 jcr->acl_data_len = 0;
910 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
911 jcr->last_fname, be.bstrerror());
912 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
913 jcr->last_fname, be.bstrerror());
914 return bsub_exit_nok;
920 * Get ACL info: don't bother allocating space if there is only a trivial ACL.
922 if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
923 Mmsg2(jcr->errmsg, _("acl_get error on file \"%s\": ERR=%s\n"),
924 jcr->last_fname, acl_strerror(errno));
925 Dmsg2(100, "acl_get error file=%s ERR=%s\n",
926 jcr->last_fname, acl_strerror(errno));
927 return bsub_exit_nok;
932 * The ACLs simply reflect the (already known) standard permissions
933 * So we don't send an ACL stream to the SD.
935 pm_strcpy(jcr->acl_data, "");
936 jcr->acl_data_len = 0;
940 #if defined(ACL_SID_FMT)
942 * New format flag added in newer Solaris versions.
944 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
946 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
947 #endif /* ACL_SID_FMT */
949 if ((acl_text = acl_totext(aclp, flags)) != NULL) {
950 jcr->acl_data_len = pm_strcpy(jcr->acl_data, acl_text);
951 actuallyfree(acl_text);
953 switch (acl_type(aclp)) {
955 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
958 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE);
966 return stream_status;
969 static bsub_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
972 int acl_enabled, error;
976 case STREAM_UNIX_ACCESS_ACL:
977 case STREAM_ACL_SOLARIS_ACLENT:
978 case STREAM_ACL_SOLARIS_ACE:
980 * First make sure the filesystem supports acls.
982 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
983 switch (acl_enabled) {
985 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
987 return bsub_exit_nok;
989 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
990 jcr->last_fname, be.bstrerror());
991 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
992 jcr->acl_data, jcr->last_fname, be.bstrerror());
993 return bsub_exit_nok;
996 * On a filesystem with ACL support make sure this particilar ACL type can be restored.
999 case STREAM_ACL_SOLARIS_ACLENT:
1001 * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
1003 if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
1004 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without aclent acl support\n"),
1006 return bsub_exit_nok;
1009 case STREAM_ACL_SOLARIS_ACE:
1011 * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
1013 if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
1014 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without ace acl support\n"),
1016 return bsub_exit_nok;
1021 * Stream id which doesn't describe the type of acl which is encoded.
1028 if ((error = acl_fromtext(jcr->acl_data, &aclp)) != 0) {
1029 Mmsg2(jcr->errmsg, _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1030 jcr->last_fname, acl_strerror(error));
1031 Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",
1032 jcr->acl_data, jcr->last_fname, acl_strerror(error));
1033 return bsub_exit_nok;
1037 * Validate that the conversion gave us the correct acl type.
1040 case STREAM_ACL_SOLARIS_ACLENT:
1041 if (acl_type(aclp) != ACLENT_T) {
1042 Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1044 return bsub_exit_nok;
1047 case STREAM_ACL_SOLARIS_ACE:
1048 if (acl_type(aclp) != ACE_T) {
1049 Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1051 return bsub_exit_nok;
1056 * Stream id which doesn't describe the type of acl which is encoded.
1062 * Restore the ACLs, but don't complain about links which really should
1063 * not have attributes, and the file it is linked to may not yet be restored.
1064 * This is only true for the old acl streams as in the new implementation we
1065 * don't save acls of symlinks (which cannot have acls anyhow)
1067 if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1068 Mmsg2(jcr->errmsg, _("acl_set error on file \"%s\": ERR=%s\n"),
1069 jcr->last_fname, acl_strerror(error));
1070 Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",
1071 jcr->acl_data, jcr->last_fname, acl_strerror(error));
1074 return bsub_exit_nok;
1078 return bsub_exit_ok;
1080 return bsub_exit_nok;
1081 } /* end switch (stream) */
1084 #else /* HAVE_EXTENDED_ACL */
1087 * Define the supported ACL streams for this OS
1089 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT };
1090 static int os_default_acl_streams[1] = { -1 };
1093 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1094 * There is no need to store those acls as we already store the stat bits too.
1096 static bool acl_is_trivial(int count, aclent_t *entries)
1101 for (n = 0; n < count; n++) {
1104 if (!(ace->a_type == USER_OBJ ||
1105 ace->a_type == GROUP_OBJ ||
1106 ace->a_type == OTHER_OBJ ||
1107 ace->a_type == CLASS_OBJ))
1114 * OS specific functions for handling different types of acl streams.
1116 static bsub_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1123 n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1124 if (n < MIN_ACL_ENTRIES)
1125 return bsub_exit_nok;
1127 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1128 if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1129 if (acl_is_trivial(n, acls)) {
1131 * The ACLs simply reflect the (already known) standard permissions
1132 * So we don't send an ACL stream to the SD.
1135 pm_strcpy(jcr->acl_data, "");
1136 jcr->acl_data_len = 0;
1137 return bsub_exit_ok;
1140 if ((acl_text = acltotext(acls, n)) != NULL) {
1141 jcr->acl_data_len = pm_strcpy(jcr->acl_data, acl_text);
1142 actuallyfree(acl_text);
1144 return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1147 Mmsg2(jcr->errmsg, _("acltotext error on file \"%s\": ERR=%s\n"),
1148 jcr->last_fname, be.bstrerror());
1149 Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",
1150 jcr->acl_data, jcr->last_fname, be.bstrerror());
1154 return bsub_exit_nok;
1157 static bsub_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
1163 acls = aclfromtext(jcr->acl_data, &n);
1165 Mmsg2(jcr->errmsg, _("aclfromtext error on file \"%s\": ERR=%s\n"),
1166 jcr->last_fname, be.bstrerror());
1167 Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",
1168 jcr->acl_data, jcr->last_fname, be.bstrerror());
1169 return bsub_exit_nok;
1173 * Restore the ACLs, but don't complain about links which really should
1174 * not have attributes, and the file it is linked to may not yet be restored.
1176 if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
1180 return bsub_exit_nok;
1182 Mmsg2(jcr->errmsg, _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
1183 jcr->last_fname, be.bstrerror());
1184 Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
1185 jcr->acl_data, jcr->last_fname, be.bstrerror());
1187 return bsub_exit_nok;
1191 return bsub_exit_ok;
1193 #endif /* HAVE_EXTENDED_ACL */
1196 * For this OS setup the build and parse function pointer to the OS specific functions.
1198 static bsub_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_acl_streams;
1199 static bsub_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = solaris_parse_acl_streams;
1201 #endif /* HAVE_SUN_OS */
1204 * Entry points when compiled with support for ACLs on a supported platform.
1208 * Read and send an ACL for the last encountered file.
1210 bsub_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1213 * Call the appropriate function.
1215 if (os_build_acl_streams) {
1216 return (*os_build_acl_streams)(jcr, ff_pkt);
1218 return bsub_exit_nok;
1221 bsub_exit_code parse_acl_streams(JCR *jcr, int stream)
1226 case STREAM_UNIX_ACCESS_ACL:
1227 case STREAM_UNIX_DEFAULT_ACL:
1229 * Handle legacy ACL streams.
1231 if (os_parse_acl_streams) {
1232 return (*os_parse_acl_streams)(jcr, stream);
1236 if (os_parse_acl_streams) {
1238 * Walk the os_access_acl_streams array with the supported Access ACL streams for this OS.
1240 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1241 if (os_access_acl_streams[cnt] == stream) {
1242 return (*os_parse_acl_streams)(jcr, stream);
1246 * Walk the os_default_acl_streams array with the supported Default ACL streams for this OS.
1248 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1249 if (os_default_acl_streams[cnt] == stream) {
1250 return (*os_parse_acl_streams)(jcr, stream);
1256 Qmsg2(jcr, M_WARNING, 0,
1257 _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
1258 jcr->last_fname, stream);
1259 return bsub_exit_nok;