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 (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
109 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
116 * Send the buffer to the storage deamon
118 Dmsg1(400, "Backing up ACL <%s>\n", jcr->acl_data);
120 sd->msg = jcr->acl_data;
121 sd->msglen = jcr->acl_data_len + 1;
125 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
131 jcr->JobBytes += sd->msglen;
133 if (!sd->signal(BNET_EOD)) {
134 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
140 Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
145 #if defined(HAVE_AIX_OS)
147 #include <sys/access.h>
149 static bool aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
153 if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
154 jcr->acl_data_len = pm_strcpy(jcr->acl_data, acl_text);
155 actuallyfree(acl_text);
157 return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT);
163 static bool aix_parse_acl_stream(JCR *jcr, int stream)
165 if (acl_put(jcr->last_fname, jcr->acl_data, 0) != 0) {
172 #elif defined(HAVE_DARWIN_OS) \
173 || defined(HAVE_FREEBSD_OS) \
174 || defined(HAVE_IRIX_OS) \
175 || defined(HAVE_OSF1_OS) \
176 || defined(HAVE_LINUX_OS)
178 #include <sys/types.h>
180 #ifdef HAVE_SYS_ACL_H
183 #error "configure failed to detect availability of sys/acl.h"
186 /* On IRIX we can get shortened ACLs */
187 #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
188 #define acl_to_text(acl,len) acl_to_short_text((acl), (len))
191 /* In Linux we can get numeric and/or shorted ACLs */
192 #if defined(HAVE_LINUX_OS)
193 #if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
194 #define BACL_ALTERNATE_TEXT (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
195 #elif defined(BACL_WANT_SHORT_ACLS)
196 #define BACL_ALTERNATE_TEXT TEXT_ABBREVIATE
197 #elif defined(BACL_WANT_NUMERIC_IDS)
198 #define BACL_ALTERNATE_TEXT TEXT_NUMERIC_IDS
200 #ifdef BACL_ALTERNATE_TEXT
201 #include <acl/libacl.h>
202 #define acl_to_text(acl,len) (acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
207 * Some generic functions used by multiple OSes.
209 static acl_type_t bac_to_os_acltype(bacl_type acltype)
214 case BACL_TYPE_ACCESS:
215 ostype = ACL_TYPE_ACCESS;
217 case BACL_TYPE_DEFAULT:
218 ostype = ACL_TYPE_DEFAULT;
221 #ifdef ACL_TYPE_DEFAULT_DIR
222 case BACL_TYPE_DEFAULT_DIR:
224 * OSF1 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
226 ostype = ACL_TYPE_DEFAULT_DIR;
229 #ifdef ACL_TYPE_EXTENDED
230 case BACL_TYPE_EXTENDED:
232 * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
234 ostype = ACL_TYPE_EXTENDED;
239 * This should never happen, as the per os version function only tries acl
240 * types supported on a certain platform.
242 ostype = (acl_type_t)ACL_TYPE_NONE;
249 #if !defined(HAVE_DARWIN_OS)
251 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
252 * There is no need to store those acls as we already store the stat bits too.
254 static bool acl_is_trivial(acl_t acl)
257 * acl is trivial if it has only the following entries:
264 #if defined(HAVE_FREEBSD_OS) || defined(HAVE_LINUX_OS)
267 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
268 while (entry_available == 1) {
270 * Get the tag type of this acl entry.
271 * If we fail to get the tagtype we call the acl non-trivial.
273 if (acl_get_tag_type(ace, &tag) < 0)
277 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
279 if (tag != ACL_USER_OBJ &&
280 tag != ACL_GROUP_OBJ &&
284 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
288 #elif defined(HAVE_IRIX_OS)
291 for (n = 0; n < acl->acl_cnt; n++) {
292 ace = &acl->acl_entry[n];
296 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
298 if (tag != ACL_USER_OBJ &&
299 tag != ACL_GROUP_OBJ &&
305 #elif defined(HAVE_OSF1_OS)
308 ace = acl->acl_first;
309 count = acl->acl_num;
312 tag = ace->entry->acl_type;
315 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
317 if (tag != ACL_USER_OBJ &&
318 tag != ACL_GROUP_OBJ &&
323 * On Tru64, perm can also contain non-standard bits such as
324 * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
326 if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
339 * Generic wrapper around acl_get_file call.
341 static int generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
348 ostype = bac_to_os_acltype(acltype);
349 acl = acl_get_file(jcr->last_fname, ostype);
351 #if defined(HAVE_IRIX_OS)
353 * From observation, IRIX's acl_get_file() seems to return a
354 * non-NULL acl with a count field of -1 when a file has no ACL
355 * defined, while IRIX's acl_to_text() returns NULL when presented
358 * Checking the count in the acl structure before calling
359 * acl_to_text() lets us avoid error messages about files
360 * with no ACLs, without modifying the flow of the code used for
361 * other operating systems, and it saves making some calls
362 * to acl_to_text() besides.
364 if (acl->acl_cnt <= 0) {
365 pm_strcpy(jcr->acl_data, "");
371 #if !defined(HAVE_DARWIN_OS)
373 * Make sure this is not just a trivial ACL.
375 if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
377 * The ACLs simply reflect the (already known) standard permissions
378 * So we don't send an ACL stream to the SD.
380 pm_strcpy(jcr->acl_data, "");
386 if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
387 len = pm_strcpy(jcr->acl_data, acl_text);
395 Jmsg2(jcr, M_ERROR, 0, _("acl_to_text error on file \"%s\": ERR=%s\n"),
396 jcr->last_fname, be.bstrerror());
397 Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",
398 jcr->last_fname, be.bstrerror());
400 pm_strcpy(jcr->acl_data, "");
407 * Handle errors gracefully.
410 #if defined(BACL_ENOTSUP)
413 * Not supported, just pretend there is nothing to see
415 pm_strcpy(jcr->acl_data, "");
420 Jmsg2(jcr, M_ERROR, 0, _("acl_get_file error on file \"%s\": ERR=%s\n"),
421 jcr->last_fname, be.bstrerror());
422 Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",
423 jcr->last_fname, be.bstrerror());
425 pm_strcpy(jcr->acl_data, "");
431 * Generic wrapper around acl_set_file call.
433 static bool generic_set_acl_on_os(JCR *jcr, bacl_type acltype)
439 * If we get empty default ACLs, clear ACLs now
441 ostype = bac_to_os_acltype(acltype);
442 if (ostype == ACL_TYPE_DEFAULT && strlen(jcr->acl_data) == 0) {
443 if (acl_delete_def_file(jcr->last_fname) == 0) {
447 Jmsg2(jcr, M_ERROR, 0, _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
448 jcr->last_fname, be.bstrerror());
453 acl = acl_from_text(jcr->acl_data);
456 Jmsg2(jcr, M_ERROR, 0, _("acl_from_text error on file \"%s\": ERR=%s\n"),
457 jcr->last_fname, be.bstrerror());
458 Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",
459 jcr->acl_data, jcr->last_fname, be.bstrerror());
465 * FreeBSD always fails acl_valid() - at least on valid input...
466 * As it does the right thing, given valid input, just ignore acl_valid().
468 #ifndef HAVE_FREEBSD_OS
469 if (acl_valid(acl) != 0) {
471 Jmsg2(jcr, M_ERROR, 0, _("ac_valid error on file \"%s\": ERR=%s\n"),
472 jcr->last_fname, be.bstrerror());
473 Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",
474 jcr->acl_data, jcr->last_fname, be.bstrerror());
482 * Restore the ACLs, but don't complain about links which really should
483 * not have attributes, and the file it is linked to may not yet be restored.
484 * This is only true for the old acl streams as in the new implementation we
485 * don't save acls of symlinks (which cannot have acls anyhow)
487 if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
489 Jmsg2(jcr, M_ERROR, 0, _("acl_set_file error on file \"%s\": ERR=%s\n"),
490 jcr->last_fname, be.bstrerror());
491 Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
492 jcr->acl_data, jcr->last_fname, be.bstrerror());
503 * OS specific functions for handling different types of acl streams.
505 #if defined(HAVE_DARWIN_OS)
506 static bool darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
508 #if defined(ACL_TYPE_EXTENDED)
510 * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
511 * and acl_get_file (name, ACL_TYPE_DEFAULT)
512 * always return NULL / EINVAL. There is no point in making
513 * these two useless calls. The real ACL is retrieved through
514 * acl_get_file (name, ACL_TYPE_EXTENDED).
516 * Read access ACLs for files, dirs and links
518 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED)) < 0)
522 * Read access ACLs for files, dirs and links
524 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
527 if (jcr->acl_data_len > 0) {
528 if (!send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL))
536 static bool darwin_parse_acl_stream(JCR *jcr, int stream)
539 case STREAM_UNIX_ACCESS_ACL:
540 case STREAM_ACL_DARWIN_ACCESS_ACL:
541 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
546 #elif defined(HAVE_FREEBSD_OS)
547 static bool freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
550 * Read access ACLs for files, dirs and links
552 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
555 if (jcr->acl_data_len > 0) {
556 if (!send_acl_stream(jcr, STREAM_ACL_FREEBSD_ACCESS_ACL))
561 * Directories can have default ACLs too
563 if (ff_pkt->type == FT_DIREND) {
564 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
567 if (jcr->acl_data_len > 0) {
568 if (!send_acl_stream(jcr, STREAM_ACL_FREEBSD_DEFAULT_ACL))
576 static bool freebsd_parse_acl_stream(JCR *jcr, int stream)
579 case STREAM_UNIX_ACCESS_ACL:
580 case STREAM_ACL_FREEBSD_ACCESS_ACL:
581 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
582 case STREAM_UNIX_DEFAULT_ACL:
583 case STREAM_ACL_FREEBSD_DEFAULT_ACL:
584 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
589 #elif defined(HAVE_IRIX_OS)
590 static bool irix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
593 * Read access ACLs for files, dirs and links
595 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
598 if (jcr->acl_data_len > 0) {
599 if (!send_acl_stream(jcr, STREAM_ACL_IRIX_ACCESS_ACL))
604 * Directories can have default ACLs too
606 if (ff_pkt->type == FT_DIREND) {
607 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
610 if (jcr->acl_data_len > 0) {
611 if (!send_acl_stream(jcr, STREAM_ACL_IRIX_DEFAULT_ACL))
619 static bool irix_parse_acl_stream(JCR *jcr, int stream)
622 case STREAM_UNIX_ACCESS_ACL:
623 case STREAM_ACL_IRIX_ACCESS_ACL:
624 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
625 case STREAM_UNIX_DEFAULT_ACL:
626 case STREAM_ACL_IRIX_DEFAULT_ACL:
627 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
632 #elif defined(HAVE_LINUX_OS)
633 static bool linux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
636 * Read access ACLs for files, dirs and links
638 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
641 if (jcr->acl_data_len > 0) {
642 if (!send_acl_stream(jcr, STREAM_ACL_LINUX_ACCESS_ACL))
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)
653 if (jcr->acl_data_len > 0) {
654 if (!send_acl_stream(jcr, STREAM_ACL_LINUX_DEFAULT_ACL))
662 static bool linux_parse_acl_stream(JCR *jcr, int stream)
665 case STREAM_UNIX_ACCESS_ACL:
666 case STREAM_ACL_LINUX_ACCESS_ACL:
667 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
668 case STREAM_UNIX_DEFAULT_ACL:
669 case STREAM_ACL_LINUX_DEFAULT_ACL:
670 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
675 #elif defined(HAVE_OSF1_OS)
676 static bool tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
679 * Read access ACLs for files, dirs and links
681 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
684 if (jcr->acl_data_len > 0) {
685 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL))
690 * Directories can have default ACLs too
692 if (ff_pkt->type == FT_DIREND) {
693 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
696 if (jcr->acl_data_len > 0) {
697 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL))
702 * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
703 * This is an inherited acl for all subdirs.
704 * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
705 * Section 21.5 Default ACLs
707 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR)) < 0)
710 if (jcr->acl_data_len > 0) {
711 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL))
719 static bool tru64_parse_acl_stream(JCR *jcr, int stream)
722 case STREAM_UNIX_ACCESS_ACL:
723 case STREAM_ACL_TRU64_ACCESS_ACL:
724 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
725 case STREAM_UNIX_DEFAULT_ACL:
726 case STREAM_ACL_TRU64_DEFAULT_ACL:
727 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
728 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
729 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR);
733 #elif defined(HAVE_HPUX_OS)
734 #ifdef HAVE_SYS_ACL_H
737 #error "configure failed to detect availability of sys/acl.h"
743 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
744 * There is no need to store those acls as we already store the stat bits too.
746 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
751 for (n = 0; n < count; n++) {
755 * See if this acl just is the stat mode in acl form.
757 if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
758 (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
759 (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
767 * OS specific functions for handling different types of acl streams.
769 static bool hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
772 struct acl_entry acls[NACLENTRIES];
775 if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
777 #if defined(BACL_ENOTSUP)
780 * Not supported, just pretend there is nothing to see
782 pm_strcpy(jcr->acl_data, "");
787 Jmsg2(jcr, M_ERROR, 0, _("getacl error on file \"%s\": ERR=%s\n"),
788 jcr->last_fname, be.bstrerror());
789 Dmsg2(100, "getacl error file=%s ERR=%s\n",
790 jcr->last_fname, be.bstrerror());
792 pm_strcpy(jcr->acl_data, "");
798 pm_strcpy(jcr->acl_data, "");
802 if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
803 if (acl_is_trivial(n, acls, ff_pkt->statp)) {
805 * The ACLs simply reflect the (already known) standard permissions
806 * So we don't send an ACL stream to the SD.
808 pm_strcpy(jcr->acl_data, "");
812 if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
813 jcr->acl_data_len = pm_strcpy(jcr->acl_data, acl_text);
814 actuallyfree(acl_text);
816 return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
820 Jmsg2(jcr, M_ERROR, 0, _("acltostr error on file \"%s\": ERR=%s\n"),
821 jcr->last_fname, be.bstrerror());
822 Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",
823 jcr->acl_data, jcr->last_fname, be.bstrerror());
831 static bool hpux_parse_acl_stream(JCR *jcr, int stream)
834 struct acl_entry acls[NACLENTRIES];
836 n = strtoacl(jcr->acl_data, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
839 Jmsg2(jcr, M_ERROR, 0, _("strtoacl error on file \"%s\": ERR=%s\n"),
840 jcr->last_fname, be.bstrerror());
841 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
842 jcr->acl_data, jcr->last_fname, be.bstrerror());
846 if (strtoacl(jcr->acl_data, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
848 Jmsg2(jcr, M_ERROR, 0, _("strtoacl error on file \"%s\": ERR=%s\n"),
849 jcr->last_fname, be.bstrerror());
850 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
851 jcr->acl_data, jcr->last_fname, be.bstrerror());
856 * Restore the ACLs, but don't complain about links which really should
857 * not have attributes, and the file it is linked to may not yet be restored.
858 * This is only true for the old acl streams as in the new implementation we
859 * don't save acls of symlinks (which cannot have acls anyhow)
861 if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
863 Jmsg2(jcr, M_ERROR, 0, _("setacl error on file \"%s\": ERR=%s\n"),
864 jcr->last_fname, be.bstrerror());
865 Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
866 jcr->acl_data, jcr->last_fname, be.bstrerror());
874 #elif defined(HAVE_SUN_OS)
875 #ifdef HAVE_SYS_ACL_H
878 #error "configure failed to detect availability of sys/acl.h"
881 #if defined(HAVE_EXTENDED_ACL)
883 * We define some internals of the Solaris acl libs here as those
884 * are not exposed yet. Probably because they want us to see the
885 * acls as opague data. But as we need to support different platforms
886 * and versions of Solaris we need to expose some data to be able
887 * to determine the type of acl used to stuff it into the correct
888 * data stream. I know this is far from portable, but maybe the
889 * propper interface is exposed later on and we can get ride of
890 * this kludge. Newer versions of Solaris include sys/acl_impl.h
891 * which has implementation details of acls, if thats included we
892 * don't have to define it ourself.
894 #if !defined(_SYS_ACL_IMPL_H)
895 typedef enum acl_type {
902 * Two external references to functions in the libsec library function not in current include files.
905 int acl_type(acl_t *);
906 char *acl_strerror(int);
910 * As the new libsec interface with acl_totext and acl_fromtext also handles
911 * the old format from acltotext we can use the new functions even
912 * for acls retrieved and stored in the database with older fd versions. If the
913 * new interface is not defined (Solaris 9 and older we fall back to the old code)
915 static bool solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
917 int acl_enabled, flags;
920 bool stream_status = false;
924 * See if filesystem supports acls.
926 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
927 switch (acl_enabled) {
929 pm_strcpy(jcr->acl_data, "");
933 Jmsg2(jcr, M_ERROR, 0, _("pathconf error on file \"%s\": ERR=%s\n"),
934 jcr->last_fname, be.bstrerror());
935 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
936 jcr->last_fname, be.bstrerror());
944 * Get ACL info: don't bother allocating space if there is only a trivial ACL.
946 if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
947 Jmsg2(jcr, M_ERROR, 0, _("acl_get error on file \"%s\": ERR=%s\n"),
948 jcr->last_fname, acl_strerror(errno));
949 Dmsg2(100, "acl_get error file=%s ERR=%s\n",
950 jcr->last_fname, acl_strerror(errno));
957 * The ACLs simply reflect the (already known) standard permissions
958 * So we don't send an ACL stream to the SD.
960 pm_strcpy(jcr->acl_data, "");
964 #if defined(ACL_SID_FMT)
966 * New format flag added in newer Solaris versions.
968 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
970 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
971 #endif /* ACL_SID_FMT */
973 if ((acl_text = acl_totext(aclp, flags)) != NULL) {
974 jcr->acl_data_len = pm_strcpy(jcr->acl_data, acl_text);
975 actuallyfree(acl_text);
977 switch (acl_type(aclp)) {
979 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
982 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE);
991 return stream_status;
994 static bool solaris_parse_acl_stream(JCR *jcr, int stream)
997 int acl_enabled, error;
1001 case STREAM_UNIX_ACCESS_ACL:
1002 case STREAM_ACL_SOLARIS_ACLENT:
1003 case STREAM_ACL_SOLARIS_ACE:
1005 * First make sure the filesystem supports acls.
1007 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1008 switch (acl_enabled) {
1010 Jmsg1(jcr, M_ERROR, 0, _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
1015 Jmsg2(jcr, M_ERROR, 0, _("pathconf error on file \"%s\": ERR=%s\n"),
1016 jcr->last_fname, be.bstrerror());
1017 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1018 jcr->acl_data, jcr->last_fname, be.bstrerror());
1023 * On a filesystem with ACL support make sure this particilar ACL type can be restored.
1026 case STREAM_ACL_SOLARIS_ACLENT:
1028 * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
1030 if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
1031 Jmsg1(jcr, M_ERROR, 0, _("Trying to restore acl on file \"%s\" on filesystem without aclent acl support\n"),
1036 case STREAM_ACL_SOLARIS_ACE:
1038 * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
1040 if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
1041 Jmsg1(jcr, M_ERROR, 0, _("Trying to restore acl on file \"%s\" on filesystem without ace acl support\n"),
1048 * Stream id which doesn't describe the type of acl which is encoded.
1055 if ((error = acl_fromtext(jcr->acl_data, &aclp)) != 0) {
1056 Jmsg2(jcr, M_ERROR, 0, _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1057 jcr->last_fname, acl_strerror(error));
1058 Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",
1059 jcr->acl_data, jcr->last_fname, acl_strerror(error));
1064 * Validate that the conversion gave us the correct acl type.
1067 case STREAM_ACL_SOLARIS_ACLENT:
1068 if (acl_type(aclp) != ACLENT_T) {
1069 Jmsg1(jcr, M_ERROR, 0, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1074 case STREAM_ACL_SOLARIS_ACE:
1075 if (acl_type(aclp) != ACE_T) {
1076 Jmsg1(jcr, M_ERROR, 0, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1083 * Stream id which doesn't describe the type of acl which is encoded.
1089 * Restore the ACLs, but don't complain about links which really should
1090 * not have attributes, and the file it is linked to may not yet be restored.
1091 * This is only true for the old acl streams as in the new implementation we
1092 * don't save acls of symlinks (which cannot have acls anyhow)
1094 if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1095 Jmsg2(jcr, M_ERROR, 0, _("acl_set error on file \"%s\": ERR=%s\n"),
1096 jcr->last_fname, acl_strerror(error));
1097 Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",
1098 jcr->acl_data, jcr->last_fname, acl_strerror(error));
1108 } /* end switch (stream) */
1111 #else /* HAVE_EXTENDED_ACL */
1114 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1115 * There is no need to store those acls as we already store the stat bits too.
1117 static bool acl_is_trivial(int count, aclent_t *entries)
1122 for (n = 0; n < count; n++) {
1125 if (!(ace->a_type == USER_OBJ ||
1126 ace->a_type == GROUP_OBJ ||
1127 ace->a_type == OTHER_OBJ ||
1128 ace->a_type == CLASS_OBJ))
1136 * OS specific functions for handling different types of acl streams.
1138 static bool solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt);
1144 n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1145 if (n < MIN_ACL_ENTRIES)
1148 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1149 if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1150 if (acl_is_trivial(n, acls)) {
1152 * The ACLs simply reflect the (already known) standard permissions
1153 * So we don't send an ACL stream to the SD.
1156 pm_strcpy(jcr->acl_data, "");
1160 if ((acl_text = acltotext(acls, n)) != NULL) {
1161 jcr->acl_data_len = pm_strcpy(jcr->acl_data, acl_text);
1162 actuallyfree(acl_text);
1165 return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1169 Jmsg2(jcr, M_ERROR, 0, _("acltotext error on file \"%s\": ERR=%s\n"),
1170 jcr->last_fname, be.bstrerror());
1171 Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",
1172 jcr->acl_data, jcr->last_fname, be.bstrerror());
1179 static bool solaris_parse_acl_stream(JCR *jcr, int stream)
1184 acls = aclfromtext(jcr->acl_data, &n);
1187 Jmsg2(jcr, M_ERROR, 0, _("aclfromtext error on file \"%s\": ERR=%s\n"),
1188 jcr->last_fname, be.bstrerror());
1189 Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",
1190 jcr->acl_data, jcr->last_fname, be.bstrerror());
1196 * Restore the ACLs, but don't complain about links which really should
1197 * not have attributes, and the file it is linked to may not yet be restored.
1199 if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
1201 Jmsg2(jcr, M_ERROR, 0, _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
1202 jcr->last_fname, be.bstrerror());
1203 Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
1204 jcr->acl_data, jcr->last_fname, be.bstrerror());
1214 #endif /* HAVE_EXTENDED_ACL */
1215 #endif /* HAVE_SUN_OS */
1218 * Entry points when compiled with support for ACLs on a supported platform.
1222 * Read and send an ACL for the last encountered file.
1224 bool build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1227 * Call the appropriate function, the ifdefs make sure the proper code is compiled.
1229 #if defined(HAVE_AIX_OS)
1230 return aix_build_acl_streams(jcr, ff_pkt);
1231 #elif defined(HAVE_DARWIN_OS)
1232 return darwin_build_acl_streams(jcr, ff_pkt);
1233 #elif defined(HAVE_FREEBSD_OS)
1234 return freebsd_build_acl_streams(jcr, ff_pkt);
1235 #elif defined(HAVE_HPUX_OS)
1236 return hpux_build_acl_streams(jcr, ff_pkt);
1237 #elif defined(HAVE_IRIX_OS)
1238 return irix_build_acl_streams(jcr, ff_pkt);
1239 #elif defined(HAVE_LINUX_OS)
1240 return linux_build_acl_streams(jcr, ff_pkt);
1241 #elif defined(HAVE_OSF1_OS)
1242 return tru64_build_acl_streams(jcr, ff_pkt);
1243 #elif defined(HAVE_SUN_OS)
1244 return solaris_build_acl_streams(jcr, ff_pkt);
1248 bool parse_acl_stream(JCR *jcr, int stream)
1251 * Based on the stream being passed in dispatch to the right function
1252 * for parsing and restoring a specific acl. The platform determines
1253 * which streams are recognized and parsed and which are handled by
1254 * the default case and ignored. The old STREAM_UNIX_ACCESS_ACL and
1255 * STREAM_UNIX_DEFAULT_ACL is handled as a legacy stream by each function.
1256 * As only one of the platform defines is true per compile we never end
1257 * up with duplicate switch values.
1260 #if defined(HAVE_AIX_OS)
1261 case STREAM_UNIX_ACCESS_ACL:
1262 case STREAM_UNIX_DEFAULT_ACL:
1263 case STREAM_ACL_AIX_TEXT:
1264 return aix_parse_acl_stream(jcr, stream);
1265 #elif defined(HAVE_DARWIN_OS)
1266 case STREAM_UNIX_ACCESS_ACL:
1267 case STREAM_ACL_DARWIN_ACCESS_ACL:
1268 return darwin_parse_acl_stream(jcr, stream);
1269 #elif defined(HAVE_FREEBSD_OS)
1270 case STREAM_UNIX_ACCESS_ACL:
1271 case STREAM_UNIX_DEFAULT_ACL:
1272 case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1273 case STREAM_ACL_FREEBSD_ACCESS_ACL:
1274 return freebsd_parse_acl_stream(jcr, stream);
1275 #elif defined(HAVE_HPUX_OS)
1276 case STREAM_UNIX_ACCESS_ACL:
1277 case STREAM_ACL_HPUX_ACL_ENTRY:
1278 return hpux_parse_acl_stream(jcr, stream);
1279 #elif defined(HAVE_IRIX_OS)
1280 case STREAM_UNIX_ACCESS_ACL:
1281 case STREAM_UNIX_DEFAULT_ACL:
1282 case STREAM_ACL_IRIX_DEFAULT_ACL:
1283 case STREAM_ACL_IRIX_ACCESS_ACL:
1284 return irix_parse_acl_stream(jcr, stream);
1285 #elif defined(HAVE_LINUX_OS)
1286 case STREAM_UNIX_ACCESS_ACL:
1287 case STREAM_UNIX_DEFAULT_ACL:
1288 case STREAM_ACL_LINUX_DEFAULT_ACL:
1289 case STREAM_ACL_LINUX_ACCESS_ACL:
1290 return linux_parse_acl_stream(jcr, stream);
1291 #elif defined(HAVE_OSF1_OS)
1292 case STREAM_UNIX_ACCESS_ACL:
1293 case STREAM_UNIX_DEFAULT_ACL:
1294 case STREAM_ACL_TRU64_DEFAULT_ACL:
1295 case STREAM_ACL_TRU64_ACCESS_ACL:
1296 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
1297 return tru64_parse_acl_stream(jcr, stream);
1298 #elif defined(HAVE_SUN_OS)
1299 case STREAM_UNIX_ACCESS_ACL:
1300 case STREAM_ACL_SOLARIS_ACLENT:
1301 #if defined(HAVE_EXTENDED_ACL)
1302 case STREAM_ACL_SOLARIS_ACE:
1304 return solaris_parse_acl_stream(jcr, stream);
1308 * Issue a warning and discard the message. But pretend the restore was ok.
1310 Qmsg2(jcr, M_WARNING, 0,
1311 _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
1312 jcr->last_fname, stream);
1314 } /* end switch (stream) */