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
60 #if !defined(HAVE_ACL)
62 * Entry points when compiled without support for ACLs or on an unsupported platform.
64 bool build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
69 bool parse_acl_stream(JCR *jcr, int stream)
75 * Send an ACL stream to the SD.
77 static bool send_acl_stream(JCR *jcr, int stream)
79 BSOCK *sd = jcr->store_bsock;
81 #ifdef FD_NO_SEND_TEST
88 if (jcr->acl_data_len <= 0)
94 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
95 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
102 * Send the buffer to the storage deamon
104 Dmsg1(400, "Backing up ACL <%s>\n", jcr->acl_data);
106 sd->msg = jcr->acl_data;
107 sd->msglen = jcr->acl_data_len + 1;
111 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
117 jcr->JobBytes += sd->msglen;
119 if (!sd->signal(BNET_EOD)) {
120 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
126 Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
131 #if defined(HAVE_AIX_OS)
133 #include <sys/access.h>
135 static bool aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
139 if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
140 jcr->acl_data_len = pm_strcpy(jcr->acl_data, acl_text);
141 actuallyfree(acl_text);
143 return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT);
149 static bool aix_parse_acl_stream(JCR *jcr, int stream)
151 if (acl_put(jcr->last_fname, jcr->acl_data, 0) != 0) {
158 #elif defined(HAVE_DARWIN_OS) \
159 || defined(HAVE_FREEBSD_OS) \
160 || defined(HAVE_IRIX_OS) \
161 || defined(HAVE_OSF1_OS) \
162 || defined(HAVE_LINUX_OS)
164 #include <sys/types.h>
166 #ifdef HAVE_SYS_ACL_H
169 #error "configure failed to detect availability of sys/acl.h"
172 /* On IRIX we can get shortened ACLs */
173 #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
174 #define acl_to_text(acl,len) acl_to_short_text((acl), (len))
177 /* In Linux we can get numeric and/or shorted ACLs */
178 #if defined(HAVE_LINUX_OS)
179 #if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
180 #define BACL_ALTERNATE_TEXT (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
181 #elif defined(BACL_WANT_SHORT_ACLS)
182 #define BACL_ALTERNATE_TEXT TEXT_ABBREVIATE
183 #elif defined(BACL_WANT_NUMERIC_IDS)
184 #define BACL_ALTERNATE_TEXT TEXT_NUMERIC_IDS
186 #ifdef BACL_ALTERNATE_TEXT
187 #include <acl/libacl.h>
188 #define acl_to_text(acl,len) (acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
193 * Some generic functions used by multiple OSes.
195 static acl_type_t bac_to_os_acltype(bacl_type acltype)
200 case BACL_TYPE_ACCESS:
201 ostype = ACL_TYPE_ACCESS;
203 case BACL_TYPE_DEFAULT:
204 ostype = ACL_TYPE_DEFAULT;
207 #ifdef ACL_TYPE_DEFAULT_DIR
208 case BACL_TYPE_DEFAULT_DIR:
210 * OSF1 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
212 ostype = ACL_TYPE_DEFAULT_DIR;
215 #ifdef ACL_TYPE_EXTENDED
216 case BACL_TYPE_EXTENDED:
218 * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
220 ostype = ACL_TYPE_EXTENDED;
225 * This should never happen, as the per os version function only tries acl
226 * types supported on a certain platform.
228 ostype = (acl_type_t)ACL_TYPE_NONE;
235 #if !defined(HAVE_DARWIN_OS)
237 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
238 * There is no need to store those acls as we already store the stat bits too.
240 static bool acl_is_trivial(acl_t acl)
243 * acl is trivial if it has only the following entries:
250 #if defined(HAVE_FREEBSD_OS) || defined(HAVE_LINUX_OS)
253 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
254 while (entry_available == 1) {
256 * Get the tag type of this acl entry.
257 * If we fail to get the tagtype we call the acl non-trivial.
259 if (acl_get_tag_type(ace, &tag) < 0)
263 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
265 if (tag != ACL_USER_OBJ &&
266 tag != ACL_GROUP_OBJ &&
270 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
274 #elif defined(HAVE_IRIX_OS)
277 for (n = 0; n < acl->acl_cnt; n++) {
278 ace = &acl->acl_entry[n];
282 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
284 if (tag != ACL_USER_OBJ &&
285 tag != ACL_GROUP_OBJ &&
291 #elif defined(HAVE_OSF1_OS)
294 ace = acl->acl_first;
295 count = acl->acl_num;
298 tag = ace->entry->acl_type;
301 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
303 if (tag != ACL_USER_OBJ &&
304 tag != ACL_GROUP_OBJ &&
309 * On Tru64, perm can also contain non-standard bits such as
310 * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
312 if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
325 * Generic wrapper around acl_get_file call.
327 static int generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
334 ostype = bac_to_os_acltype(acltype);
335 acl = acl_get_file(jcr->last_fname, ostype);
337 #if defined(HAVE_IRIX_OS)
339 * From observation, IRIX's acl_get_file() seems to return a
340 * non-NULL acl with a count field of -1 when a file has no ACL
341 * defined, while IRIX's acl_to_text() returns NULL when presented
344 * Checking the count in the acl structure before calling
345 * acl_to_text() lets us avoid error messages about files
346 * with no ACLs, without modifying the flow of the code used for
347 * other operating systems, and it saves making some calls
348 * to acl_to_text() besides.
350 if (acl->acl_cnt <= 0) {
351 pm_strcpy(jcr->acl_data, "");
357 #if !defined(HAVE_DARWIN_OS)
359 * Make sure this is not just a trivial ACL.
361 if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
363 * The ACLs simply reflect the (already known) standard permissions
364 * So we don't send an ACL stream to the SD.
366 pm_strcpy(jcr->acl_data, "");
372 if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
373 len = pm_strcpy(jcr->acl_data, acl_text);
381 Jmsg2(jcr, M_ERROR, 0, _("acl_to_text error on file \"%s\": ERR=%s\n"),
382 jcr->last_fname, be.bstrerror());
383 Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",
384 jcr->last_fname, be.bstrerror());
386 pm_strcpy(jcr->acl_data, "");
389 return 0; /* non-fatal error */
393 * Handle errors gracefully.
395 if (acl == (acl_t)NULL) {
397 #if defined(BACL_ENOTSUP)
399 break; /* not supported */
403 /* Some real error */
404 Jmsg2(jcr, M_ERROR, 0, _("acl_get_file error on file \"%s\": ERR=%s\n"),
405 jcr->last_fname, be.bstrerror());
406 Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",
407 jcr->last_fname, be.bstrerror());
409 pm_strcpy(jcr->acl_data, "");
410 return 0; /* non-fatal error */
414 * Not supported, just pretend there is nothing to see
416 pm_strcpy(jcr->acl_data, "");
421 * Generic wrapper around acl_set_file call.
423 static bool generic_set_acl_on_os(JCR *jcr, bacl_type acltype)
429 * If we get empty default ACLs, clear ACLs now
431 ostype = bac_to_os_acltype(acltype);
432 if (ostype == ACL_TYPE_DEFAULT && strlen(jcr->acl_data) == 0) {
433 if (acl_delete_def_file(jcr->last_fname) == 0) {
437 Jmsg2(jcr, M_ERROR, 0, _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
438 jcr->last_fname, be.bstrerror());
443 acl = acl_from_text(jcr->acl_data);
446 Jmsg2(jcr, M_ERROR, 0, _("acl_from_text error on file \"%s\": ERR=%s\n"),
447 jcr->last_fname, be.bstrerror());
448 Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",
449 jcr->acl_data, jcr->last_fname, be.bstrerror());
455 * FreeBSD always fails acl_valid() - at least on valid input...
456 * As it does the right thing, given valid input, just ignore acl_valid().
458 #ifndef HAVE_FREEBSD_OS
459 if (acl_valid(acl) != 0) {
461 Jmsg2(jcr, M_ERROR, 0, _("ac_valid error on file \"%s\": ERR=%s\n"),
462 jcr->last_fname, be.bstrerror());
463 Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",
464 jcr->acl_data, jcr->last_fname, be.bstrerror());
472 * Restore the ACLs, but don't complain about links which really should
473 * not have attributes, and the file it is linked to may not yet be restored.
474 * This is only true for the old acl streams as in the new implementation we
475 * don't save acls of symlinks (which cannot have acls anyhow)
477 if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
479 Jmsg2(jcr, M_ERROR, 0, _("acl_set_file error on file \"%s\": ERR=%s\n"),
480 jcr->last_fname, be.bstrerror());
481 Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
482 jcr->acl_data, jcr->last_fname, be.bstrerror());
493 * OS specific functions for handling different types of acl streams.
495 #if defined(HAVE_DARWIN_OS)
496 static bool darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
498 #if defined(ACL_TYPE_EXTENDED)
500 * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
501 * and acl_get_file (name, ACL_TYPE_DEFAULT)
502 * always return NULL / EINVAL. There is no point in making
503 * these two useless calls. The real ACL is retrieved through
504 * acl_get_file (name, ACL_TYPE_EXTENDED).
506 * Read access ACLs for files, dirs and links
508 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED)) < 0)
512 * Read access ACLs for files, dirs and links
514 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
518 if (jcr->acl_data_len > 0) {
519 if (!send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL))
526 static bool darwin_parse_acl_stream(JCR *jcr, int stream)
529 case STREAM_UNIX_ACCESS_ACL:
530 case STREAM_ACL_DARWIN_ACCESS_ACL:
531 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
536 #elif defined(HAVE_FREEBSD_OS)
537 static bool freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
540 * Read access ACLs for files, dirs and links
542 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
545 if (jcr->acl_data_len > 0) {
546 if (!send_acl_stream(jcr, STREAM_ACL_FREEBSD_ACCESS_ACL))
551 * Directories can have default ACLs too
553 if (ff_pkt->type == FT_DIREND) {
554 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
557 if (jcr->acl_data_len > 0) {
558 if (!send_acl_stream(jcr, STREAM_ACL_FREEBSD_DEFAULT_ACL))
566 static bool freebsd_parse_acl_stream(JCR *jcr, int stream)
569 case STREAM_UNIX_ACCESS_ACL:
570 case STREAM_ACL_FREEBSD_ACCESS_ACL:
571 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
572 case STREAM_UNIX_DEFAULT_ACL:
573 case STREAM_ACL_FREEBSD_DEFAULT_ACL:
574 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
579 #elif defined(HAVE_IRIX_OS)
580 static bool irix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
583 * Read access ACLs for files, dirs and links
585 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
588 if (jcr->acl_data_len > 0) {
589 if (!send_acl_stream(jcr, STREAM_ACL_IRIX_ACCESS_ACL))
594 * Directories can have default ACLs too
596 if (ff_pkt->type == FT_DIREND) {
597 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
600 if (jcr->acl_data_len > 0) {
601 if (!send_acl_stream(jcr, STREAM_ACL_IRIX_DEFAULT_ACL))
609 static bool irix_parse_acl_stream(JCR *jcr, int stream)
612 case STREAM_UNIX_ACCESS_ACL:
613 case STREAM_ACL_IRIX_ACCESS_ACL:
614 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
615 case STREAM_UNIX_DEFAULT_ACL:
616 case STREAM_ACL_IRIX_DEFAULT_ACL:
617 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
622 #elif defined(HAVE_LINUX_OS)
623 static bool linux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
626 * Read access ACLs for files, dirs and links
628 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
631 if (jcr->acl_data_len > 0) {
632 if (!send_acl_stream(jcr, STREAM_ACL_LINUX_ACCESS_ACL))
637 * Directories can have default ACLs too
639 if (ff_pkt->type == FT_DIREND) {
640 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
643 if (jcr->acl_data_len > 0) {
644 if (!send_acl_stream(jcr, STREAM_ACL_LINUX_DEFAULT_ACL))
652 static bool linux_parse_acl_stream(JCR *jcr, int stream)
655 case STREAM_UNIX_ACCESS_ACL:
656 case STREAM_ACL_LINUX_ACCESS_ACL:
657 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
658 case STREAM_UNIX_DEFAULT_ACL:
659 case STREAM_ACL_LINUX_DEFAULT_ACL:
660 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
665 #elif defined(HAVE_OSF1_OS)
666 static bool tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
669 * Read access ACLs for files, dirs and links
671 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
674 if (jcr->acl_data_len > 0) {
675 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL))
680 * Directories can have default ACLs too
682 if (ff_pkt->type == FT_DIREND) {
683 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
686 if (jcr->acl_data_len > 0) {
687 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL))
692 * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
693 * This is an inherited acl for all subdirs.
694 * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
695 * Section 21.5 Default ACLs
697 if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR)) < 0)
700 if (jcr->acl_data_len > 0) {
701 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL))
709 static bool tru64_parse_acl_stream(JCR *jcr, int stream)
712 case STREAM_UNIX_ACCESS_ACL:
713 case STREAM_ACL_TRU64_ACCESS_ACL:
714 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
715 case STREAM_UNIX_DEFAULT_ACL:
716 case STREAM_ACL_TRU64_DEFAULT_ACL:
717 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
718 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
719 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR);
723 #elif defined(HAVE_HPUX_OS)
724 #ifdef HAVE_SYS_ACL_H
727 #error "configure failed to detect availability of sys/acl.h"
733 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
734 * There is no need to store those acls as we already store the stat bits too.
736 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
741 for (n = 0; n < count; n++) {
745 * See if this acl just is the stat mode in acl form.
747 if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
748 (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
749 (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
757 * OS specific functions for handling different types of acl streams.
759 static bool hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
762 struct acl_entry acls[NACLENTRIES];
765 if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
767 #if defined(BACL_ENOTSUP)
770 * Not supported, just pretend there is nothing to see
772 pm_strcpy(jcr->acl_data, "");
777 Jmsg2(jcr, M_ERROR, 0, _("getacl error on file \"%s\": ERR=%s\n"),
778 jcr->last_fname, be.bstrerror());
779 Dmsg2(100, "getacl error file=%s ERR=%s\n",
780 jcr->last_fname, be.bstrerror());
782 pm_strcpy(jcr->acl_data, "");
788 pm_strcpy(jcr->acl_data, "");
792 if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
793 if (acl_is_trivial(n, acls, ff_pkt->statp)) {
795 * The ACLs simply reflect the (already known) standard permissions
796 * So we don't send an ACL stream to the SD.
798 pm_strcpy(jcr->acl_data, "");
802 if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
803 jcr->acl_data_len = pm_strcpy(jcr->acl_data, acl_text);
804 actuallyfree(acl_text);
806 return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
810 Jmsg2(jcr, M_ERROR, 0, _("acltostr error on file \"%s\": ERR=%s\n"),
811 jcr->last_fname, be.bstrerror());
812 Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",
813 jcr->acl_data, jcr->last_fname, be.bstrerror());
821 static bool hpux_parse_acl_stream(JCR *jcr, int stream)
824 struct acl_entry acls[NACLENTRIES];
826 n = strtoacl(jcr->acl_data, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
829 Jmsg2(jcr, M_ERROR, 0, _("strtoacl error on file \"%s\": ERR=%s\n"),
830 jcr->last_fname, be.bstrerror());
831 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
832 jcr->acl_data, jcr->last_fname, be.bstrerror());
836 if (strtoacl(jcr->acl_data, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
838 Jmsg2(jcr, M_ERROR, 0, _("strtoacl error on file \"%s\": ERR=%s\n"),
839 jcr->last_fname, be.bstrerror());
840 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
841 jcr->acl_data, jcr->last_fname, be.bstrerror());
846 * Restore the ACLs, but don't complain about links which really should
847 * not have attributes, and the file it is linked to may not yet be restored.
848 * This is only true for the old acl streams as in the new implementation we
849 * don't save acls of symlinks (which cannot have acls anyhow)
851 if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
853 Jmsg2(jcr, M_ERROR, 0, _("setacl error on file \"%s\": ERR=%s\n"),
854 jcr->last_fname, be.bstrerror());
855 Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
856 jcr->acl_data, jcr->last_fname, be.bstrerror());
864 #elif defined(HAVE_SUN_OS)
865 #ifdef HAVE_SYS_ACL_H
868 #error "configure failed to detect availability of sys/acl.h"
871 #if defined(HAVE_EXTENDED_ACL)
873 * We define some internals of the Solaris acl libs here as those
874 * are not exposed yet. Probably because they want us to see the
875 * acls as opague data. But as we need to support different platforms
876 * and versions of Solaris we need to expose some data to be able
877 * to determine the type of acl used to stuff it into the correct
878 * data stream. I know this is far from portable, but maybe the
879 * propper interface is exposed later on and we can get ride of
880 * this kludge. Newer versions of Solaris include sys/acl_impl.h
881 * which has implementation details of acls, if thats included we
882 * don't have to define it ourself.
884 #if !defined(_SYS_ACL_IMPL_H)
885 typedef enum acl_type {
892 * Two external references to functions in the libsec library function not in current include files.
895 int acl_type(acl_t *);
896 char *acl_strerror(int);
900 * As the new libsec interface with acl_totext and acl_fromtext also handles
901 * the old format from acltotext we can use the new functions even
902 * for acls retrieved and stored in the database with older fd versions. If the
903 * new interface is not defined (Solaris 9 and older we fall back to the old code)
905 static bool solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
907 int acl_enabled, flags;
910 bool stream_status = false;
914 * See if filesystem supports acls.
916 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
917 switch (acl_enabled) {
919 pm_strcpy(jcr->acl_data, "");
923 Jmsg2(jcr, M_ERROR, 0, _("pathconf error on file \"%s\": ERR=%s\n"),
924 jcr->last_fname, be.bstrerror());
925 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
926 jcr->last_fname, be.bstrerror());
934 * Get ACL info: don't bother allocating space if there is only a trivial ACL.
936 if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
937 Jmsg2(jcr, M_ERROR, 0, _("acl_get error on file \"%s\": ERR=%s\n"),
938 jcr->last_fname, acl_strerror(errno));
939 Dmsg2(100, "acl_get error file=%s ERR=%s\n",
940 jcr->last_fname, acl_strerror(errno));
947 * The ACLs simply reflect the (already known) standard permissions
948 * So we don't send an ACL stream to the SD.
950 pm_strcpy(jcr->acl_data, "");
954 #if defined(ACL_SID_FMT)
956 * New format flag added in newer Solaris versions.
958 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
960 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
961 #endif /* ACL_SID_FMT */
963 if ((acl_text = acl_totext(aclp, flags)) != NULL) {
964 jcr->acl_data_len = pm_strcpy(jcr->acl_data, acl_text);
965 actuallyfree(acl_text);
967 switch (acl_type(aclp)) {
969 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
972 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE);
981 return stream_status;
984 static bool solaris_parse_acl_stream(JCR *jcr, int stream)
987 int acl_enabled, error;
991 case STREAM_UNIX_ACCESS_ACL:
992 case STREAM_ACL_SOLARIS_ACLENT:
993 case STREAM_ACL_SOLARIS_ACE:
995 * First make sure the filesystem supports acls.
997 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
998 switch (acl_enabled) {
1000 Jmsg1(jcr, M_ERROR, 0, _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
1005 Jmsg2(jcr, M_ERROR, 0, _("pathconf error on file \"%s\": ERR=%s\n"),
1006 jcr->last_fname, be.bstrerror());
1007 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1008 jcr->acl_data, jcr->last_fname, be.bstrerror());
1013 * On a filesystem with ACL support make sure this particilar ACL type can be restored.
1016 case STREAM_ACL_SOLARIS_ACLENT:
1018 * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
1020 if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
1021 Jmsg1(jcr, M_ERROR, 0, _("Trying to restore acl on file \"%s\" on filesystem without aclent acl support\n"),
1026 case STREAM_ACL_SOLARIS_ACE:
1028 * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
1030 if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
1031 Jmsg1(jcr, M_ERROR, 0, _("Trying to restore acl on file \"%s\" on filesystem without ace acl support\n"),
1038 * Stream id which doesn't describe the type of acl which is encoded.
1045 if ((error = acl_fromtext(jcr->acl_data, &aclp)) != 0) {
1046 Jmsg2(jcr, M_ERROR, 0, _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1047 jcr->last_fname, acl_strerror(error));
1048 Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",
1049 jcr->acl_data, jcr->last_fname, acl_strerror(error));
1054 * Validate that the conversion gave us the correct acl type.
1057 case STREAM_ACL_SOLARIS_ACLENT:
1058 if (acl_type(aclp) != ACLENT_T) {
1059 Jmsg1(jcr, M_ERROR, 0, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1064 case STREAM_ACL_SOLARIS_ACE:
1065 if (acl_type(aclp) != ACE_T) {
1066 Jmsg1(jcr, M_ERROR, 0, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1073 * Stream id which doesn't describe the type of acl which is encoded.
1079 * Restore the ACLs, but don't complain about links which really should
1080 * not have attributes, and the file it is linked to may not yet be restored.
1081 * This is only true for the old acl streams as in the new implementation we
1082 * don't save acls of symlinks (which cannot have acls anyhow)
1084 if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1085 Jmsg2(jcr, M_ERROR, 0, _("acl_set error on file \"%s\": ERR=%s\n"),
1086 jcr->last_fname, acl_strerror(error));
1087 Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",
1088 jcr->acl_data, jcr->last_fname, acl_strerror(error));
1098 } /* end switch (stream) */
1101 #else /* HAVE_EXTENDED_ACL */
1104 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1105 * There is no need to store those acls as we already store the stat bits too.
1107 static bool acl_is_trivial(int count, aclent_t *entries)
1112 for (n = 0; n < count; n++) {
1115 if (!(ace->a_type == USER_OBJ ||
1116 ace->a_type == GROUP_OBJ ||
1117 ace->a_type == OTHER_OBJ ||
1118 ace->a_type == CLASS_OBJ))
1126 * OS specific functions for handling different types of acl streams.
1128 static bool solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1134 n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1135 if (n < MIN_ACL_ENTRIES)
1138 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1139 if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1140 if (acl_is_trivial(n, acls)) {
1142 * The ACLs simply reflect the (already known) standard permissions
1143 * So we don't send an ACL stream to the SD.
1146 pm_strcpy(jcr->acl_data, "");
1150 if ((acl_text = acltotext(acls, n)) != NULL) {
1151 jcr->acl_data_len = pm_strcpy(jcr->acl_data, acl_text);
1152 actuallyfree(acl_text);
1155 return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1159 Jmsg2(jcr, M_ERROR, 0, _("acltotext error on file \"%s\": ERR=%s\n"),
1160 jcr->last_fname, be.bstrerror());
1161 Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",
1162 jcr->acl_data, jcr->last_fname, be.bstrerror());
1169 static bool solaris_parse_acl_stream(JCR *jcr, int stream)
1174 acls = aclfromtext(jcr->acl_data, &n);
1177 Jmsg2(jcr, M_ERROR, 0, _("aclfromtext error on file \"%s\": ERR=%s\n"),
1178 jcr->last_fname, be.bstrerror());
1179 Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",
1180 jcr->acl_data, jcr->last_fname, be.bstrerror());
1186 * Restore the ACLs, but don't complain about links which really should
1187 * not have attributes, and the file it is linked to may not yet be restored.
1189 if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
1191 Jmsg2(jcr, M_ERROR, 0, _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
1192 jcr->last_fname, be.bstrerror());
1193 Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
1194 jcr->acl_data, jcr->last_fname, be.bstrerror());
1204 #endif /* HAVE_EXTENDED_ACL */
1205 #endif /* HAVE_SUN_OS */
1208 * Entry points when compiled with support for ACLs on a supported platform.
1212 * Read and send an ACL for the last encountered file.
1214 bool build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1217 * Call the appropriate function, the ifdefs make sure the proper code is compiled.
1219 #if defined(HAVE_AIX_OS)
1220 return aix_build_acl_streams(jcr, ff_pkt);
1221 #elif defined(HAVE_DARWIN_OS)
1222 return darwin_build_acl_streams(jcr, ff_pkt);
1223 #elif defined(HAVE_FREEBSD_OS)
1224 return freebsd_build_acl_streams(jcr, ff_pkt);
1225 #elif defined(HAVE_HPUX_OS)
1226 return hpux_build_acl_streams(jcr, ff_pkt);
1227 #elif defined(HAVE_IRIX_OS)
1228 return irix_build_acl_streams(jcr, ff_pkt);
1229 #elif defined(HAVE_LINUX_OS)
1230 return linux_build_acl_streams(jcr, ff_pkt);
1231 #elif defined(HAVE_OSF1_OS)
1232 return tru64_build_acl_streams(jcr, ff_pkt);
1233 #elif defined(HAVE_SUN_OS)
1234 return solaris_build_acl_streams(jcr, ff_pkt);
1238 bool parse_acl_stream(JCR *jcr, int stream)
1241 * Based on the stream being passed in dispatch to the right function
1242 * for parsing and restoring a specific acl. The platform determines
1243 * which streams are recognized and parsed and which are handled by
1244 * the default case and ignored. The old STREAM_UNIX_ACCESS_ACL and
1245 * STREAM_UNIX_DEFAULT_ACL is handled as a legacy stream by each function.
1246 * As only one of the platform defines is true per compile we never end
1247 * up with duplicate switch values.
1250 #if defined(HAVE_AIX_OS)
1251 case STREAM_UNIX_ACCESS_ACL:
1252 case STREAM_UNIX_DEFAULT_ACL:
1253 case STREAM_ACL_AIX_TEXT:
1254 return aix_parse_acl_stream(jcr, stream);
1255 #elif defined(HAVE_DARWIN_OS)
1256 case STREAM_UNIX_ACCESS_ACL:
1257 case STREAM_ACL_DARWIN_ACCESS_ACL:
1258 return darwin_parse_acl_stream(jcr, stream);
1259 #elif defined(HAVE_FREEBSD_OS)
1260 case STREAM_UNIX_ACCESS_ACL:
1261 case STREAM_UNIX_DEFAULT_ACL:
1262 case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1263 case STREAM_ACL_FREEBSD_ACCESS_ACL:
1264 return freebsd_parse_acl_stream(jcr, stream);
1265 #elif defined(HAVE_HPUX_OS)
1266 case STREAM_UNIX_ACCESS_ACL:
1267 case STREAM_ACL_HPUX_ACL_ENTRY:
1268 return hpux_parse_acl_stream(jcr, stream);
1269 #elif defined(HAVE_IRIX_OS)
1270 case STREAM_UNIX_ACCESS_ACL:
1271 case STREAM_UNIX_DEFAULT_ACL:
1272 case STREAM_ACL_IRIX_DEFAULT_ACL:
1273 case STREAM_ACL_IRIX_ACCESS_ACL:
1274 return irix_parse_acl_stream(jcr, stream);
1275 #elif defined(HAVE_LINUX_OS)
1276 case STREAM_UNIX_ACCESS_ACL:
1277 case STREAM_UNIX_DEFAULT_ACL:
1278 case STREAM_ACL_LINUX_DEFAULT_ACL:
1279 case STREAM_ACL_LINUX_ACCESS_ACL:
1280 return linux_parse_acl_stream(jcr, stream);
1281 #elif defined(HAVE_OSF1_OS)
1282 case STREAM_UNIX_ACCESS_ACL:
1283 case STREAM_UNIX_DEFAULT_ACL:
1284 case STREAM_ACL_TRU64_DEFAULT_ACL:
1285 case STREAM_ACL_TRU64_ACCESS_ACL:
1286 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
1287 return tru64_parse_acl_stream(jcr, stream);
1288 #elif defined(HAVE_SUN_OS)
1289 case STREAM_UNIX_ACCESS_ACL:
1290 case STREAM_ACL_SOLARIS_ACLENT:
1291 #if defined(HAVE_EXTENDED_ACL)
1292 case STREAM_ACL_SOLARIS_ACE:
1294 return solaris_parse_acl_stream(jcr, stream);
1298 * Issue a warning and discard the message. But pretend the restore was ok.
1300 Qmsg2(jcr, M_WARNING, 0,
1301 _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
1302 jcr->last_fname, stream);
1304 } /* end switch (stream) */