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. Everything outside that gets stub functions.
62 * Also when XATTR 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, int len)
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 = 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)
154 if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
155 len = pm_strcpy(jcr->acl_data, acl_text);
156 actuallyfree(acl_text);
158 return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT, len);
164 static bool aix_parse_acl_stream(JCR *jcr, int stream)
166 if (acl_put(jcr->last_fname, jcr->acl_data, 0) != 0) {
173 #elif defined(HAVE_DARWIN_OS) \
174 || defined(HAVE_FREEBSD_OS) \
175 || defined(HAVE_IRIX_OS) \
176 || defined(HAVE_OSF1_OS) \
177 || defined(HAVE_LINUX_OS)
179 #include <sys/types.h>
181 #ifdef HAVE_SYS_ACL_H
184 #error "configure failed to detect availability of sys/acl.h"
187 /* On IRIX we can get shortened ACLs */
188 #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
189 #define acl_to_text(acl,len) acl_to_short_text((acl), (len))
192 /* In Linux we can get numeric and/or shorted ACLs */
193 #if defined(HAVE_LINUX_OS)
194 #if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
195 #define BACL_ALTERNATE_TEXT (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
196 #elif defined(BACL_WANT_SHORT_ACLS)
197 #define BACL_ALTERNATE_TEXT TEXT_ABBREVIATE
198 #elif defined(BACL_WANT_NUMERIC_IDS)
199 #define BACL_ALTERNATE_TEXT TEXT_NUMERIC_IDS
201 #ifdef BACL_ALTERNATE_TEXT
202 #include <acl/libacl.h>
203 #define acl_to_text(acl,len) (acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
208 * Some generic functions used by multiple OSes.
210 static acl_type_t bac_to_os_acltype(bacl_type acltype)
215 case BACL_TYPE_ACCESS:
216 ostype = ACL_TYPE_ACCESS;
218 case BACL_TYPE_DEFAULT:
219 ostype = ACL_TYPE_DEFAULT;
222 #ifdef ACL_TYPE_DEFAULT_DIR
223 case BACL_TYPE_DEFAULT_DIR:
225 * OSF1 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
227 ostype = ACL_TYPE_DEFAULT_DIR;
230 #ifdef ACL_TYPE_EXTENDED
231 case BACL_TYPE_EXTENDED:
233 * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
235 ostype = ACL_TYPE_EXTENDED;
240 * This should never happen, as the per os version function only tries acl
241 * types supported on a certain platform.
243 ostype = (acl_type_t)ACL_TYPE_NONE;
250 #if !defined(HAVE_DARWIN_OS)
252 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
253 * There is no need to store those acls as we already store the stat bits too.
255 static bool acl_is_trivial(acl_t acl)
258 * acl is trivial if it has only the following entries:
265 #if defined(HAVE_FREEBSD_OS) || defined(HAVE_LINUX_OS)
268 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
269 while (entry_available == 1) {
271 * Get the tag type of this acl entry.
272 * If we fail to get the tagtype we call the acl non-trivial.
274 if (acl_get_tag_type(ace, &tag) < 0)
278 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
280 if (tag != ACL_USER_OBJ &&
281 tag != ACL_GROUP_OBJ &&
285 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
289 #elif defined(HAVE_IRIX_OS)
292 for (n = 0; n < acl->acl_cnt; n++) {
293 ace = &acl->acl_entry[n];
297 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
299 if (tag != ACL_USER_OBJ &&
300 tag != ACL_GROUP_OBJ &&
306 #elif defined(HAVE_OSF1_OS)
309 ace = acl->acl_first;
310 count = acl->acl_num;
313 tag = ace->entry->acl_type;
316 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
318 if (tag != ACL_USER_OBJ &&
319 tag != ACL_GROUP_OBJ &&
324 * On Tru64, perm can also contain non-standard bits such as
325 * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
327 if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
340 * Generic wrapper around acl_get_file call.
342 static int generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
349 ostype = bac_to_os_acltype(acltype);
350 acl = acl_get_file(jcr->last_fname, ostype);
352 #if defined(HAVE_IRIX_OS)
354 * From observation, IRIX's acl_get_file() seems to return a
355 * non-NULL acl with a count field of -1 when a file has no ACL
356 * defined, while IRIX's acl_to_text() returns NULL when presented
359 * Checking the count in the acl structure before calling
360 * acl_to_text() lets us avoid error messages about files
361 * with no ACLs, without modifying the flow of the code used for
362 * other operating systems, and it saves making some calls
363 * to acl_to_text() besides.
365 if (acl->acl_cnt <= 0) {
366 pm_strcpy(jcr->acl_data, "");
372 #if !defined(HAVE_DARWIN_OS)
374 * Make sure this is not just a trivial ACL.
376 if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
378 * The ACLs simply reflect the (already known) standard permissions
379 * So we don't send an ACL stream to the SD.
381 pm_strcpy(jcr->acl_data, "");
387 if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
388 len = pm_strcpy(jcr->acl_data, acl_text);
396 Jmsg2(jcr, M_ERROR, 0, _("acl_to_text error on file \"%s\": ERR=%s\n"),
397 jcr->last_fname, be.bstrerror());
398 Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",
399 jcr->last_fname, be.bstrerror());
401 pm_strcpy(jcr->acl_data, "");
408 * Handle errors gracefully.
411 #if defined(BACL_ENOTSUP)
414 * Not supported, just pretend there is nothing to see
416 pm_strcpy(jcr->acl_data, "");
421 Jmsg2(jcr, M_ERROR, 0, _("acl_get_file error on file \"%s\": ERR=%s\n"),
422 jcr->last_fname, be.bstrerror());
423 Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",
424 jcr->last_fname, be.bstrerror());
426 pm_strcpy(jcr->acl_data, "");
432 * Generic wrapper around acl_set_file call.
434 static bool generic_set_acl_on_os(JCR *jcr, bacl_type acltype)
440 * If we get empty default ACLs, clear ACLs now
442 ostype = bac_to_os_acltype(acltype);
443 if (ostype == ACL_TYPE_DEFAULT && strlen(jcr->acl_data) == 0) {
444 if (acl_delete_def_file(jcr->last_fname) == 0) {
448 Jmsg2(jcr, M_ERROR, 0, _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
449 jcr->last_fname, be.bstrerror());
454 acl = acl_from_text(jcr->acl_data);
457 Jmsg2(jcr, M_ERROR, 0, _("acl_from_text error on file \"%s\": ERR=%s\n"),
458 jcr->last_fname, be.bstrerror());
459 Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",
460 jcr->acl_data, jcr->last_fname, be.bstrerror());
466 * FreeBSD always fails acl_valid() - at least on valid input...
467 * As it does the right thing, given valid input, just ignore acl_valid().
469 #ifndef HAVE_FREEBSD_OS
470 if (acl_valid(acl) != 0) {
472 Jmsg2(jcr, M_ERROR, 0, _("ac_valid error on file \"%s\": ERR=%s\n"),
473 jcr->last_fname, be.bstrerror());
474 Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",
475 jcr->acl_data, jcr->last_fname, be.bstrerror());
483 * Restore the ACLs, but don't complain about links which really should
484 * not have attributes, and the file it is linked to may not yet be restored.
485 * This is only true for the old acl streams as in the new implementation we
486 * don't save acls of symlinks (which cannot have acls anyhow)
488 if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
490 Jmsg2(jcr, M_ERROR, 0, _("acl_set_file error on file \"%s\": ERR=%s\n"),
491 jcr->last_fname, be.bstrerror());
492 Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
493 jcr->acl_data, jcr->last_fname, be.bstrerror());
504 * OS specific functions for handling different types of acl streams.
506 #if defined(HAVE_DARWIN_OS)
507 static bool darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
511 #if defined(ACL_TYPE_EXTENDED)
513 * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
514 * and acl_get_file (name, ACL_TYPE_DEFAULT)
515 * always return NULL / EINVAL. There is no point in making
516 * these two useless calls. The real ACL is retrieved through
517 * acl_get_file (name, ACL_TYPE_EXTENDED).
519 * Read access ACLs for files, dirs and links
521 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED)) < 0)
525 * Read access ACLs for files, dirs and links
527 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
531 if (!send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL, len))
539 static bool darwin_parse_acl_stream(JCR *jcr, int stream)
542 case STREAM_UNIX_ACCESS_ACL:
543 case STREAM_ACL_DARWIN_ACCESS_ACL:
544 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
549 #elif defined(HAVE_FREEBSD_OS)
550 static bool freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
555 * Read access ACLs for files, dirs and links
557 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
561 if (!send_acl_stream(jcr, STREAM_ACL_FREEBSD_ACCESS_ACL, len))
566 * Directories can have default ACLs too
568 if (ff_pkt->type == FT_DIREND) {
569 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
573 if (!send_acl_stream(jcr, STREAM_ACL_FREEBSD_DEFAULT_ACL, len))
581 static bool freebsd_parse_acl_stream(JCR *jcr, int stream)
584 case STREAM_UNIX_ACCESS_ACL:
585 case STREAM_ACL_FREEBSD_ACCESS_ACL:
586 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
587 case STREAM_UNIX_DEFAULT_ACL:
588 case STREAM_ACL_FREEBSD_DEFAULT_ACL:
589 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
594 #elif defined(HAVE_IRIX_OS)
595 static bool irix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
600 * Read access ACLs for files, dirs and links
602 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
606 if (!send_acl_stream(jcr, STREAM_ACL_IRIX_ACCESS_ACL, len))
611 * Directories can have default ACLs too
613 if (ff_pkt->type == FT_DIREND) {
614 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
618 if (!send_acl_stream(jcr, STREAM_ACL_IRIX_DEFAULT_ACL, len))
626 static bool irix_parse_acl_stream(JCR *jcr, int stream)
629 case STREAM_UNIX_ACCESS_ACL:
630 case STREAM_ACL_IRIX_ACCESS_ACL:
631 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
632 case STREAM_UNIX_DEFAULT_ACL:
633 case STREAM_ACL_IRIX_DEFAULT_ACL:
634 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
639 #elif defined(HAVE_LINUX_OS)
640 static bool linux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
645 * Read access ACLs for files, dirs and links
647 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
651 if (!send_acl_stream(jcr, STREAM_ACL_LINUX_ACCESS_ACL, len))
656 * Directories can have default ACLs too
658 if (ff_pkt->type == FT_DIREND) {
659 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
663 if (!send_acl_stream(jcr, STREAM_ACL_LINUX_DEFAULT_ACL, len))
671 static bool linux_parse_acl_stream(JCR *jcr, int stream)
674 case STREAM_UNIX_ACCESS_ACL:
675 case STREAM_ACL_LINUX_ACCESS_ACL:
676 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
677 case STREAM_UNIX_DEFAULT_ACL:
678 case STREAM_ACL_LINUX_DEFAULT_ACL:
679 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
684 #elif defined(HAVE_OSF1_OS)
685 static bool tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
690 * Read access ACLs for files, dirs and links
692 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
696 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL, len))
701 * Directories can have default ACLs too
703 if (ff_pkt->type == FT_DIREND) {
704 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
708 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL, len))
713 * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
714 * This is an inherited acl for all subdirs.
715 * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
716 * Section 21.5 Default ACLs
718 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR)) < 0)
722 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL, len))
730 static bool tru64_parse_acl_stream(JCR *jcr, int stream)
733 case STREAM_UNIX_ACCESS_ACL:
734 case STREAM_ACL_TRU64_ACCESS_ACL:
735 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
736 case STREAM_UNIX_DEFAULT_ACL:
737 case STREAM_ACL_TRU64_DEFAULT_ACL:
738 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
739 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
740 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR);
744 #elif defined(HAVE_HPUX_OS)
745 #ifdef HAVE_SYS_ACL_H
748 #error "configure failed to detect availability of sys/acl.h"
754 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
755 * There is no need to store those acls as we already store the stat bits too.
757 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
762 for (n = 0; n < count; n++) {
766 * See if this acl just is the stat mode in acl form.
768 if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
769 (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
770 (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
778 * OS specific functions for handling different types of acl streams.
780 static bool hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
783 struct acl_entry acls[NACLENTRIES];
786 if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
788 #if defined(BACL_ENOTSUP)
791 * Not supported, just pretend there is nothing to see
793 pm_strcpy(jcr->acl_data, "");
798 Jmsg2(jcr, M_ERROR, 0, _("getacl error on file \"%s\": ERR=%s\n"),
799 jcr->last_fname, be.bstrerror());
800 Dmsg2(100, "getacl error file=%s ERR=%s\n",
801 jcr->last_fname, be.bstrerror());
803 pm_strcpy(jcr->acl_data, "");
809 pm_strcpy(jcr->acl_data, "");
813 if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
814 if (acl_is_trivial(n, acls, ff_pkt->statp)) {
816 * The ACLs simply reflect the (already known) standard permissions
817 * So we don't send an ACL stream to the SD.
819 pm_strcpy(jcr->acl_data, "");
823 if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
824 len = pm_strcpy(jcr->acl_data, acl_text);
825 actuallyfree(acl_text);
827 return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY, len);
831 Jmsg2(jcr, M_ERROR, 0, _("acltostr error on file \"%s\": ERR=%s\n"),
832 jcr->last_fname, be.bstrerror());
833 Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",
834 jcr->acl_data, jcr->last_fname, be.bstrerror());
842 static bool hpux_parse_acl_stream(JCR *jcr, int stream)
845 struct acl_entry acls[NACLENTRIES];
847 n = strtoacl(jcr->acl_data, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
850 Jmsg2(jcr, M_ERROR, 0, _("strtoacl error on file \"%s\": ERR=%s\n"),
851 jcr->last_fname, be.bstrerror());
852 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
853 jcr->acl_data, jcr->last_fname, be.bstrerror());
857 if (strtoacl(jcr->acl_data, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
859 Jmsg2(jcr, M_ERROR, 0, _("strtoacl error on file \"%s\": ERR=%s\n"),
860 jcr->last_fname, be.bstrerror());
861 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
862 jcr->acl_data, jcr->last_fname, be.bstrerror());
867 * Restore the ACLs, but don't complain about links which really should
868 * not have attributes, and the file it is linked to may not yet be restored.
869 * This is only true for the old acl streams as in the new implementation we
870 * don't save acls of symlinks (which cannot have acls anyhow)
872 if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
874 Jmsg2(jcr, M_ERROR, 0, _("setacl error on file \"%s\": ERR=%s\n"),
875 jcr->last_fname, be.bstrerror());
876 Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
877 jcr->acl_data, jcr->last_fname, be.bstrerror());
885 #elif defined(HAVE_SUN_OS)
886 #ifdef HAVE_SYS_ACL_H
889 #error "configure failed to detect availability of sys/acl.h"
892 #if defined(HAVE_EXTENDED_ACL)
894 * We define some internals of the Solaris acl libs here as those
895 * are not exposed yet. Probably because they want us to see the
896 * acls as opague data. But as we need to support different platforms
897 * and versions of Solaris we need to expose some data to be able
898 * to determine the type of acl used to stuff it into the correct
899 * data stream. I know this is far from portable, but maybe the
900 * propper interface is exposed later on and we can get ride of
901 * this kludge. Newer versions of Solaris include sys/acl_impl.h
902 * which has implementation details of acls, if thats included we
903 * don't have to define it ourself.
905 #if !defined(_SYS_ACL_IMPL_H)
906 typedef enum acl_type {
913 * Two external references to functions in the libsec library function not in current include files.
916 int acl_type(acl_t *);
917 char *acl_strerror(int);
921 * As the new libsec interface with acl_totext and acl_fromtext also handles
922 * the old format from acltotext we can use the new functions even
923 * for acls retrieved and stored in the database with older fd versions. If the
924 * new interface is not defined (Solaris 9 and older we fall back to the old code)
926 static bool solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
928 int acl_enabled, len, flags;
931 bool stream_status = false;
934 * See if filesystem supports acls.
936 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
937 switch (acl_enabled) {
939 pm_strcpy(jcr->acl_data, "");
943 Jmsg2(jcr, M_ERROR, 0, _("pathconf error on file \"%s\": ERR=%s\n"),
944 jcr->last_fname, strerror(errno));
945 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
946 jcr->last_fname, strerror(errno));
954 * Get ACL info: don't bother allocating space if there is only a trivial ACL.
956 if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
957 Jmsg2(jcr, M_ERROR, 0, _("acl_get error on file \"%s\": ERR=%s\n"),
958 jcr->last_fname, acl_strerror(errno));
959 Dmsg2(100, "acl_get error file=%s ERR=%s\n",
960 jcr->last_fname, acl_strerror(errno));
967 * The ACLs simply reflect the (already known) standard permissions
968 * So we don't send an ACL stream to the SD.
970 pm_strcpy(jcr->acl_data, "");
974 #if defined(ACL_SID_FMT)
976 * New format flag added in newer Solaris versions.
978 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
980 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
981 #endif /* ACL_SID_FMT */
983 if ((acl_text = acl_totext(aclp, flags)) != NULL) {
984 len = pm_strcpy(jcr->acl_data, acl_text);
985 actuallyfree(acl_text);
987 switch (acl_type(aclp)) {
989 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT, len);
992 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE, len);
1001 return stream_status;
1004 static bool solaris_parse_acl_stream(JCR *jcr, int stream)
1007 int acl_enabled, error;
1010 case STREAM_UNIX_ACCESS_ACL:
1011 case STREAM_ACL_SOLARIS_ACLENT:
1012 case STREAM_ACL_SOLARIS_ACE:
1014 * First make sure the filesystem supports acls.
1016 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1017 switch (acl_enabled) {
1019 Jmsg1(jcr, M_ERROR, 0, _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
1024 Jmsg2(jcr, M_ERROR, 0, _("pathconf error on file \"%s\": ERR=%s\n"),
1025 jcr->last_fname, strerror(errno));
1026 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1027 jcr->acl_data, jcr->last_fname, strerror(errno));
1032 * On a filesystem with ACL support make sure this particilar ACL type can be restored.
1035 case STREAM_ACL_SOLARIS_ACLENT:
1037 * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
1039 if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
1040 Jmsg1(jcr, M_ERROR, 0, _("Trying to restore acl on file \"%s\" on filesystem without aclent acl support\n"),
1045 case STREAM_ACL_SOLARIS_ACE:
1047 * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
1049 if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
1050 Jmsg1(jcr, M_ERROR, 0, _("Trying to restore acl on file \"%s\" on filesystem without ace acl support\n"),
1057 * Stream id which doesn't describe the type of acl which is encoded.
1064 if ((error = acl_fromtext(jcr->acl_data, &aclp)) != 0) {
1065 Jmsg2(jcr, M_ERROR, 0, _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1066 jcr->last_fname, acl_strerror(error));
1067 Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",
1068 jcr->acl_data, jcr->last_fname, acl_strerror(error));
1073 * Validate that the conversion gave us the correct acl type.
1076 case STREAM_ACL_SOLARIS_ACLENT:
1077 if (acl_type(aclp) != ACLENT_T) {
1078 Jmsg1(jcr, M_ERROR, 0, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1083 case STREAM_ACL_SOLARIS_ACE:
1084 if (acl_type(aclp) != ACE_T) {
1085 Jmsg1(jcr, M_ERROR, 0, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1092 * Stream id which doesn't describe the type of acl which is encoded.
1098 * Restore the ACLs, but don't complain about links which really should
1099 * not have attributes, and the file it is linked to may not yet be restored.
1100 * This is only true for the old acl streams as in the new implementation we
1101 * don't save acls of symlinks (which cannot have acls anyhow)
1103 if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1104 Jmsg2(jcr, M_ERROR, 0, _("acl_set error on file \"%s\": ERR=%s\n"),
1105 jcr->last_fname, acl_strerror(error));
1106 Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",
1107 jcr->acl_data, jcr->last_fname, acl_strerror(error));
1117 } /* end switch (stream) */
1120 #else /* HAVE_EXTENDED_ACL */
1123 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1124 * There is no need to store those acls as we already store the stat bits too.
1126 static bool acl_is_trivial(int count, aclent_t *entries)
1131 for (n = 0; n < count; n++) {
1134 if (!(ace->a_type == USER_OBJ ||
1135 ace->a_type == GROUP_OBJ ||
1136 ace->a_type == OTHER_OBJ ||
1137 ace->a_type == CLASS_OBJ))
1145 * OS specific functions for handling different types of acl streams.
1147 static bool solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt);
1153 n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1154 if (n < MIN_ACL_ENTRIES) {
1157 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1158 if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1159 if (acl_is_trivial(n, acls)) {
1161 * The ACLs simply reflect the (already known) standard permissions
1162 * So we don't send an ACL stream to the SD.
1165 pm_strcpy(jcr->acl_data, "");
1169 if ((acl_text = acltotext(acls, n)) != NULL) {
1170 len = pm_strcpy(jcr->acl_data, acl_text);
1171 actuallyfree(acl_text);
1174 return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT, len);
1178 Jmsg2(jcr, M_ERROR, 0, _("acltotext error on file \"%s\": ERR=%s\n"),
1179 jcr->last_fname, be.bstrerror());
1180 Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",
1181 jcr->acl_data, jcr->last_fname, be.bstrerror());
1188 static bool solaris_parse_acl_stream(JCR *jcr, int stream)
1193 acls = aclfromtext(jcr->acl_data, &n);
1196 Jmsg2(jcr, M_ERROR, 0, _("aclfromtext error on file \"%s\": ERR=%s\n"),
1197 jcr->last_fname, be.bstrerror());
1198 Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",
1199 jcr->acl_data, jcr->last_fname, be.bstrerror());
1205 * Restore the ACLs, but don't complain about links which really should
1206 * not have attributes, and the file it is linked to may not yet be restored.
1208 if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
1210 Jmsg2(jcr, M_ERROR, 0, _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
1211 jcr->last_fname, be.bstrerror());
1212 Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
1213 jcr->acl_data, jcr->last_fname, be.bstrerror());
1223 #endif /* HAVE_EXTENDED_ACL */
1224 #endif /* HAVE_SUN_OS */
1227 * Entry points when compiled with support for ACLs on a supported platform.
1231 * Read and send an ACL for the last encountered file.
1233 bool build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1236 * Call the appropriate function, the ifdefs make sure the proper code is compiled.
1238 #if defined(HAVE_AIX_OS)
1239 return aix_build_acl_streams(jcr, ff_pkt);
1240 #elif defined(HAVE_DARWIN_OS)
1241 return darwin_build_acl_streams(jcr, ff_pkt);
1242 #elif defined(HAVE_FREEBSD_OS)
1243 return freebsd_build_acl_streams(jcr, ff_pkt);
1244 #elif defined(HAVE_HPUX_OS)
1245 return hpux_build_acl_streams(jcr, ff_pkt);
1246 #elif defined(HAVE_IRIX_OS)
1247 return irix_build_acl_streams(jcr, ff_pkt);
1248 #elif defined(HAVE_LINUX_OS)
1249 return linux_build_acl_streams(jcr, ff_pkt);
1250 #elif defined(HAVE_OSF1_OS)
1251 return tru64_build_acl_streams(jcr, ff_pkt);
1252 #elif defined(HAVE_SUN_OS)
1253 return solaris_build_acl_streams(jcr, ff_pkt);
1257 bool parse_acl_stream(JCR *jcr, int stream)
1260 * Based on the stream being passed in dispatch to the right function
1261 * for parsing and restoring a specific acl. The platform determines
1262 * which streams are recognized and parsed and which are handled by
1263 * the default case and ignored. The old STREAM_UNIX_ACCESS_ACL and
1264 * STREAM_UNIX_DEFAULT_ACL is handled as a legacy stream by each function.
1265 * As only one of the platform defines is true per compile we never end
1266 * up with duplicate switch values.
1269 #if defined(HAVE_AIX_OS)
1270 case STREAM_UNIX_ACCESS_ACL:
1271 case STREAM_UNIX_DEFAULT_ACL:
1272 case STREAM_ACL_AIX_TEXT:
1273 return aix_parse_acl_stream(jcr, stream);
1274 #elif defined(HAVE_DARWIN_OS)
1275 case STREAM_UNIX_ACCESS_ACL:
1276 case STREAM_ACL_DARWIN_ACCESS_ACL:
1277 return darwin_parse_acl_stream(jcr, stream);
1278 #elif defined(HAVE_FREEBSD_OS)
1279 case STREAM_UNIX_ACCESS_ACL:
1280 case STREAM_UNIX_DEFAULT_ACL:
1281 case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1282 case STREAM_ACL_FREEBSD_ACCESS_ACL:
1283 return freebsd_parse_acl_stream(jcr, stream);
1284 #elif defined(HAVE_HPUX_OS)
1285 case STREAM_UNIX_ACCESS_ACL:
1286 case STREAM_ACL_HPUX_ACL_ENTRY:
1287 return hpux_parse_acl_stream(jcr, stream);
1288 #elif defined(HAVE_IRIX_OS)
1289 case STREAM_UNIX_ACCESS_ACL:
1290 case STREAM_UNIX_DEFAULT_ACL:
1291 case STREAM_ACL_IRIX_DEFAULT_ACL:
1292 case STREAM_ACL_IRIX_ACCESS_ACL:
1293 return irix_parse_acl_stream(jcr, stream);
1294 #elif defined(HAVE_LINUX_OS)
1295 case STREAM_UNIX_ACCESS_ACL:
1296 case STREAM_UNIX_DEFAULT_ACL:
1297 case STREAM_ACL_LINUX_DEFAULT_ACL:
1298 case STREAM_ACL_LINUX_ACCESS_ACL:
1299 return linux_parse_acl_stream(jcr, stream);
1300 #elif defined(HAVE_OSF1_OS)
1301 case STREAM_UNIX_ACCESS_ACL:
1302 case STREAM_UNIX_DEFAULT_ACL:
1303 case STREAM_ACL_TRU64_DEFAULT_ACL:
1304 case STREAM_ACL_TRU64_ACCESS_ACL:
1305 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
1306 return tru64_parse_acl_stream(jcr, stream);
1307 #elif defined(HAVE_SUN_OS)
1308 case STREAM_UNIX_ACCESS_ACL:
1309 case STREAM_ACL_SOLARIS_ACLENT:
1310 #if defined(HAVE_EXTENDED_ACL)
1311 case STREAM_ACL_SOLARIS_ACE:
1313 return solaris_parse_acl_stream(jcr, stream);
1317 * Issue a warning and discard the message. But pretend the restore was ok.
1319 Qmsg2(jcr, M_WARNING, 0,
1320 _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
1321 jcr->last_fname, stream);
1323 } /* end switch (stream) */