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 ACL for bacula.
31 * We handle two different typers of ACLs: access and default ACLS.
32 * Default ACLs 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 * As for the streams to use, we have two choices:
39 * 1. Build a generic framework.
40 * With two different types of ACLs, supported differently, we
41 * probably end up encoding and decoding everything ourselves.
43 * 2. Take the easy way out.
44 * Just handle each platform individually, assuming that backups
45 * and restores are done on the same (kind of) client.
47 * Currently we take the easy way out. We use two kinds of streams, one
48 * for access ACLs and one for default ACLs. If an OS mixes the two, we
49 * send the mix in the access ACL stream.
51 * Looking at more man pages, supporting a framework seems really hard
52 * if we want to support HP-UX. Deity knows what AIX is up to.
54 * Written by Preben 'Peppe' Guldberg, December MMIV
68 * List of supported OSs.
69 * Not sure if all the HAVE_XYZ_OS are correct for autoconf.
70 * The ones that says man page, are coded according to man pages only.
72 #if !defined(HAVE_ACL) /* ACL support is required, of course */ \
73 || !( defined(HAVE_AIX_OS) /* man page -- may need flags */ \
74 || defined(HAVE_DARWIN_OS) /* tested -- compile without flags */ \
75 || defined(HAVE_FREEBSD_OS) /* tested -- compile without flags */ \
76 || defined(HAVE_HPUX_OS) /* man page -- may need flags */ \
77 || defined(HAVE_IRIX_OS) /* man page -- compile without flags */ \
78 || defined(HAVE_LINUX_OS) /* tested -- compile with -lacl */ \
79 || defined(HAVE_OSF1_OS) /* man page -- may need -lpacl */ \
80 || defined(HAVE_SUN_OS) /* tested -- compile with -lsec */ \
84 * Entry points when compiled without support for ACLs or on an unsupported platform.
86 bool build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
88 Jmsg(jcr, M_FATAL, 0, _("ACL support not configured for your machine.\n"));
92 bool parse_acl_stream(JCR *jcr, int stream)
94 Jmsg(jcr, M_FATAL, 0, _("ACL support not configured for your machine.\n"));
101 * Send an ACL stream to the SD.
103 static bool send_acl_stream(JCR *jcr, int stream, int len)
105 BSOCK *sd = jcr->store_bsock;
107 #ifdef FD_NO_SEND_TEST
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 = 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)
160 if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
161 len = pm_strcpy(jcr->acl_data, acl_text);
162 actuallyfree(acl_text);
164 return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT, len);
170 static bool aix_parse_acl_stream(JCR *jcr, int stream)
172 if (acl_put(jcr->last_fname, jcr->acl_data, 0) != 0) {
179 #elif defined(HAVE_DARWIN_OS) \
180 || defined(HAVE_FREEBSD_OS) \
181 || defined(HAVE_IRIX_OS) \
182 || defined(HAVE_OSF1_OS) \
183 || defined(HAVE_LINUX_OS)
185 #include <sys/types.h>
187 #ifdef HAVE_SYS_ACL_H
190 #error "configure failed to detect availability of sys/acl.h"
193 /* On IRIX we can get shortened ACLs */
194 #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
195 #define acl_to_text(acl,len) acl_to_short_text((acl), (len))
198 /* In Linux we can get numeric and/or shorted ACLs */
199 #if defined(HAVE_LINUX_OS)
200 #if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
201 #define BACL_ALTERNATE_TEXT (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
202 #elif defined(BACL_WANT_SHORT_ACLS)
203 #define BACL_ALTERNATE_TEXT TEXT_ABBREVIATE
204 #elif defined(BACL_WANT_NUMERIC_IDS)
205 #define BACL_ALTERNATE_TEXT TEXT_NUMERIC_IDS
207 #ifdef BACL_ALTERNATE_TEXT
208 #include <acl/libacl.h>
209 #define acl_to_text(acl,len) (acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
214 * Some generic functions used by multiple OSes.
216 static acl_type_t bac_to_os_acltype(bacl_type acltype)
221 case BACL_TYPE_ACCESS:
222 ostype = ACL_TYPE_ACCESS;
224 case BACL_TYPE_DEFAULT:
225 ostype = ACL_TYPE_DEFAULT;
228 #ifdef ACL_TYPE_DEFAULT_DIR
229 case BACL_TYPE_DEFAULT_DIR:
231 * OSF1 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
233 ostype = ACL_TYPE_DEFAULT_DIR;
236 #ifdef ACL_TYPE_EXTENDED
237 case BACL_TYPE_EXTENDED:
239 * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
241 ostype = ACL_TYPE_EXTENDED;
246 * This should never happen, as the per os version function only tries acl
247 * types supported on a certain platform.
249 ostype = ACL_TYPE_NONE;
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 #if defined(HAVE_DARWIN_OS)
261 static bool acl_is_trivial(acl_t acl)
264 * acl is trivial if it is empty.
266 return (acl_entries(acl) == 0);
268 #else /* FreeBSD, IRIX, OSF1, Linux */
269 static bool acl_is_trivial(acl_t acl)
272 * acl is trivial if it has only the following entries:
279 #if defined(HAVE_FREEBSD_OS) || defined(HAVE_LINUX_OS)
282 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
283 while (entry_available == 1) {
285 * Get the tag type of this acl entry.
286 * If we fail to get the tagtype we call the acl non-trivial.
288 if (acl_get_tag_type(ace, &tag) < 0)
292 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
294 if (tag != ACL_USER_OBJ &&
295 tag != ACL_GROUP_OBJ &&
299 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
303 #elif defined(HAVE_IRIX_OS)
306 for (n = 0; n < acl->acl_cnt; n++) {
307 ace = &acl->acl_entry[n];
311 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
313 if (tag != ACL_USER_OBJ &&
314 tag != ACL_GROUP_OBJ &&
320 #elif defined(HAVE_OSF1_OS)
323 ace = acl->acl_first;
324 count = acl->acl_num;
327 tag = ace->entry->acl_type;
330 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
332 if (tag != ACL_USER_OBJ &&
333 tag != ACL_GROUP_OBJ &&
338 * On Tru64, perm can also contain non-standard bits such as
339 * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
341 if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
354 * Generic wrapper around acl_get_file call.
356 static int generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
363 ostype = bac_to_os_acltype(acltype);
364 acl = acl_get_file(jcr->last_fname, ostype);
366 #if defined(HAVE_IRIX_OS)
368 * From observation, IRIX's acl_get_file() seems to return a
369 * non-NULL acl with a count field of -1 when a file has no ACL
370 * defined, while IRIX's acl_to_text() returns NULL when presented
373 * Checking the count in the acl structure before calling
374 * acl_to_text() lets us avoid error messages about files
375 * with no ACLs, without modifying the flow of the code used for
376 * other operating systems, and it saves making some calls
377 * to acl_to_text() besides.
379 if (acl->acl_cnt <= 0) {
380 pm_strcpy(jcr->acl_data, "");
387 * Make sure this is not just a trivial ACL.
389 if ((acltype == BACL_TYPE_ACCESS ||
390 acltype == BACL_TYPE_EXTENDED) &&
391 acl_is_trivial(acl)) {
393 * The ACLs simply reflect the (already known) standard permissions
394 * So we don't send an ACL stream to the SD.
396 pm_strcpy(jcr->acl_data, "");
401 if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
402 len = pm_strcpy(jcr->acl_data, acl_text);
410 Jmsg2(jcr, M_ERROR, 0, _("acl_to_text error on file \"%s\": ERR=%s\n"),
411 jcr->last_fname, be.bstrerror());
412 Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",
413 jcr->last_fname, be.bstrerror());
415 pm_strcpy(jcr->acl_data, "");
422 * Handle errors gracefully.
425 #if defined(BACL_ENOTSUP)
428 * Not supported, just pretend there is nothing to see
430 pm_strcpy(jcr->acl_data, "");
435 Jmsg2(jcr, M_ERROR, 0, _("acl_get_file error on file \"%s\": ERR=%s\n"),
436 jcr->last_fname, be.bstrerror());
437 Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",
438 jcr->last_fname, be.bstrerror());
440 pm_strcpy(jcr->acl_data, "");
446 * Generic wrapper around acl_set_file call.
448 static bool generic_set_acl_on_os(JCR *jcr, bacl_type acltype)
454 * If we get empty default ACLs, clear ACLs now
456 ostype = bac_to_os_acltype(acltype);
457 if (ostype == ACL_TYPE_DEFAULT && strlen(jcr->acl_data) == 0) {
458 if (acl_delete_def_file(jcr->last_fname) == 0) {
462 Jmsg2(jcr, M_ERROR, 0, _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
463 jcr->last_fname, be.bstrerror());
468 acl = acl_from_text(jcr->acl_data);
471 Jmsg2(jcr, M_ERROR, 0, _("acl_from_text error on file \"%s\": ERR=%s\n"),
472 jcr->last_fname, be.bstrerror());
473 Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",
474 jcr->acl_data, jcr->last_fname, be.bstrerror());
480 * FreeBSD always fails acl_valid() - at least on valid input...
481 * As it does the right thing, given valid input, just ignore acl_valid().
483 #ifndef HAVE_FREEBSD_OS
484 if (acl_valid(acl) != 0) {
486 Jmsg2(jcr, M_ERROR, 0, _("ac_valid error on file \"%s\": ERR=%s\n"),
487 jcr->last_fname, be.bstrerror());
488 Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",
489 jcr->acl_data, jcr->last_fname, be.bstrerror());
497 * Restore the ACLs, but don't complain about links which really should
498 * not have attributes, and the file it is linked to may not yet be restored.
499 * This is only true for the old acl streams as in the new implementation we
500 * don't save acls of symlinks (which cannot have acls anyhow)
502 if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
504 Jmsg2(jcr, M_ERROR, 0, _("acl_set_file error on file \"%s\": ERR=%s\n"),
505 jcr->last_fname, be.bstrerror());
506 Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
507 jcr->acl_data, jcr->last_fname, be.bstrerror());
518 * OS specific functions for handling different types of acl streams.
520 #if defined(HAVE_DARWIN_OS)
521 static bool darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
525 #if defined(ACL_TYPE_EXTENDED)
527 * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
528 * and acl_get_file (name, ACL_TYPE_DEFAULT)
529 * always return NULL / EINVAL. There is no point in making
530 * these two useless calls. The real ACL is retrieved through
531 * acl_get_file (name, ACL_TYPE_EXTENDED).
533 * Read access ACLs for files, dirs and links
535 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED)) < 0)
539 * Read access ACLs for files, dirs and links
541 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
546 if (!send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL_T, len))
553 static bool darwin_parse_acl_stream(JCR *jcr, int stream)
556 case STREAM_UNIX_ACCESS_ACL:
557 case STREAM_ACL_DARWIN_ACCESS_ACL_T:
558 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
563 #elif defined(HAVE_FREEBSD_OS)
564 static bool freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
569 * Read access ACLs for files, dirs and links
571 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
575 if (!send_acl_stream(jcr, STREAM_ACL_FREEBSD_ACCESS_ACL_T, len))
580 * Directories can have default ACLs too
582 if (ff_pkt->type == FT_DIREND) {
583 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
587 if (!send_acl_stream(jcr, STREAM_ACL_FREEBSD_DEFAULT_ACL_T, len))
595 static bool freebsd_parse_acl_stream(JCR *jcr, int stream)
598 case STREAM_UNIX_ACCESS_ACL:
599 case STREAM_ACL_FREEBSD_ACCESS_ACL_T:
600 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
601 case STREAM_UNIX_DEFAULT_ACL:
602 case STREAM_ACL_FREEBSD_DEFAULT_ACL_T:
603 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
608 #elif defined(HAVE_IRIX_OS)
609 static bool irix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
614 * Read access ACLs for files, dirs and links
616 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
620 if (!send_acl_stream(jcr, STREAM_ACL_IRIX_ACCESS_ACL_T, len))
625 * Directories can have default ACLs too
627 if (ff_pkt->type == FT_DIREND) {
628 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
632 if (!send_acl_stream(jcr, STREAM_ACL_IRIX_DEFAULT_ACL_T, len))
640 static bool irix_parse_acl_stream(JCR *jcr, int stream)
643 case STREAM_UNIX_ACCESS_ACL:
644 case STREAM_ACL_IRIX_ACCESS_ACL_T:
645 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
646 case STREAM_UNIX_DEFAULT_ACL:
647 case STREAM_ACL_IRIX_DEFAULT_ACL_T:
648 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
653 #elif defined(HAVE_LINUX_OS)
654 static bool linux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
659 * Read access ACLs for files, dirs and links
661 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
665 if (!send_acl_stream(jcr, STREAM_ACL_LINUX_ACCESS_ACL_T, len))
670 * Directories can have default ACLs too
672 if (ff_pkt->type == FT_DIREND) {
673 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
677 if (!send_acl_stream(jcr, STREAM_ACL_LINUX_DEFAULT_ACL_T, len))
685 static bool linux_parse_acl_stream(JCR *jcr, int stream)
688 case STREAM_UNIX_ACCESS_ACL:
689 case STREAM_ACL_LINUX_ACCESS_ACL_T:
690 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
691 case STREAM_UNIX_DEFAULT_ACL:
692 case STREAM_ACL_LINUX_DEFAULT_ACL_T:
693 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
698 #elif defined(HAVE_OSF1_OS)
699 static bool tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
704 * Read access ACLs for files, dirs and links
706 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
710 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL_T, len))
715 * Directories can have default ACLs too
717 if (ff_pkt->type == FT_DIREND) {
718 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
722 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL_T, len))
727 * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
728 * This is an inherited acl for all subdirs.
729 * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
730 * Section 21.5 Default ACLs
732 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR)) < 0)
736 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL_T, len))
744 static bool tru64_parse_acl_stream(JCR *jcr, int stream)
747 case STREAM_UNIX_ACCESS_ACL:
748 case STREAM_ACL_TRU64_ACCESS_ACL_T:
749 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
750 case STREAM_UNIX_DEFAULT_ACL:
751 case STREAM_ACL_TRU64_DEFAULT_ACL_T:
752 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
753 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL_T:
754 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR);
758 #elif defined(HAVE_HPUX_OS)
759 #ifdef HAVE_SYS_ACL_H
762 #error "configure failed to detect availability of sys/acl.h"
768 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
769 * There is no need to store those acls as we already store the stat bits too.
771 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
776 for (n = 0; n < count; n++) {
780 * See if this acl just is the stat mode in acl form.
782 if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
783 (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
784 (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
792 * OS specific functions for handling different types of acl streams.
794 static bool hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
797 struct acl_entry acls[NACLENTRIES];
800 if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
802 #if defined(BACL_ENOTSUP)
805 * Not supported, just pretend there is nothing to see
807 pm_strcpy(jcr->acl_data, "");
812 Jmsg2(jcr, M_ERROR, 0, _("getacl error on file \"%s\": ERR=%s\n"),
813 jcr->last_fname, be.bstrerror());
814 Dmsg2(100, "getacl error file=%s ERR=%s\n",
815 jcr->last_fname, be.bstrerror());
817 pm_strcpy(jcr->acl_data, "");
823 pm_strcpy(jcr->acl_data, "");
827 if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
828 if (acl_is_trivial(n, acls, ff_pkt->statp)) {
830 * The ACLs simply reflect the (already known) standard permissions
831 * So we don't send an ACL stream to the SD.
833 pm_strcpy(jcr->acl_data, "");
837 if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
838 len = pm_strcpy(jcr->acl_data, acl_text);
839 actuallyfree(acl_text);
841 return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY, len);
845 Jmsg2(jcr, M_ERROR, 0, _("acltostr error on file \"%s\": ERR=%s\n"),
846 jcr->last_fname, be.bstrerror());
847 Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",
848 jcr->acl_data, jcr->last_fname, be.bstrerror());
856 static bool hpux_parse_acl_stream(JCR *jcr, int stream)
859 struct acl_entry acls[NACLENTRIES];
861 n = strtoacl(jcr->acl_data, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
864 Jmsg2(jcr, M_ERROR, 0, _("strtoacl error on file \"%s\": ERR=%s\n"),
865 jcr->last_fname, be.bstrerror());
866 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
867 jcr->acl_data, jcr->last_fname, be.bstrerror());
871 if (strtoacl(jcr->acl_data, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
873 Jmsg2(jcr, M_ERROR, 0, _("strtoacl error on file \"%s\": ERR=%s\n"),
874 jcr->last_fname, be.bstrerror());
875 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
876 jcr->acl_data, jcr->last_fname, be.bstrerror());
881 * Restore the ACLs, but don't complain about links which really should
882 * not have attributes, and the file it is linked to may not yet be restored.
883 * This is only true for the old acl streams as in the new implementation we
884 * don't save acls of symlinks (which cannot have acls anyhow)
886 if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
888 Jmsg2(jcr, M_ERROR, 0, _("setacl error on file \"%s\": ERR=%s\n"),
889 jcr->last_fname, be.bstrerror());
890 Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
891 jcr->acl_data, jcr->last_fname, be.bstrerror());
899 #elif defined(HAVE_SUN_OS)
900 #ifdef HAVE_SYS_ACL_H
903 #error "configure failed to detect availability of sys/acl.h"
906 #if defined(HAVE_EXTENDED_ACL)
908 * We define some internals of the Solaris acl libs here as those
909 * are not exposed yet. Probably because they want us to see the
910 * acls as opague data. But as we need to support different platforms
911 * and versions of Solaris we need to expose some data to be able
912 * to determine the type of acl used to stuff it into the correct
913 * data stream. I know this is far from portable, but maybe the
914 * propper interface is exposed later on and we can get ride of
915 * this kludge. Newer versions of Solaris include sys/acl_impl.h
916 * which has implementation details of acls, if thats included we
917 * don't have to define it ourself.
919 #if !defined(_SYS_ACL_IMPL_H)
920 typedef enum acl_type {
927 * Two external references to functions in the libsec library function not in current include files.
930 int acl_type(acl_t *);
931 char *acl_strerror(int);
935 * As the new libsec interface with acl_totext and acl_fromtext also handles
936 * the old format from acltotext we can use the new functions even
937 * for acls retrieved and stored in the database with older fd versions. If the
938 * new interface is not defined (Solaris 9 and older we fall back to the old code)
940 static bool solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
945 bool stream_status = false;
948 * Get ACL info: don't bother allocating space if there is only a trivial ACL.
950 if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
952 #if defined(BACL_ENOTSUP)
955 * Not supported, just pretend there is nothing to see
957 pm_strcpy(jcr->acl_data, "");
961 Jmsg2(jcr, M_ERROR, 0, _("acl_get error on file \"%s\": ERR=%s\n"),
962 jcr->last_fname, acl_strerror(errno));
963 Dmsg2(100, "acl_get error file=%s ERR=%s\n",
964 jcr->last_fname, acl_strerror(errno));
972 * The ACLs simply reflect the (already known) standard permissions
973 * So we don't send an ACL stream to the SD.
975 pm_strcpy(jcr->acl_data, "");
979 #if defined(ACL_SID_FMT)
981 * New format flag added in newer Solaris versions.
983 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
985 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
986 #endif /* ACL_SID_FMT */
988 if ((acl_text = acl_totext(aclp, flags)) != NULL) {
989 len = pm_strcpy(jcr->acl_data, acl_text);
990 actuallyfree(acl_text);
992 switch (acl_type(aclp)) {
994 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT_T, len);
997 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE_T, len);
1006 return stream_status;
1009 static bool solaris_parse_acl_stream(JCR *jcr, int stream)
1015 case STREAM_UNIX_ACCESS_ACL:
1016 case STREAM_ACL_SOLARIS_ACLENT_T:
1017 case STREAM_ACL_SOLARIS_ACE_T:
1018 if ((error = acl_fromtext(jcr->acl_data, &aclp)) != 0) {
1019 Jmsg2(jcr, M_ERROR, 0, _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1020 jcr->last_fname, acl_strerror(error));
1021 Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",
1022 jcr->acl_data, jcr->last_fname, acl_strerror(error));
1027 * Validate that the conversion gave us the correct acl type.
1030 case STREAM_ACL_SOLARIS_ACLENT_T:
1031 if (acl_type(aclp) != ACLENT_T) {
1032 Jmsg1(jcr, M_ERROR, 0, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1036 case STREAM_ACL_SOLARIS_ACE_T:
1037 if (acl_type(aclp) != ACE_T) {
1038 Jmsg1(jcr, M_ERROR, 0, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1044 * Stream id which doesn't describe the type of acl which is encoded.
1050 * Restore the ACLs, but don't complain about links which really should
1051 * not have attributes, and the file it is linked to may not yet be restored.
1052 * This is only true for the old acl streams as in the new implementation we
1053 * don't save acls of symlinks (which cannot have acls anyhow)
1055 if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1056 Jmsg2(jcr, M_ERROR, 0, _("acl_set error on file \"%s\": ERR=%s\n"),
1057 jcr->last_fname, acl_strerror(error));
1058 Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",
1059 jcr->acl_data, jcr->last_fname, acl_strerror(error));
1069 } /* end switch (stream) */
1072 #else /* HAVE_EXTENDED_ACL */
1075 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1076 * There is no need to store those acls as we already store the stat bits too.
1078 static bool acl_is_trivial(int count, aclent_t *entries)
1083 for (n = 0; n < count; n++) {
1086 if (!(ace->a_type == USER_OBJ ||
1087 ace->a_type == GROUP_OBJ ||
1088 ace->a_type == OTHER_OBJ ||
1089 ace->a_type == CLASS_OBJ))
1097 * OS specific functions for handling different types of acl streams.
1099 static bool solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt);
1105 n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1106 if (n < MIN_ACL_ENTRIES) {
1109 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1110 if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1111 if (acl_is_trivial(n, acls)) {
1113 * The ACLs simply reflect the (already known) standard permissions
1114 * So we don't send an ACL stream to the SD.
1117 pm_strcpy(jcr->acl_data, "");
1121 if ((acl_text = acltotext(acls, n)) != NULL) {
1122 len = pm_strcpy(jcr->acl_data, acl_text);
1123 actuallyfree(acl_text);
1126 return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT_T, len);
1130 Jmsg2(jcr, M_ERROR, 0, _("acltotext error on file \"%s\": ERR=%s\n"),
1131 jcr->last_fname, be.bstrerror());
1132 Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",
1133 jcr->acl_data, jcr->last_fname, be.bstrerror());
1140 static bool solaris_parse_acl_stream(JCR *jcr, int stream)
1145 acls = aclfromtext(jcr->acl_data, &n);
1148 Jmsg2(jcr, M_ERROR, 0, _("aclfromtext error on file \"%s\": ERR=%s\n"),
1149 jcr->last_fname, be.bstrerror());
1150 Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",
1151 jcr->acl_data, jcr->last_fname, be.bstrerror());
1157 * Restore the ACLs, but don't complain about links which really should
1158 * not have attributes, and the file it is linked to may not yet be restored.
1160 if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
1162 Jmsg2(jcr, M_ERROR, 0, _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
1163 jcr->last_fname, be.bstrerror());
1164 Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
1165 jcr->acl_data, jcr->last_fname, be.bstrerror());
1175 #endif /* HAVE_EXTENDED_ACL */
1176 #endif /* HAVE_SUN_OS */
1179 * Entry points when compiled with support for ACLs on a supported platform.
1183 * Read and send an ACL for the last encountered file.
1185 bool build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1188 * Call the appropriate function, the ifdefs make sure the proper code is compiled.
1190 #if defined(HAVE_AIX_OS)
1191 return aix_build_acl_streams(jcr, ff_pkt);
1192 #elif defined(HAVE_DARWIN_OS)
1193 return darwin_build_acl_streams(jcr, ff_pkt);
1194 #elif defined(HAVE_FREEBSD_OS)
1195 return freebsd_build_acl_streams(jcr, ff_pkt);
1196 #elif defined(HAVE_HPUX_OS)
1197 return hpux_build_acl_streams(jcr, ff_pkt);
1198 #elif defined(HAVE_IRIX_OS)
1199 return irix_build_acl_streams(jcr, ff_pkt);
1200 #elif defined(HAVE_LINUX_OS)
1201 return linux_build_acl_streams(jcr, ff_pkt);
1202 #elif defined(HAVE_OSF1_OS)
1203 return tru64_build_acl_streams(jcr, ff_pkt);
1204 #elif defined(HAVE_SUN_OS)
1205 return solaris_build_acl_streams(jcr, ff_pkt);
1209 bool parse_acl_stream(JCR *jcr, int stream)
1212 * Based on the stream being passed in dispatch to the right function
1213 * for parsing and restoring a specific acl. The platform determines
1214 * which streams are recognized and parsed and which are handled by
1215 * the default case and ignored. The old STREAM_UNIX_ACCESS_ACL and
1216 * STREAM_UNIX_DEFAULT_ACL is handled as a legacy stream by each function.
1217 * As only one of the platform defines is true per compile we never end
1218 * up with duplicate switch values.
1221 #if defined(HAVE_AIX_OS)
1222 case STREAM_UNIX_ACCESS_ACL:
1223 case STREAM_UNIX_DEFAULT_ACL:
1224 case STREAM_ACL_AIX_TEXT:
1225 return aix_parse_acl_stream(jcr, stream);
1226 #elif defined(HAVE_DARWIN_OS)
1227 case STREAM_UNIX_ACCESS_ACL:
1228 case STREAM_ACL_DARWIN_ACCESS_ACL_T:
1229 return darwin_parse_acl_stream(jcr, stream);
1230 #elif defined(HAVE_FREEBSD_OS)
1231 case STREAM_UNIX_ACCESS_ACL:
1232 case STREAM_UNIX_DEFAULT_ACL:
1233 case STREAM_ACL_FREEBSD_DEFAULT_ACL_T:
1234 case STREAM_ACL_FREEBSD_ACCESS_ACL_T:
1235 return freebsd_parse_acl_stream(jcr, stream);
1236 #elif defined(HAVE_HPUX_OS)
1237 case STREAM_UNIX_ACCESS_ACL:
1238 case STREAM_ACL_HPUX_ACL_ENTRY:
1239 return hpux_parse_acl_stream(jcr, stream);
1240 #elif defined(HAVE_IRIX_OS)
1241 case STREAM_UNIX_ACCESS_ACL:
1242 case STREAM_UNIX_DEFAULT_ACL:
1243 case STREAM_ACL_IRIX_DEFAULT_ACL_T:
1244 case STREAM_ACL_IRIX_ACCESS_ACL_T:
1245 return irix_parse_acl_stream(jcr, stream);
1246 #elif defined(HAVE_LINUX_OS)
1247 case STREAM_UNIX_ACCESS_ACL:
1248 case STREAM_UNIX_DEFAULT_ACL:
1249 case STREAM_ACL_LINUX_DEFAULT_ACL_T:
1250 case STREAM_ACL_LINUX_ACCESS_ACL_T:
1251 return linux_parse_acl_stream(jcr, stream);
1252 #elif defined(HAVE_OSF1_OS)
1253 case STREAM_UNIX_ACCESS_ACL:
1254 case STREAM_UNIX_DEFAULT_ACL:
1255 case STREAM_ACL_TRU64_DEFAULT_ACL_T:
1256 case STREAM_ACL_TRU64_ACCESS_ACL_T:
1257 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL_T:
1258 return tru64_parse_acl_stream(jcr, stream);
1259 #elif defined(HAVE_SUN_OS)
1260 case STREAM_UNIX_ACCESS_ACL:
1261 case STREAM_ACL_SOLARIS_ACLENT_T:
1262 #if defined(HAVE_EXTENDED_ACL)
1263 case STREAM_ACL_SOLARIS_ACE_T:
1265 return solaris_parse_acl_stream(jcr, stream);
1269 * Issue a warning and discard the message. But pretend the restore was ok.
1271 Qmsg2(jcr, M_WARNING, 0,
1272 _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
1273 jcr->last_fname, stream);
1275 } /* end switch (stream) */