2 Bacula® - The Network Backup Solution
4 Copyright (C) 2004-2008 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 OSs.
62 * Not sure if all the HAVE_XYZ_OS are correct for autoconf.
63 * The ones that says man page, are coded according to man pages only.
65 #if !defined(HAVE_ACL) /* ACL support is required, of course */ \
66 || !( defined(HAVE_AIX_OS) /* man page -- may need flags */ \
67 || defined(HAVE_DARWIN_OS) /* tested -- compile without flags */ \
68 || defined(HAVE_FREEBSD_OS) /* tested -- compile without flags */ \
69 || defined(HAVE_HPUX_OS) /* man page -- may need flags */ \
70 || defined(HAVE_IRIX_OS) /* man page -- compile without flags */ \
71 || defined(HAVE_LINUX_OS) /* tested -- compile with -lacl */ \
72 || defined(HAVE_OSF1_OS) /* man page -- may need -lpacl */ \
73 || defined(HAVE_SUN_OS) /* tested -- compile with -lsec */ \
77 * Entry points when compiled without support for ACLs or on an unsupported platform.
79 bool build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
81 Jmsg(jcr, M_FATAL, 0, _("ACL support not configured for your machine.\n"));
85 bool parse_acl_stream(JCR *jcr, int stream)
87 Jmsg(jcr, M_FATAL, 0, _("ACL support not configured for your machine.\n"));
94 * Send an ACL stream to the SD.
96 static bool send_acl_stream(JCR *jcr, int stream, int len)
98 BSOCK *sd = jcr->store_bsock;
100 #ifdef FD_NO_SEND_TEST
107 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
108 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
115 * Send the buffer to the storage deamon
117 Dmsg1(400, "Backing up ACL <%s>\n", jcr->acl_data);
119 sd->msg = jcr->acl_data;
120 sd->msglen = len + 1;
124 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
130 jcr->JobBytes += sd->msglen;
132 if (!sd->signal(BNET_EOD)) {
133 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
139 Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
144 #if defined(HAVE_AIX_OS)
146 #include <sys/access.h>
148 static bool aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
153 if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
154 len = pm_strcpy(jcr->acl_data, acl_text);
155 actuallyfree(acl_text);
157 return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT, len);
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;
250 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
251 * There is no need to store those acls as we already store the stat bits too.
253 #if defined(HAVE_DARWIN_OS)
254 static bool acl_is_trivial(acl_t acl)
257 * acl is trivial if it is empty.
259 return (acl_entries(acl) == 0);
261 #else /* FreeBSD, IRIX, OSF1, Linux */
262 static bool acl_is_trivial(acl_t acl)
265 * acl is trivial if it has only the following entries:
272 #if defined(HAVE_FREEBSD_OS) || defined(HAVE_LINUX_OS)
275 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
276 while (entry_available == 1) {
278 * Get the tag type of this acl entry.
279 * If we fail to get the tagtype we call the acl non-trivial.
281 if (acl_get_tag_type(ace, &tag) < 0)
285 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
287 if (tag != ACL_USER_OBJ &&
288 tag != ACL_GROUP_OBJ &&
292 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
296 #elif defined(HAVE_IRIX_OS)
299 for (n = 0; n < acl->acl_cnt; n++) {
300 ace = &acl->acl_entry[n];
304 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
306 if (tag != ACL_USER_OBJ &&
307 tag != ACL_GROUP_OBJ &&
313 #elif defined(HAVE_OSF1_OS)
316 ace = acl->acl_first;
317 count = acl->acl_num;
320 tag = ace->entry->acl_type;
323 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
325 if (tag != ACL_USER_OBJ &&
326 tag != ACL_GROUP_OBJ &&
331 * On Tru64, perm can also contain non-standard bits such as
332 * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
334 if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
347 * Generic wrapper around acl_get_file call.
349 static int generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
356 ostype = bac_to_os_acltype(acltype);
357 acl = acl_get_file(jcr->last_fname, ostype);
359 #if defined(HAVE_IRIX_OS)
361 * From observation, IRIX's acl_get_file() seems to return a
362 * non-NULL acl with a count field of -1 when a file has no ACL
363 * defined, while IRIX's acl_to_text() returns NULL when presented
366 * Checking the count in the acl structure before calling
367 * acl_to_text() lets us avoid error messages about files
368 * with no ACLs, without modifying the flow of the code used for
369 * other operating systems, and it saves making some calls
370 * to acl_to_text() besides.
372 if (acl->acl_cnt <= 0) {
373 pm_strcpy(jcr->acl_data, "");
380 * Make sure this is not just a trivial ACL.
382 if ((acltype == BACL_TYPE_ACCESS ||
383 acltype == BACL_TYPE_EXTENDED) &&
384 acl_is_trivial(acl)) {
386 * The ACLs simply reflect the (already known) standard permissions
387 * So we don't send an ACL stream to the SD.
389 pm_strcpy(jcr->acl_data, "");
394 if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
395 len = pm_strcpy(jcr->acl_data, acl_text);
403 Jmsg2(jcr, M_ERROR, 0, _("acl_to_text error on file \"%s\": ERR=%s\n"),
404 jcr->last_fname, be.bstrerror());
405 Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",
406 jcr->last_fname, be.bstrerror());
408 pm_strcpy(jcr->acl_data, "");
415 * Handle errors gracefully.
418 #if defined(BACL_ENOTSUP)
421 * Not supported, just pretend there is nothing to see
423 pm_strcpy(jcr->acl_data, "");
428 Jmsg2(jcr, M_ERROR, 0, _("acl_get_file error on file \"%s\": ERR=%s\n"),
429 jcr->last_fname, be.bstrerror());
430 Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",
431 jcr->last_fname, be.bstrerror());
433 pm_strcpy(jcr->acl_data, "");
439 * Generic wrapper around acl_set_file call.
441 static bool generic_set_acl_on_os(JCR *jcr, bacl_type acltype)
447 * If we get empty default ACLs, clear ACLs now
449 ostype = bac_to_os_acltype(acltype);
450 if (ostype == ACL_TYPE_DEFAULT && strlen(jcr->acl_data) == 0) {
451 if (acl_delete_def_file(jcr->last_fname) == 0) {
455 Jmsg2(jcr, M_ERROR, 0, _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
456 jcr->last_fname, be.bstrerror());
461 acl = acl_from_text(jcr->acl_data);
464 Jmsg2(jcr, M_ERROR, 0, _("acl_from_text error on file \"%s\": ERR=%s\n"),
465 jcr->last_fname, be.bstrerror());
466 Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",
467 jcr->acl_data, jcr->last_fname, be.bstrerror());
473 * FreeBSD always fails acl_valid() - at least on valid input...
474 * As it does the right thing, given valid input, just ignore acl_valid().
476 #ifndef HAVE_FREEBSD_OS
477 if (acl_valid(acl) != 0) {
479 Jmsg2(jcr, M_ERROR, 0, _("ac_valid error on file \"%s\": ERR=%s\n"),
480 jcr->last_fname, be.bstrerror());
481 Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",
482 jcr->acl_data, jcr->last_fname, be.bstrerror());
490 * Restore the ACLs, but don't complain about links which really should
491 * not have attributes, and the file it is linked to may not yet be restored.
492 * This is only true for the old acl streams as in the new implementation we
493 * don't save acls of symlinks (which cannot have acls anyhow)
495 if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
497 Jmsg2(jcr, M_ERROR, 0, _("acl_set_file error on file \"%s\": ERR=%s\n"),
498 jcr->last_fname, be.bstrerror());
499 Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
500 jcr->acl_data, jcr->last_fname, be.bstrerror());
511 * OS specific functions for handling different types of acl streams.
513 #if defined(HAVE_DARWIN_OS)
514 static bool darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
518 #if defined(ACL_TYPE_EXTENDED)
520 * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
521 * and acl_get_file (name, ACL_TYPE_DEFAULT)
522 * always return NULL / EINVAL. There is no point in making
523 * these two useless calls. The real ACL is retrieved through
524 * acl_get_file (name, ACL_TYPE_EXTENDED).
526 * Read access ACLs for files, dirs and links
528 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED)) < 0)
532 * Read access ACLs for files, dirs and links
534 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
539 if (!send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL_T, len))
546 static bool darwin_parse_acl_stream(JCR *jcr, int stream)
549 case STREAM_UNIX_ACCESS_ACL:
550 case STREAM_ACL_DARWIN_ACCESS_ACL_T:
551 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
556 #elif defined(HAVE_FREEBSD_OS)
557 static bool freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
562 * Read access ACLs for files, dirs and links
564 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
568 if (!send_acl_stream(jcr, STREAM_ACL_FREEBSD_ACCESS_ACL_T, len))
573 * Directories can have default ACLs too
575 if (ff_pkt->type == FT_DIREND) {
576 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
580 if (!send_acl_stream(jcr, STREAM_ACL_FREEBSD_DEFAULT_ACL_T, len))
588 static bool freebsd_parse_acl_stream(JCR *jcr, int stream)
591 case STREAM_UNIX_ACCESS_ACL:
592 case STREAM_ACL_FREEBSD_ACCESS_ACL_T:
593 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
594 case STREAM_UNIX_DEFAULT_ACL:
595 case STREAM_ACL_FREEBSD_DEFAULT_ACL_T:
596 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
601 #elif defined(HAVE_IRIX_OS)
602 static bool irix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
607 * Read access ACLs for files, dirs and links
609 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
613 if (!send_acl_stream(jcr, STREAM_ACL_IRIX_ACCESS_ACL_T, len))
618 * Directories can have default ACLs too
620 if (ff_pkt->type == FT_DIREND) {
621 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
625 if (!send_acl_stream(jcr, STREAM_ACL_IRIX_DEFAULT_ACL_T, len))
633 static bool irix_parse_acl_stream(JCR *jcr, int stream)
636 case STREAM_UNIX_ACCESS_ACL:
637 case STREAM_ACL_IRIX_ACCESS_ACL_T:
638 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
639 case STREAM_UNIX_DEFAULT_ACL:
640 case STREAM_ACL_IRIX_DEFAULT_ACL_T:
641 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
646 #elif defined(HAVE_LINUX_OS)
647 static bool linux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
652 * Read access ACLs for files, dirs and links
654 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
658 if (!send_acl_stream(jcr, STREAM_ACL_LINUX_ACCESS_ACL_T, len))
663 * Directories can have default ACLs too
665 if (ff_pkt->type == FT_DIREND) {
666 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
670 if (!send_acl_stream(jcr, STREAM_ACL_LINUX_DEFAULT_ACL_T, len))
678 static bool linux_parse_acl_stream(JCR *jcr, int stream)
681 case STREAM_UNIX_ACCESS_ACL:
682 case STREAM_ACL_LINUX_ACCESS_ACL_T:
683 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
684 case STREAM_UNIX_DEFAULT_ACL:
685 case STREAM_ACL_LINUX_DEFAULT_ACL_T:
686 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
691 #elif defined(HAVE_OSF1_OS)
692 static bool tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
697 * Read access ACLs for files, dirs and links
699 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
703 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL_T, len))
708 * Directories can have default ACLs too
710 if (ff_pkt->type == FT_DIREND) {
711 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
715 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL_T, len))
720 * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
721 * This is an inherited acl for all subdirs.
722 * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
723 * Section 21.5 Default ACLs
725 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR)) < 0)
729 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL_T, len))
737 static bool tru64_parse_acl_stream(JCR *jcr, int stream)
740 case STREAM_UNIX_ACCESS_ACL:
741 case STREAM_ACL_TRU64_ACCESS_ACL_T:
742 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
743 case STREAM_UNIX_DEFAULT_ACL:
744 case STREAM_ACL_TRU64_DEFAULT_ACL_T:
745 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
746 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL_T:
747 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR);
751 #elif defined(HAVE_HPUX_OS)
752 #ifdef HAVE_SYS_ACL_H
755 #error "configure failed to detect availability of sys/acl.h"
761 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
762 * There is no need to store those acls as we already store the stat bits too.
764 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
769 for (n = 0; n < count; n++) {
773 * See if this acl just is the stat mode in acl form.
775 if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
776 (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
777 (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
785 * OS specific functions for handling different types of acl streams.
787 static bool hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
790 struct acl_entry acls[NACLENTRIES];
793 if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
795 #if defined(BACL_ENOTSUP)
798 * Not supported, just pretend there is nothing to see
800 pm_strcpy(jcr->acl_data, "");
805 Jmsg2(jcr, M_ERROR, 0, _("getacl error on file \"%s\": ERR=%s\n"),
806 jcr->last_fname, be.bstrerror());
807 Dmsg2(100, "getacl error file=%s ERR=%s\n",
808 jcr->last_fname, be.bstrerror());
810 pm_strcpy(jcr->acl_data, "");
816 pm_strcpy(jcr->acl_data, "");
820 if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
821 if (acl_is_trivial(n, acls, ff_pkt->statp)) {
823 * The ACLs simply reflect the (already known) standard permissions
824 * So we don't send an ACL stream to the SD.
826 pm_strcpy(jcr->acl_data, "");
830 if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
831 len = pm_strcpy(jcr->acl_data, acl_text);
832 actuallyfree(acl_text);
834 return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY, len);
838 Jmsg2(jcr, M_ERROR, 0, _("acltostr error on file \"%s\": ERR=%s\n"),
839 jcr->last_fname, be.bstrerror());
840 Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",
841 jcr->acl_data, jcr->last_fname, be.bstrerror());
849 static bool hpux_parse_acl_stream(JCR *jcr, int stream)
852 struct acl_entry acls[NACLENTRIES];
854 n = strtoacl(jcr->acl_data, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
857 Jmsg2(jcr, M_ERROR, 0, _("strtoacl error on file \"%s\": ERR=%s\n"),
858 jcr->last_fname, be.bstrerror());
859 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
860 jcr->acl_data, jcr->last_fname, be.bstrerror());
864 if (strtoacl(jcr->acl_data, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
866 Jmsg2(jcr, M_ERROR, 0, _("strtoacl error on file \"%s\": ERR=%s\n"),
867 jcr->last_fname, be.bstrerror());
868 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
869 jcr->acl_data, jcr->last_fname, be.bstrerror());
874 * Restore the ACLs, but don't complain about links which really should
875 * not have attributes, and the file it is linked to may not yet be restored.
876 * This is only true for the old acl streams as in the new implementation we
877 * don't save acls of symlinks (which cannot have acls anyhow)
879 if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
881 Jmsg2(jcr, M_ERROR, 0, _("setacl error on file \"%s\": ERR=%s\n"),
882 jcr->last_fname, be.bstrerror());
883 Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
884 jcr->acl_data, jcr->last_fname, be.bstrerror());
892 #elif defined(HAVE_SUN_OS)
893 #ifdef HAVE_SYS_ACL_H
896 #error "configure failed to detect availability of sys/acl.h"
899 #if defined(HAVE_EXTENDED_ACL)
901 * We define some internals of the Solaris acl libs here as those
902 * are not exposed yet. Probably because they want us to see the
903 * acls as opague data. But as we need to support different platforms
904 * and versions of Solaris we need to expose some data to be able
905 * to determine the type of acl used to stuff it into the correct
906 * data stream. I know this is far from portable, but maybe the
907 * propper interface is exposed later on and we can get ride of
908 * this kludge. Newer versions of Solaris include sys/acl_impl.h
909 * which has implementation details of acls, if thats included we
910 * don't have to define it ourself.
912 #if !defined(_SYS_ACL_IMPL_H)
913 typedef enum acl_type {
920 * Two external references to functions in the libsec library function not in current include files.
923 int acl_type(acl_t *);
924 char *acl_strerror(int);
928 * As the new libsec interface with acl_totext and acl_fromtext also handles
929 * the old format from acltotext we can use the new functions even
930 * for acls retrieved and stored in the database with older fd versions. If the
931 * new interface is not defined (Solaris 9 and older we fall back to the old code)
933 static bool solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
938 bool stream_status = false;
941 * Get ACL info: don't bother allocating space if there is only a trivial ACL.
943 if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
945 #if defined(BACL_ENOTSUP)
948 * Not supported, just pretend there is nothing to see
950 pm_strcpy(jcr->acl_data, "");
954 Jmsg2(jcr, M_ERROR, 0, _("acl_get error on file \"%s\": ERR=%s\n"),
955 jcr->last_fname, acl_strerror(errno));
956 Dmsg2(100, "acl_get error file=%s ERR=%s\n",
957 jcr->last_fname, acl_strerror(errno));
965 * The ACLs simply reflect the (already known) standard permissions
966 * So we don't send an ACL stream to the SD.
968 pm_strcpy(jcr->acl_data, "");
972 #if defined(ACL_SID_FMT)
974 * New format flag added in newer Solaris versions.
976 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
978 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
979 #endif /* ACL_SID_FMT */
981 if ((acl_text = acl_totext(aclp, flags)) != NULL) {
982 len = pm_strcpy(jcr->acl_data, acl_text);
983 actuallyfree(acl_text);
985 switch (acl_type(aclp)) {
987 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT_T, len);
990 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE_T, len);
999 return stream_status;
1002 static bool solaris_parse_acl_stream(JCR *jcr, int stream)
1008 case STREAM_UNIX_ACCESS_ACL:
1009 case STREAM_ACL_SOLARIS_ACLENT_T:
1010 case STREAM_ACL_SOLARIS_ACE_T:
1011 if ((error = acl_fromtext(jcr->acl_data, &aclp)) != 0) {
1012 Jmsg2(jcr, M_ERROR, 0, _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1013 jcr->last_fname, acl_strerror(error));
1014 Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",
1015 jcr->acl_data, jcr->last_fname, acl_strerror(error));
1020 * Validate that the conversion gave us the correct acl type.
1023 case STREAM_ACL_SOLARIS_ACLENT_T:
1024 if (acl_type(aclp) != ACLENT_T) {
1025 Jmsg1(jcr, M_ERROR, 0, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1029 case STREAM_ACL_SOLARIS_ACE_T:
1030 if (acl_type(aclp) != ACE_T) {
1031 Jmsg1(jcr, M_ERROR, 0, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1037 * Stream id which doesn't describe the type of acl which is encoded.
1043 * Restore the ACLs, but don't complain about links which really should
1044 * not have attributes, and the file it is linked to may not yet be restored.
1045 * This is only true for the old acl streams as in the new implementation we
1046 * don't save acls of symlinks (which cannot have acls anyhow)
1048 if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1049 Jmsg2(jcr, M_ERROR, 0, _("acl_set error on file \"%s\": ERR=%s\n"),
1050 jcr->last_fname, acl_strerror(error));
1051 Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",
1052 jcr->acl_data, jcr->last_fname, acl_strerror(error));
1062 } /* end switch (stream) */
1065 #else /* HAVE_EXTENDED_ACL */
1068 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1069 * There is no need to store those acls as we already store the stat bits too.
1071 static bool acl_is_trivial(int count, aclent_t *entries)
1076 for (n = 0; n < count; n++) {
1079 if (!(ace->a_type == USER_OBJ ||
1080 ace->a_type == GROUP_OBJ ||
1081 ace->a_type == OTHER_OBJ ||
1082 ace->a_type == CLASS_OBJ))
1090 * OS specific functions for handling different types of acl streams.
1092 static bool solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt);
1098 n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1099 if (n < MIN_ACL_ENTRIES) {
1102 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1103 if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1104 if (acl_is_trivial(n, acls)) {
1106 * The ACLs simply reflect the (already known) standard permissions
1107 * So we don't send an ACL stream to the SD.
1110 pm_strcpy(jcr->acl_data, "");
1114 if ((acl_text = acltotext(acls, n)) != NULL) {
1115 len = pm_strcpy(jcr->acl_data, acl_text);
1116 actuallyfree(acl_text);
1119 return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT_T, len);
1123 Jmsg2(jcr, M_ERROR, 0, _("acltotext error on file \"%s\": ERR=%s\n"),
1124 jcr->last_fname, be.bstrerror());
1125 Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",
1126 jcr->acl_data, jcr->last_fname, be.bstrerror());
1133 static bool solaris_parse_acl_stream(JCR *jcr, int stream)
1138 acls = aclfromtext(jcr->acl_data, &n);
1141 Jmsg2(jcr, M_ERROR, 0, _("aclfromtext error on file \"%s\": ERR=%s\n"),
1142 jcr->last_fname, be.bstrerror());
1143 Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",
1144 jcr->acl_data, jcr->last_fname, be.bstrerror());
1150 * Restore the ACLs, but don't complain about links which really should
1151 * not have attributes, and the file it is linked to may not yet be restored.
1153 if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
1155 Jmsg2(jcr, M_ERROR, 0, _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
1156 jcr->last_fname, be.bstrerror());
1157 Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
1158 jcr->acl_data, jcr->last_fname, be.bstrerror());
1168 #endif /* HAVE_EXTENDED_ACL */
1169 #endif /* HAVE_SUN_OS */
1172 * Entry points when compiled with support for ACLs on a supported platform.
1176 * Read and send an ACL for the last encountered file.
1178 bool build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1181 * Call the appropriate function, the ifdefs make sure the proper code is compiled.
1183 #if defined(HAVE_AIX_OS)
1184 return aix_build_acl_streams(jcr, ff_pkt);
1185 #elif defined(HAVE_DARWIN_OS)
1186 return darwin_build_acl_streams(jcr, ff_pkt);
1187 #elif defined(HAVE_FREEBSD_OS)
1188 return freebsd_build_acl_streams(jcr, ff_pkt);
1189 #elif defined(HAVE_HPUX_OS)
1190 return hpux_build_acl_streams(jcr, ff_pkt);
1191 #elif defined(HAVE_IRIX_OS)
1192 return irix_build_acl_streams(jcr, ff_pkt);
1193 #elif defined(HAVE_LINUX_OS)
1194 return linux_build_acl_streams(jcr, ff_pkt);
1195 #elif defined(HAVE_OSF1_OS)
1196 return tru64_build_acl_streams(jcr, ff_pkt);
1197 #elif defined(HAVE_SUN_OS)
1198 return solaris_build_acl_streams(jcr, ff_pkt);
1202 bool parse_acl_stream(JCR *jcr, int stream)
1205 * Based on the stream being passed in dispatch to the right function
1206 * for parsing and restoring a specific acl. The platform determines
1207 * which streams are recognized and parsed and which are handled by
1208 * the default case and ignored. The old STREAM_UNIX_ACCESS_ACL and
1209 * STREAM_UNIX_DEFAULT_ACL is handled as a legacy stream by each function.
1210 * As only one of the platform defines is true per compile we never end
1211 * up with duplicate switch values.
1214 #if defined(HAVE_AIX_OS)
1215 case STREAM_UNIX_ACCESS_ACL:
1216 case STREAM_UNIX_DEFAULT_ACL:
1217 case STREAM_ACL_AIX_TEXT:
1218 return aix_parse_acl_stream(jcr, stream);
1219 #elif defined(HAVE_DARWIN_OS)
1220 case STREAM_UNIX_ACCESS_ACL:
1221 case STREAM_ACL_DARWIN_ACCESS_ACL_T:
1222 return darwin_parse_acl_stream(jcr, stream);
1223 #elif defined(HAVE_FREEBSD_OS)
1224 case STREAM_UNIX_ACCESS_ACL:
1225 case STREAM_UNIX_DEFAULT_ACL:
1226 case STREAM_ACL_FREEBSD_DEFAULT_ACL_T:
1227 case STREAM_ACL_FREEBSD_ACCESS_ACL_T:
1228 return freebsd_parse_acl_stream(jcr, stream);
1229 #elif defined(HAVE_HPUX_OS)
1230 case STREAM_UNIX_ACCESS_ACL:
1231 case STREAM_ACL_HPUX_ACL_ENTRY:
1232 return hpux_parse_acl_stream(jcr, stream);
1233 #elif defined(HAVE_IRIX_OS)
1234 case STREAM_UNIX_ACCESS_ACL:
1235 case STREAM_UNIX_DEFAULT_ACL:
1236 case STREAM_ACL_IRIX_DEFAULT_ACL_T:
1237 case STREAM_ACL_IRIX_ACCESS_ACL_T:
1238 return irix_parse_acl_stream(jcr, stream);
1239 #elif defined(HAVE_LINUX_OS)
1240 case STREAM_UNIX_ACCESS_ACL:
1241 case STREAM_UNIX_DEFAULT_ACL:
1242 case STREAM_ACL_LINUX_DEFAULT_ACL_T:
1243 case STREAM_ACL_LINUX_ACCESS_ACL_T:
1244 return linux_parse_acl_stream(jcr, stream);
1245 #elif defined(HAVE_OSF1_OS)
1246 case STREAM_UNIX_ACCESS_ACL:
1247 case STREAM_UNIX_DEFAULT_ACL:
1248 case STREAM_ACL_TRU64_DEFAULT_ACL_T:
1249 case STREAM_ACL_TRU64_ACCESS_ACL_T:
1250 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL_T:
1251 return tru64_parse_acl_stream(jcr, stream);
1252 #elif defined(HAVE_SUN_OS)
1253 case STREAM_UNIX_ACCESS_ACL:
1254 case STREAM_ACL_SOLARIS_ACLENT_T:
1255 #if defined(HAVE_EXTENDED_ACL)
1256 case STREAM_ACL_SOLARIS_ACE_T:
1258 return solaris_parse_acl_stream(jcr, stream);
1262 * Issue a warning and discard the message. But pretend the restore was ok.
1264 Qmsg2(jcr, M_WARNING, 0,
1265 _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
1266 jcr->last_fname, stream);
1268 } /* end switch (stream) */