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.
47 * As we implement the decoding/restoring process as a big switch based
48 * on the stream number being passed in extending the switching code is
51 * Original written by Preben 'Peppe' Guldberg, December MMIV
52 * Major rewrite by Marco van Wieringen, November MMVIII
61 * List of supported OSes. Everything outside that gets stub functions.
62 * Also when ACL support is explicitly disabled.
63 * Not sure if all the HAVE_XYZ_OS are correct for autoconf.
64 * The ones that says man page, are coded according to man pages only.
66 #if !defined(HAVE_ACL) /* ACL support is required, of course */ \
67 || !( defined(HAVE_AIX_OS) /* man page -- may need flags */ \
68 || defined(HAVE_DARWIN_OS) /* tested -- compile without flags */ \
69 || defined(HAVE_FREEBSD_OS) /* tested -- compile without flags */ \
70 || defined(HAVE_HPUX_OS) /* man page -- may need flags */ \
71 || defined(HAVE_IRIX_OS) /* man page -- compile without flags */ \
72 || defined(HAVE_LINUX_OS) /* tested -- compile with -lacl */ \
73 || defined(HAVE_OSF1_OS) /* man page -- may need -lpacl */ \
74 || defined(HAVE_SUN_OS) /* tested -- compile with -lsec */ \
78 * Entry points when compiled without support for ACLs or on an unsupported platform.
80 bool build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
82 Jmsg(jcr, M_FATAL, 0, _("ACL support not configured for your machine.\n"));
86 bool parse_acl_stream(JCR *jcr, int stream)
88 Jmsg(jcr, M_FATAL, 0, _("ACL support not configured for your machine.\n"));
95 * Send an ACL stream to the SD.
97 static bool send_acl_stream(JCR *jcr, int stream)
99 BSOCK *sd = jcr->store_bsock;
101 #ifdef FD_NO_SEND_TEST
108 if (jcr->acl_data_len <= 0)
114 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
115 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
122 * Send the buffer to the storage deamon
124 Dmsg1(400, "Backing up ACL <%s>\n", jcr->acl_data);
126 sd->msg = jcr->acl_data;
127 sd->msglen = jcr->acl_data_len + 1;
131 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
137 jcr->JobBytes += sd->msglen;
139 if (!sd->signal(BNET_EOD)) {
140 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
146 Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
151 #if defined(HAVE_AIX_OS)
153 #include <sys/access.h>
155 static bool aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
159 if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
160 jcr->acl_data_len = pm_strcpy(jcr->acl_data, acl_text);
161 actuallyfree(acl_text);
163 return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT);
169 static bool aix_parse_acl_stream(JCR *jcr, int stream)
171 if (acl_put(jcr->last_fname, jcr->acl_data, 0) != 0) {
178 #elif defined(HAVE_DARWIN_OS) \
179 || defined(HAVE_FREEBSD_OS) \
180 || defined(HAVE_IRIX_OS) \
181 || defined(HAVE_OSF1_OS) \
182 || defined(HAVE_LINUX_OS)
184 #include <sys/types.h>
186 #ifdef HAVE_SYS_ACL_H
189 #error "configure failed to detect availability of sys/acl.h"
192 /* On IRIX we can get shortened ACLs */
193 #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
194 #define acl_to_text(acl,len) acl_to_short_text((acl), (len))
197 /* In Linux we can get numeric and/or shorted ACLs */
198 #if defined(HAVE_LINUX_OS)
199 #if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
200 #define BACL_ALTERNATE_TEXT (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
201 #elif defined(BACL_WANT_SHORT_ACLS)
202 #define BACL_ALTERNATE_TEXT TEXT_ABBREVIATE
203 #elif defined(BACL_WANT_NUMERIC_IDS)
204 #define BACL_ALTERNATE_TEXT TEXT_NUMERIC_IDS
206 #ifdef BACL_ALTERNATE_TEXT
207 #include <acl/libacl.h>
208 #define acl_to_text(acl,len) (acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
213 * Some generic functions used by multiple OSes.
215 static acl_type_t bac_to_os_acltype(bacl_type acltype)
220 case BACL_TYPE_ACCESS:
221 ostype = ACL_TYPE_ACCESS;
223 case BACL_TYPE_DEFAULT:
224 ostype = ACL_TYPE_DEFAULT;
227 #ifdef ACL_TYPE_DEFAULT_DIR
228 case BACL_TYPE_DEFAULT_DIR:
230 * OSF1 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
232 ostype = ACL_TYPE_DEFAULT_DIR;
235 #ifdef ACL_TYPE_EXTENDED
236 case BACL_TYPE_EXTENDED:
238 * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
240 ostype = ACL_TYPE_EXTENDED;
245 * This should never happen, as the per os version function only tries acl
246 * types supported on a certain platform.
248 ostype = (acl_type_t)ACL_TYPE_NONE;
255 #if !defined(HAVE_DARWIN_OS)
257 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
258 * There is no need to store those acls as we already store the stat bits too.
260 static bool acl_is_trivial(acl_t acl)
263 * acl is trivial if it has only the following entries:
270 #if defined(HAVE_FREEBSD_OS) || defined(HAVE_LINUX_OS)
273 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
274 while (entry_available == 1) {
276 * Get the tag type of this acl entry.
277 * If we fail to get the tagtype we call the acl non-trivial.
279 if (acl_get_tag_type(ace, &tag) < 0)
283 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
285 if (tag != ACL_USER_OBJ &&
286 tag != ACL_GROUP_OBJ &&
290 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
294 #elif defined(HAVE_IRIX_OS)
297 for (n = 0; n < acl->acl_cnt; n++) {
298 ace = &acl->acl_entry[n];
302 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
304 if (tag != ACL_USER_OBJ &&
305 tag != ACL_GROUP_OBJ &&
311 #elif defined(HAVE_OSF1_OS)
314 ace = acl->acl_first;
315 count = acl->acl_num;
318 tag = ace->entry->acl_type;
321 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
323 if (tag != ACL_USER_OBJ &&
324 tag != ACL_GROUP_OBJ &&
329 * On Tru64, perm can also contain non-standard bits such as
330 * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
332 if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
345 * Generic wrapper around acl_get_file call.
347 static int generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
354 ostype = bac_to_os_acltype(acltype);
355 acl = acl_get_file(jcr->last_fname, ostype);
357 #if defined(HAVE_IRIX_OS)
359 * From observation, IRIX's acl_get_file() seems to return a
360 * non-NULL acl with a count field of -1 when a file has no ACL
361 * defined, while IRIX's acl_to_text() returns NULL when presented
364 * Checking the count in the acl structure before calling
365 * acl_to_text() lets us avoid error messages about files
366 * with no ACLs, without modifying the flow of the code used for
367 * other operating systems, and it saves making some calls
368 * to acl_to_text() besides.
370 if (acl->acl_cnt <= 0) {
371 pm_strcpy(jcr->acl_data, "");
377 #if !defined(HAVE_DARWIN_OS)
379 * Make sure this is not just a trivial ACL.
381 if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
383 * The ACLs simply reflect the (already known) standard permissions
384 * So we don't send an ACL stream to the SD.
386 pm_strcpy(jcr->acl_data, "");
392 if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
393 len = pm_strcpy(jcr->acl_data, acl_text);
401 Jmsg2(jcr, M_ERROR, 0, _("acl_to_text error on file \"%s\": ERR=%s\n"),
402 jcr->last_fname, be.bstrerror());
403 Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",
404 jcr->last_fname, be.bstrerror());
406 pm_strcpy(jcr->acl_data, "");
413 * Handle errors gracefully.
416 #if defined(BACL_ENOTSUP)
419 * Not supported, just pretend there is nothing to see
421 pm_strcpy(jcr->acl_data, "");
426 Jmsg2(jcr, M_ERROR, 0, _("acl_get_file error on file \"%s\": ERR=%s\n"),
427 jcr->last_fname, be.bstrerror());
428 Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",
429 jcr->last_fname, be.bstrerror());
431 pm_strcpy(jcr->acl_data, "");
437 * Generic wrapper around acl_set_file call.
439 static bool generic_set_acl_on_os(JCR *jcr, bacl_type acltype)
445 * If we get empty default ACLs, clear ACLs now
447 ostype = bac_to_os_acltype(acltype);
448 if (ostype == ACL_TYPE_DEFAULT && strlen(jcr->acl_data) == 0) {
449 if (acl_delete_def_file(jcr->last_fname) == 0) {
453 Jmsg2(jcr, M_ERROR, 0, _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
454 jcr->last_fname, be.bstrerror());
459 acl = acl_from_text(jcr->acl_data);
462 Jmsg2(jcr, M_ERROR, 0, _("acl_from_text error on file \"%s\": ERR=%s\n"),
463 jcr->last_fname, be.bstrerror());
464 Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",
465 jcr->acl_data, jcr->last_fname, be.bstrerror());
471 * FreeBSD always fails acl_valid() - at least on valid input...
472 * As it does the right thing, given valid input, just ignore acl_valid().
474 #ifndef HAVE_FREEBSD_OS
475 if (acl_valid(acl) != 0) {
477 Jmsg2(jcr, M_ERROR, 0, _("ac_valid error on file \"%s\": ERR=%s\n"),
478 jcr->last_fname, be.bstrerror());
479 Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",
480 jcr->acl_data, jcr->last_fname, be.bstrerror());
488 * Restore the ACLs, but don't complain about links which really should
489 * not have attributes, and the file it is linked to may not yet be restored.
490 * This is only true for the old acl streams as in the new implementation we
491 * don't save acls of symlinks (which cannot have acls anyhow)
493 if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
495 Jmsg2(jcr, M_ERROR, 0, _("acl_set_file error on file \"%s\": ERR=%s\n"),
496 jcr->last_fname, be.bstrerror());
497 Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
498 jcr->acl_data, jcr->last_fname, be.bstrerror());
509 * OS specific functions for handling different types of acl streams.
511 #if defined(HAVE_DARWIN_OS)
512 static bool darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
514 #if defined(ACL_TYPE_EXTENDED)
516 * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
517 * and acl_get_file (name, ACL_TYPE_DEFAULT)
518 * always return NULL / EINVAL. There is no point in making
519 * these two useless calls. The real ACL is retrieved through
520 * acl_get_file (name, ACL_TYPE_EXTENDED).
522 * Read access ACLs for files, dirs and links
524 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED)) < 0)
528 * Read access ACLs for files, dirs and links
530 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
533 if (jcr->acl_data_len > 0) {
534 if (!send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL))
542 static bool darwin_parse_acl_stream(JCR *jcr, int stream)
545 case STREAM_UNIX_ACCESS_ACL:
546 case STREAM_ACL_DARWIN_ACCESS_ACL:
547 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
552 #elif defined(HAVE_FREEBSD_OS)
553 static bool freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
556 * Read access ACLs for files, dirs and links
558 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
561 if (jcr->acl_data_len > 0) {
562 if (!send_acl_stream(jcr, STREAM_ACL_FREEBSD_ACCESS_ACL))
567 * Directories can have default ACLs too
569 if (ff_pkt->type == FT_DIREND) {
570 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
573 if (jcr->acl_data_len > 0) {
574 if (!send_acl_stream(jcr, STREAM_ACL_FREEBSD_DEFAULT_ACL))
582 static bool freebsd_parse_acl_stream(JCR *jcr, int stream)
585 case STREAM_UNIX_ACCESS_ACL:
586 case STREAM_ACL_FREEBSD_ACCESS_ACL:
587 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
588 case STREAM_UNIX_DEFAULT_ACL:
589 case STREAM_ACL_FREEBSD_DEFAULT_ACL:
590 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
595 #elif defined(HAVE_IRIX_OS)
596 static bool irix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
599 * Read access ACLs for files, dirs and links
601 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
604 if (jcr->acl_data_len > 0) {
605 if (!send_acl_stream(jcr, STREAM_ACL_IRIX_ACCESS_ACL))
610 * Directories can have default ACLs too
612 if (ff_pkt->type == FT_DIREND) {
613 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
616 if (jcr->acl_data_len > 0) {
617 if (!send_acl_stream(jcr, STREAM_ACL_IRIX_DEFAULT_ACL))
625 static bool irix_parse_acl_stream(JCR *jcr, int stream)
628 case STREAM_UNIX_ACCESS_ACL:
629 case STREAM_ACL_IRIX_ACCESS_ACL:
630 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
631 case STREAM_UNIX_DEFAULT_ACL:
632 case STREAM_ACL_IRIX_DEFAULT_ACL:
633 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
638 #elif defined(HAVE_LINUX_OS)
639 static bool linux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
642 * Read access ACLs for files, dirs and links
644 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
647 if (jcr->acl_data_len > 0) {
648 if (!send_acl_stream(jcr, STREAM_ACL_LINUX_ACCESS_ACL))
653 * Directories can have default ACLs too
655 if (ff_pkt->type == FT_DIREND) {
656 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
659 if (jcr->acl_data_len > 0) {
660 if (!send_acl_stream(jcr, STREAM_ACL_LINUX_DEFAULT_ACL))
668 static bool linux_parse_acl_stream(JCR *jcr, int stream)
671 case STREAM_UNIX_ACCESS_ACL:
672 case STREAM_ACL_LINUX_ACCESS_ACL:
673 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
674 case STREAM_UNIX_DEFAULT_ACL:
675 case STREAM_ACL_LINUX_DEFAULT_ACL:
676 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
681 #elif defined(HAVE_OSF1_OS)
682 static bool tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
685 * Read access ACLs for files, dirs and links
687 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
690 if (jcr->acl_data_len > 0) {
691 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL))
696 * Directories can have default ACLs too
698 if (ff_pkt->type == FT_DIREND) {
699 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
702 if (jcr->acl_data_len > 0) {
703 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL))
708 * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
709 * This is an inherited acl for all subdirs.
710 * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
711 * Section 21.5 Default ACLs
713 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR)) < 0)
716 if (jcr->acl_data_len > 0) {
717 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL))
725 static bool tru64_parse_acl_stream(JCR *jcr, int stream)
728 case STREAM_UNIX_ACCESS_ACL:
729 case STREAM_ACL_TRU64_ACCESS_ACL:
730 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
731 case STREAM_UNIX_DEFAULT_ACL:
732 case STREAM_ACL_TRU64_DEFAULT_ACL:
733 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
734 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
735 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR);
739 #elif defined(HAVE_HPUX_OS)
740 #ifdef HAVE_SYS_ACL_H
743 #error "configure failed to detect availability of sys/acl.h"
749 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
750 * There is no need to store those acls as we already store the stat bits too.
752 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
757 for (n = 0; n < count; n++) {
761 * See if this acl just is the stat mode in acl form.
763 if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
764 (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
765 (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
773 * OS specific functions for handling different types of acl streams.
775 static bool hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
778 struct acl_entry acls[NACLENTRIES];
781 if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
783 #if defined(BACL_ENOTSUP)
786 * Not supported, just pretend there is nothing to see
788 pm_strcpy(jcr->acl_data, "");
793 Jmsg2(jcr, M_ERROR, 0, _("getacl error on file \"%s\": ERR=%s\n"),
794 jcr->last_fname, be.bstrerror());
795 Dmsg2(100, "getacl error file=%s ERR=%s\n",
796 jcr->last_fname, be.bstrerror());
798 pm_strcpy(jcr->acl_data, "");
804 pm_strcpy(jcr->acl_data, "");
808 if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
809 if (acl_is_trivial(n, acls, ff_pkt->statp)) {
811 * The ACLs simply reflect the (already known) standard permissions
812 * So we don't send an ACL stream to the SD.
814 pm_strcpy(jcr->acl_data, "");
818 if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
819 jcr->acl_data_len = pm_strcpy(jcr->acl_data, acl_text);
820 actuallyfree(acl_text);
822 return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
826 Jmsg2(jcr, M_ERROR, 0, _("acltostr error on file \"%s\": ERR=%s\n"),
827 jcr->last_fname, be.bstrerror());
828 Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",
829 jcr->acl_data, jcr->last_fname, be.bstrerror());
837 static bool hpux_parse_acl_stream(JCR *jcr, int stream)
840 struct acl_entry acls[NACLENTRIES];
842 n = strtoacl(jcr->acl_data, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
845 Jmsg2(jcr, M_ERROR, 0, _("strtoacl error on file \"%s\": ERR=%s\n"),
846 jcr->last_fname, be.bstrerror());
847 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
848 jcr->acl_data, jcr->last_fname, be.bstrerror());
852 if (strtoacl(jcr->acl_data, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
854 Jmsg2(jcr, M_ERROR, 0, _("strtoacl error on file \"%s\": ERR=%s\n"),
855 jcr->last_fname, be.bstrerror());
856 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
857 jcr->acl_data, jcr->last_fname, be.bstrerror());
862 * Restore the ACLs, but don't complain about links which really should
863 * not have attributes, and the file it is linked to may not yet be restored.
864 * This is only true for the old acl streams as in the new implementation we
865 * don't save acls of symlinks (which cannot have acls anyhow)
867 if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
869 Jmsg2(jcr, M_ERROR, 0, _("setacl error on file \"%s\": ERR=%s\n"),
870 jcr->last_fname, be.bstrerror());
871 Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
872 jcr->acl_data, jcr->last_fname, be.bstrerror());
880 #elif defined(HAVE_SUN_OS)
881 #ifdef HAVE_SYS_ACL_H
884 #error "configure failed to detect availability of sys/acl.h"
887 #if defined(HAVE_EXTENDED_ACL)
889 * We define some internals of the Solaris acl libs here as those
890 * are not exposed yet. Probably because they want us to see the
891 * acls as opague data. But as we need to support different platforms
892 * and versions of Solaris we need to expose some data to be able
893 * to determine the type of acl used to stuff it into the correct
894 * data stream. I know this is far from portable, but maybe the
895 * propper interface is exposed later on and we can get ride of
896 * this kludge. Newer versions of Solaris include sys/acl_impl.h
897 * which has implementation details of acls, if thats included we
898 * don't have to define it ourself.
900 #if !defined(_SYS_ACL_IMPL_H)
901 typedef enum acl_type {
908 * Two external references to functions in the libsec library function not in current include files.
911 int acl_type(acl_t *);
912 char *acl_strerror(int);
916 * As the new libsec interface with acl_totext and acl_fromtext also handles
917 * the old format from acltotext we can use the new functions even
918 * for acls retrieved and stored in the database with older fd versions. If the
919 * new interface is not defined (Solaris 9 and older we fall back to the old code)
921 static bool solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
923 int acl_enabled, flags;
926 bool stream_status = false;
930 * See if filesystem supports acls.
932 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
933 switch (acl_enabled) {
935 pm_strcpy(jcr->acl_data, "");
939 Jmsg2(jcr, M_ERROR, 0, _("pathconf error on file \"%s\": ERR=%s\n"),
940 jcr->last_fname, be.bstrerror());
941 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
942 jcr->last_fname, be.bstrerror());
950 * Get ACL info: don't bother allocating space if there is only a trivial ACL.
952 if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
953 Jmsg2(jcr, M_ERROR, 0, _("acl_get error on file \"%s\": ERR=%s\n"),
954 jcr->last_fname, acl_strerror(errno));
955 Dmsg2(100, "acl_get error file=%s ERR=%s\n",
956 jcr->last_fname, acl_strerror(errno));
963 * The ACLs simply reflect the (already known) standard permissions
964 * So we don't send an ACL stream to the SD.
966 pm_strcpy(jcr->acl_data, "");
970 #if defined(ACL_SID_FMT)
972 * New format flag added in newer Solaris versions.
974 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
976 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
977 #endif /* ACL_SID_FMT */
979 if ((acl_text = acl_totext(aclp, flags)) != NULL) {
980 jcr->acl_data_len = pm_strcpy(jcr->acl_data, acl_text);
981 actuallyfree(acl_text);
983 switch (acl_type(aclp)) {
985 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
988 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE);
997 return stream_status;
1000 static bool solaris_parse_acl_stream(JCR *jcr, int stream)
1003 int acl_enabled, error;
1007 case STREAM_UNIX_ACCESS_ACL:
1008 case STREAM_ACL_SOLARIS_ACLENT:
1009 case STREAM_ACL_SOLARIS_ACE:
1011 * First make sure the filesystem supports acls.
1013 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1014 switch (acl_enabled) {
1016 Jmsg1(jcr, M_ERROR, 0, _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
1021 Jmsg2(jcr, M_ERROR, 0, _("pathconf error on file \"%s\": ERR=%s\n"),
1022 jcr->last_fname, be.bstrerror());
1023 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1024 jcr->acl_data, jcr->last_fname, be.bstrerror());
1029 * On a filesystem with ACL support make sure this particilar ACL type can be restored.
1032 case STREAM_ACL_SOLARIS_ACLENT:
1034 * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
1036 if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
1037 Jmsg1(jcr, M_ERROR, 0, _("Trying to restore acl on file \"%s\" on filesystem without aclent acl support\n"),
1042 case STREAM_ACL_SOLARIS_ACE:
1044 * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
1046 if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
1047 Jmsg1(jcr, M_ERROR, 0, _("Trying to restore acl on file \"%s\" on filesystem without ace acl support\n"),
1054 * Stream id which doesn't describe the type of acl which is encoded.
1061 if ((error = acl_fromtext(jcr->acl_data, &aclp)) != 0) {
1062 Jmsg2(jcr, M_ERROR, 0, _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1063 jcr->last_fname, acl_strerror(error));
1064 Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",
1065 jcr->acl_data, jcr->last_fname, acl_strerror(error));
1070 * Validate that the conversion gave us the correct acl type.
1073 case STREAM_ACL_SOLARIS_ACLENT:
1074 if (acl_type(aclp) != ACLENT_T) {
1075 Jmsg1(jcr, M_ERROR, 0, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1080 case STREAM_ACL_SOLARIS_ACE:
1081 if (acl_type(aclp) != ACE_T) {
1082 Jmsg1(jcr, M_ERROR, 0, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1089 * Stream id which doesn't describe the type of acl which is encoded.
1095 * Restore the ACLs, but don't complain about links which really should
1096 * not have attributes, and the file it is linked to may not yet be restored.
1097 * This is only true for the old acl streams as in the new implementation we
1098 * don't save acls of symlinks (which cannot have acls anyhow)
1100 if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1101 Jmsg2(jcr, M_ERROR, 0, _("acl_set error on file \"%s\": ERR=%s\n"),
1102 jcr->last_fname, acl_strerror(error));
1103 Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",
1104 jcr->acl_data, jcr->last_fname, acl_strerror(error));
1114 } /* end switch (stream) */
1117 #else /* HAVE_EXTENDED_ACL */
1120 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1121 * There is no need to store those acls as we already store the stat bits too.
1123 static bool acl_is_trivial(int count, aclent_t *entries)
1128 for (n = 0; n < count; n++) {
1131 if (!(ace->a_type == USER_OBJ ||
1132 ace->a_type == GROUP_OBJ ||
1133 ace->a_type == OTHER_OBJ ||
1134 ace->a_type == CLASS_OBJ))
1142 * OS specific functions for handling different types of acl streams.
1144 static bool solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt);
1150 n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1151 if (n < MIN_ACL_ENTRIES)
1154 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1155 if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1156 if (acl_is_trivial(n, acls)) {
1158 * The ACLs simply reflect the (already known) standard permissions
1159 * So we don't send an ACL stream to the SD.
1162 pm_strcpy(jcr->acl_data, "");
1166 if ((acl_text = acltotext(acls, n)) != NULL) {
1167 jcr->acl_data_len = pm_strcpy(jcr->acl_data, acl_text);
1168 actuallyfree(acl_text);
1171 return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1175 Jmsg2(jcr, M_ERROR, 0, _("acltotext error on file \"%s\": ERR=%s\n"),
1176 jcr->last_fname, be.bstrerror());
1177 Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",
1178 jcr->acl_data, jcr->last_fname, be.bstrerror());
1185 static bool solaris_parse_acl_stream(JCR *jcr, int stream)
1190 acls = aclfromtext(jcr->acl_data, &n);
1193 Jmsg2(jcr, M_ERROR, 0, _("aclfromtext error on file \"%s\": ERR=%s\n"),
1194 jcr->last_fname, be.bstrerror());
1195 Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",
1196 jcr->acl_data, jcr->last_fname, be.bstrerror());
1202 * Restore the ACLs, but don't complain about links which really should
1203 * not have attributes, and the file it is linked to may not yet be restored.
1205 if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
1207 Jmsg2(jcr, M_ERROR, 0, _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
1208 jcr->last_fname, be.bstrerror());
1209 Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
1210 jcr->acl_data, jcr->last_fname, be.bstrerror());
1220 #endif /* HAVE_EXTENDED_ACL */
1221 #endif /* HAVE_SUN_OS */
1224 * Entry points when compiled with support for ACLs on a supported platform.
1228 * Read and send an ACL for the last encountered file.
1230 bool build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1233 * Call the appropriate function, the ifdefs make sure the proper code is compiled.
1235 #if defined(HAVE_AIX_OS)
1236 return aix_build_acl_streams(jcr, ff_pkt);
1237 #elif defined(HAVE_DARWIN_OS)
1238 return darwin_build_acl_streams(jcr, ff_pkt);
1239 #elif defined(HAVE_FREEBSD_OS)
1240 return freebsd_build_acl_streams(jcr, ff_pkt);
1241 #elif defined(HAVE_HPUX_OS)
1242 return hpux_build_acl_streams(jcr, ff_pkt);
1243 #elif defined(HAVE_IRIX_OS)
1244 return irix_build_acl_streams(jcr, ff_pkt);
1245 #elif defined(HAVE_LINUX_OS)
1246 return linux_build_acl_streams(jcr, ff_pkt);
1247 #elif defined(HAVE_OSF1_OS)
1248 return tru64_build_acl_streams(jcr, ff_pkt);
1249 #elif defined(HAVE_SUN_OS)
1250 return solaris_build_acl_streams(jcr, ff_pkt);
1254 bool parse_acl_stream(JCR *jcr, int stream)
1257 * Based on the stream being passed in dispatch to the right function
1258 * for parsing and restoring a specific acl. The platform determines
1259 * which streams are recognized and parsed and which are handled by
1260 * the default case and ignored. The old STREAM_UNIX_ACCESS_ACL and
1261 * STREAM_UNIX_DEFAULT_ACL is handled as a legacy stream by each function.
1262 * As only one of the platform defines is true per compile we never end
1263 * up with duplicate switch values.
1266 #if defined(HAVE_AIX_OS)
1267 case STREAM_UNIX_ACCESS_ACL:
1268 case STREAM_UNIX_DEFAULT_ACL:
1269 case STREAM_ACL_AIX_TEXT:
1270 return aix_parse_acl_stream(jcr, stream);
1271 #elif defined(HAVE_DARWIN_OS)
1272 case STREAM_UNIX_ACCESS_ACL:
1273 case STREAM_ACL_DARWIN_ACCESS_ACL:
1274 return darwin_parse_acl_stream(jcr, stream);
1275 #elif defined(HAVE_FREEBSD_OS)
1276 case STREAM_UNIX_ACCESS_ACL:
1277 case STREAM_UNIX_DEFAULT_ACL:
1278 case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1279 case STREAM_ACL_FREEBSD_ACCESS_ACL:
1280 return freebsd_parse_acl_stream(jcr, stream);
1281 #elif defined(HAVE_HPUX_OS)
1282 case STREAM_UNIX_ACCESS_ACL:
1283 case STREAM_ACL_HPUX_ACL_ENTRY:
1284 return hpux_parse_acl_stream(jcr, stream);
1285 #elif defined(HAVE_IRIX_OS)
1286 case STREAM_UNIX_ACCESS_ACL:
1287 case STREAM_UNIX_DEFAULT_ACL:
1288 case STREAM_ACL_IRIX_DEFAULT_ACL:
1289 case STREAM_ACL_IRIX_ACCESS_ACL:
1290 return irix_parse_acl_stream(jcr, stream);
1291 #elif defined(HAVE_LINUX_OS)
1292 case STREAM_UNIX_ACCESS_ACL:
1293 case STREAM_UNIX_DEFAULT_ACL:
1294 case STREAM_ACL_LINUX_DEFAULT_ACL:
1295 case STREAM_ACL_LINUX_ACCESS_ACL:
1296 return linux_parse_acl_stream(jcr, stream);
1297 #elif defined(HAVE_OSF1_OS)
1298 case STREAM_UNIX_ACCESS_ACL:
1299 case STREAM_UNIX_DEFAULT_ACL:
1300 case STREAM_ACL_TRU64_DEFAULT_ACL:
1301 case STREAM_ACL_TRU64_ACCESS_ACL:
1302 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
1303 return tru64_parse_acl_stream(jcr, stream);
1304 #elif defined(HAVE_SUN_OS)
1305 case STREAM_UNIX_ACCESS_ACL:
1306 case STREAM_ACL_SOLARIS_ACLENT:
1307 #if defined(HAVE_EXTENDED_ACL)
1308 case STREAM_ACL_SOLARIS_ACE:
1310 return solaris_parse_acl_stream(jcr, stream);
1314 * Issue a warning and discard the message. But pretend the restore was ok.
1316 Qmsg2(jcr, M_WARNING, 0,
1317 _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
1318 jcr->last_fname, stream);
1320 } /* end switch (stream) */