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);
260 return true; /* Allow to compile -- KES */
262 #else /* FreeBSD, IRIX, OSF1, Linux */
263 static bool acl_is_trivial(acl_t acl)
266 * acl is trivial if it has only the following entries:
273 #if defined(HAVE_FREEBSD_OS) || defined(HAVE_LINUX_OS)
276 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
277 while (entry_available == 1) {
279 * Get the tag type of this acl entry.
280 * If we fail to get the tagtype we call the acl non-trivial.
282 if (acl_get_tag_type(ace, &tag) < 0)
286 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
288 if (tag != ACL_USER_OBJ &&
289 tag != ACL_GROUP_OBJ &&
293 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
297 #elif defined(HAVE_IRIX_OS)
300 for (n = 0; n < acl->acl_cnt; n++) {
301 ace = &acl->acl_entry[n];
305 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
307 if (tag != ACL_USER_OBJ &&
308 tag != ACL_GROUP_OBJ &&
314 #elif defined(HAVE_OSF1_OS)
317 ace = acl->acl_first;
318 count = acl->acl_num;
321 tag = ace->entry->acl_type;
324 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
326 if (tag != ACL_USER_OBJ &&
327 tag != ACL_GROUP_OBJ &&
332 * On Tru64, perm can also contain non-standard bits such as
333 * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
335 if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
348 * Generic wrapper around acl_get_file call.
350 static int generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
357 ostype = bac_to_os_acltype(acltype);
358 acl = acl_get_file(jcr->last_fname, ostype);
360 #if defined(HAVE_IRIX_OS)
362 * From observation, IRIX's acl_get_file() seems to return a
363 * non-NULL acl with a count field of -1 when a file has no ACL
364 * defined, while IRIX's acl_to_text() returns NULL when presented
367 * Checking the count in the acl structure before calling
368 * acl_to_text() lets us avoid error messages about files
369 * with no ACLs, without modifying the flow of the code used for
370 * other operating systems, and it saves making some calls
371 * to acl_to_text() besides.
373 if (acl->acl_cnt <= 0) {
374 pm_strcpy(jcr->acl_data, "");
381 * Make sure this is not just a trivial ACL.
383 if ((acltype == BACL_TYPE_ACCESS ||
384 acltype == BACL_TYPE_EXTENDED) &&
385 acl_is_trivial(acl)) {
387 * The ACLs simply reflect the (already known) standard permissions
388 * So we don't send an ACL stream to the SD.
390 pm_strcpy(jcr->acl_data, "");
395 if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
396 len = pm_strcpy(jcr->acl_data, acl_text);
404 Jmsg2(jcr, M_ERROR, 0, _("acl_to_text error on file \"%s\": ERR=%s\n"),
405 jcr->last_fname, be.bstrerror());
406 Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",
407 jcr->last_fname, be.bstrerror());
409 pm_strcpy(jcr->acl_data, "");
416 * Handle errors gracefully.
419 #if defined(BACL_ENOTSUP)
422 * Not supported, just pretend there is nothing to see
424 pm_strcpy(jcr->acl_data, "");
429 Jmsg2(jcr, M_ERROR, 0, _("acl_get_file error on file \"%s\": ERR=%s\n"),
430 jcr->last_fname, be.bstrerror());
431 Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",
432 jcr->last_fname, be.bstrerror());
434 pm_strcpy(jcr->acl_data, "");
440 * Generic wrapper around acl_set_file call.
442 static bool generic_set_acl_on_os(JCR *jcr, bacl_type acltype)
448 * If we get empty default ACLs, clear ACLs now
450 ostype = bac_to_os_acltype(acltype);
451 if (ostype == ACL_TYPE_DEFAULT && strlen(jcr->acl_data) == 0) {
452 if (acl_delete_def_file(jcr->last_fname) == 0) {
456 Jmsg2(jcr, M_ERROR, 0, _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
457 jcr->last_fname, be.bstrerror());
462 acl = acl_from_text(jcr->acl_data);
465 Jmsg2(jcr, M_ERROR, 0, _("acl_from_text error on file \"%s\": ERR=%s\n"),
466 jcr->last_fname, be.bstrerror());
467 Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",
468 jcr->acl_data, jcr->last_fname, be.bstrerror());
474 * FreeBSD always fails acl_valid() - at least on valid input...
475 * As it does the right thing, given valid input, just ignore acl_valid().
477 #ifndef HAVE_FREEBSD_OS
478 if (acl_valid(acl) != 0) {
480 Jmsg2(jcr, M_ERROR, 0, _("ac_valid error on file \"%s\": ERR=%s\n"),
481 jcr->last_fname, be.bstrerror());
482 Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",
483 jcr->acl_data, jcr->last_fname, be.bstrerror());
491 * Restore the ACLs, but don't complain about links which really should
492 * not have attributes, and the file it is linked to may not yet be restored.
493 * This is only true for the old acl streams as in the new implementation we
494 * don't save acls of symlinks (which cannot have acls anyhow)
496 if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
498 Jmsg2(jcr, M_ERROR, 0, _("acl_set_file error on file \"%s\": ERR=%s\n"),
499 jcr->last_fname, be.bstrerror());
500 Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
501 jcr->acl_data, jcr->last_fname, be.bstrerror());
512 * OS specific functions for handling different types of acl streams.
514 #if defined(HAVE_DARWIN_OS)
515 static bool darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
519 #if defined(ACL_TYPE_EXTENDED)
521 * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
522 * and acl_get_file (name, ACL_TYPE_DEFAULT)
523 * always return NULL / EINVAL. There is no point in making
524 * these two useless calls. The real ACL is retrieved through
525 * acl_get_file (name, ACL_TYPE_EXTENDED).
527 * Read access ACLs for files, dirs and links
529 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED)) < 0)
533 * Read access ACLs for files, dirs and links
535 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
540 if (!send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL_T, len))
547 static bool darwin_parse_acl_stream(JCR *jcr, int stream)
550 case STREAM_UNIX_ACCESS_ACL:
551 case STREAM_ACL_DARWIN_ACCESS_ACL_T:
552 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
557 #elif defined(HAVE_FREEBSD_OS)
558 static bool freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
563 * Read access ACLs for files, dirs and links
565 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
569 if (!send_acl_stream(jcr, STREAM_ACL_FREEBSD_ACCESS_ACL_T, len))
574 * Directories can have default ACLs too
576 if (ff_pkt->type == FT_DIREND) {
577 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
581 if (!send_acl_stream(jcr, STREAM_ACL_FREEBSD_DEFAULT_ACL_T, len))
589 static bool freebsd_parse_acl_stream(JCR *jcr, int stream)
592 case STREAM_UNIX_ACCESS_ACL:
593 case STREAM_ACL_FREEBSD_ACCESS_ACL_T:
594 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
595 case STREAM_UNIX_DEFAULT_ACL:
596 case STREAM_ACL_FREEBSD_DEFAULT_ACL_T:
597 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
602 #elif defined(HAVE_IRIX_OS)
603 static bool irix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
608 * Read access ACLs for files, dirs and links
610 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
614 if (!send_acl_stream(jcr, STREAM_ACL_IRIX_ACCESS_ACL_T, len))
619 * Directories can have default ACLs too
621 if (ff_pkt->type == FT_DIREND) {
622 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
626 if (!send_acl_stream(jcr, STREAM_ACL_IRIX_DEFAULT_ACL_T, len))
634 static bool irix_parse_acl_stream(JCR *jcr, int stream)
637 case STREAM_UNIX_ACCESS_ACL:
638 case STREAM_ACL_IRIX_ACCESS_ACL_T:
639 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
640 case STREAM_UNIX_DEFAULT_ACL:
641 case STREAM_ACL_IRIX_DEFAULT_ACL_T:
642 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
647 #elif defined(HAVE_LINUX_OS)
648 static bool linux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
653 * Read access ACLs for files, dirs and links
655 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
659 if (!send_acl_stream(jcr, STREAM_ACL_LINUX_ACCESS_ACL_T, len))
664 * Directories can have default ACLs too
666 if (ff_pkt->type == FT_DIREND) {
667 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
671 if (!send_acl_stream(jcr, STREAM_ACL_LINUX_DEFAULT_ACL_T, len))
679 static bool linux_parse_acl_stream(JCR *jcr, int stream)
682 case STREAM_UNIX_ACCESS_ACL:
683 case STREAM_ACL_LINUX_ACCESS_ACL_T:
684 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
685 case STREAM_UNIX_DEFAULT_ACL:
686 case STREAM_ACL_LINUX_DEFAULT_ACL_T:
687 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
692 #elif defined(HAVE_OSF1_OS)
693 static bool tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
698 * Read access ACLs for files, dirs and links
700 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
704 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL_T, len))
709 * Directories can have default ACLs too
711 if (ff_pkt->type == FT_DIREND) {
712 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
716 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL_T, len))
721 * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
722 * This is an inherited acl for all subdirs.
723 * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
724 * Section 21.5 Default ACLs
726 if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR)) < 0)
730 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL_T, len))
738 static bool tru64_parse_acl_stream(JCR *jcr, int stream)
741 case STREAM_UNIX_ACCESS_ACL:
742 case STREAM_ACL_TRU64_ACCESS_ACL_T:
743 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
744 case STREAM_UNIX_DEFAULT_ACL:
745 case STREAM_ACL_TRU64_DEFAULT_ACL_T:
746 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
747 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL_T:
748 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR);
752 #elif defined(HAVE_HPUX_OS)
753 #ifdef HAVE_SYS_ACL_H
756 #error "configure failed to detect availability of sys/acl.h"
762 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
763 * There is no need to store those acls as we already store the stat bits too.
765 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
770 for (n = 0; n < count; n++) {
774 * See if this acl just is the stat mode in acl form.
776 if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
777 (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
778 (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
786 * OS specific functions for handling different types of acl streams.
788 static bool hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
791 struct acl_entry acls[NACLENTRIES];
794 if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
796 #if defined(BACL_ENOTSUP)
799 * Not supported, just pretend there is nothing to see
801 pm_strcpy(jcr->acl_data, "");
806 Jmsg2(jcr, M_ERROR, 0, _("getacl error on file \"%s\": ERR=%s\n"),
807 jcr->last_fname, be.bstrerror());
808 Dmsg2(100, "getacl error file=%s ERR=%s\n",
809 jcr->last_fname, be.bstrerror());
811 pm_strcpy(jcr->acl_data, "");
817 pm_strcpy(jcr->acl_data, "");
821 if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
822 if (acl_is_trivial(n, acls, ff_pkt->statp)) {
824 * The ACLs simply reflect the (already known) standard permissions
825 * So we don't send an ACL stream to the SD.
827 pm_strcpy(jcr->acl_data, "");
831 if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
832 len = pm_strcpy(jcr->acl_data, acl_text);
833 actuallyfree(acl_text);
835 return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY, len);
839 Jmsg2(jcr, M_ERROR, 0, _("acltostr error on file \"%s\": ERR=%s\n"),
840 jcr->last_fname, be.bstrerror());
841 Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",
842 jcr->acl_data, jcr->last_fname, be.bstrerror());
850 static bool hpux_parse_acl_stream(JCR *jcr, int stream)
853 struct acl_entry acls[NACLENTRIES];
855 n = strtoacl(jcr->acl_data, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
858 Jmsg2(jcr, M_ERROR, 0, _("strtoacl error on file \"%s\": ERR=%s\n"),
859 jcr->last_fname, be.bstrerror());
860 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
861 jcr->acl_data, jcr->last_fname, be.bstrerror());
865 if (strtoacl(jcr->acl_data, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
867 Jmsg2(jcr, M_ERROR, 0, _("strtoacl error on file \"%s\": ERR=%s\n"),
868 jcr->last_fname, be.bstrerror());
869 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
870 jcr->acl_data, jcr->last_fname, be.bstrerror());
875 * Restore the ACLs, but don't complain about links which really should
876 * not have attributes, and the file it is linked to may not yet be restored.
877 * This is only true for the old acl streams as in the new implementation we
878 * don't save acls of symlinks (which cannot have acls anyhow)
880 if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
882 Jmsg2(jcr, M_ERROR, 0, _("setacl error on file \"%s\": ERR=%s\n"),
883 jcr->last_fname, be.bstrerror());
884 Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
885 jcr->acl_data, jcr->last_fname, be.bstrerror());
893 #elif defined(HAVE_SUN_OS)
894 #ifdef HAVE_SYS_ACL_H
897 #error "configure failed to detect availability of sys/acl.h"
900 #if defined(HAVE_EXTENDED_ACL)
902 * We define some internals of the Solaris acl libs here as those
903 * are not exposed yet. Probably because they want us to see the
904 * acls as opague data. But as we need to support different platforms
905 * and versions of Solaris we need to expose some data to be able
906 * to determine the type of acl used to stuff it into the correct
907 * data stream. I know this is far from portable, but maybe the
908 * propper interface is exposed later on and we can get ride of
909 * this kludge. Newer versions of Solaris include sys/acl_impl.h
910 * which has implementation details of acls, if thats included we
911 * don't have to define it ourself.
913 #if !defined(_SYS_ACL_IMPL_H)
914 typedef enum acl_type {
921 * Two external references to functions in the libsec library function not in current include files.
924 int acl_type(acl_t *);
925 char *acl_strerror(int);
929 * As the new libsec interface with acl_totext and acl_fromtext also handles
930 * the old format from acltotext we can use the new functions even
931 * for acls retrieved and stored in the database with older fd versions. If the
932 * new interface is not defined (Solaris 9 and older we fall back to the old code)
934 static bool solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
939 bool stream_status = false;
942 * Get ACL info: don't bother allocating space if there is only a trivial ACL.
944 if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
946 #if defined(BACL_ENOTSUP)
949 * Not supported, just pretend there is nothing to see
951 pm_strcpy(jcr->acl_data, "");
955 Jmsg2(jcr, M_ERROR, 0, _("acl_get error on file \"%s\": ERR=%s\n"),
956 jcr->last_fname, acl_strerror(errno));
957 Dmsg2(100, "acl_get error file=%s ERR=%s\n",
958 jcr->last_fname, acl_strerror(errno));
966 * The ACLs simply reflect the (already known) standard permissions
967 * So we don't send an ACL stream to the SD.
969 pm_strcpy(jcr->acl_data, "");
973 #if defined(ACL_SID_FMT)
975 * New format flag added in newer Solaris versions.
977 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
979 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
980 #endif /* ACL_SID_FMT */
982 if ((acl_text = acl_totext(aclp, flags)) != NULL) {
983 len = pm_strcpy(jcr->acl_data, acl_text);
984 actuallyfree(acl_text);
986 switch (acl_type(aclp)) {
988 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT_T, len);
991 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE_T, len);
1000 return stream_status;
1003 static bool solaris_parse_acl_stream(JCR *jcr, int stream)
1009 case STREAM_UNIX_ACCESS_ACL:
1010 case STREAM_ACL_SOLARIS_ACLENT_T:
1011 case STREAM_ACL_SOLARIS_ACE_T:
1012 if ((error = acl_fromtext(jcr->acl_data, &aclp)) != 0) {
1013 Jmsg2(jcr, M_ERROR, 0, _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1014 jcr->last_fname, acl_strerror(error));
1015 Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",
1016 jcr->acl_data, jcr->last_fname, acl_strerror(error));
1021 * Validate that the conversion gave us the correct acl type.
1024 case STREAM_ACL_SOLARIS_ACLENT_T:
1025 if (acl_type(aclp) != ACLENT_T) {
1026 Jmsg1(jcr, M_ERROR, 0, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1030 case STREAM_ACL_SOLARIS_ACE_T:
1031 if (acl_type(aclp) != ACE_T) {
1032 Jmsg1(jcr, M_ERROR, 0, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1038 * Stream id which doesn't describe the type of acl which is encoded.
1044 * Restore the ACLs, but don't complain about links which really should
1045 * not have attributes, and the file it is linked to may not yet be restored.
1046 * This is only true for the old acl streams as in the new implementation we
1047 * don't save acls of symlinks (which cannot have acls anyhow)
1049 if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1050 Jmsg2(jcr, M_ERROR, 0, _("acl_set error on file \"%s\": ERR=%s\n"),
1051 jcr->last_fname, acl_strerror(error));
1052 Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",
1053 jcr->acl_data, jcr->last_fname, acl_strerror(error));
1063 } /* end switch (stream) */
1066 #else /* HAVE_EXTENDED_ACL */
1069 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1070 * There is no need to store those acls as we already store the stat bits too.
1072 static bool acl_is_trivial(int count, aclent_t *entries)
1077 for (n = 0; n < count; n++) {
1080 if (!(ace->a_type == USER_OBJ ||
1081 ace->a_type == GROUP_OBJ ||
1082 ace->a_type == OTHER_OBJ ||
1083 ace->a_type == CLASS_OBJ))
1091 * OS specific functions for handling different types of acl streams.
1093 static bool solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt);
1099 n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1100 if (n < MIN_ACL_ENTRIES) {
1103 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1104 if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1105 if (acl_is_trivial(n, acls)) {
1107 * The ACLs simply reflect the (already known) standard permissions
1108 * So we don't send an ACL stream to the SD.
1111 pm_strcpy(jcr->acl_data, "");
1115 if ((acl_text = acltotext(acls, n)) != NULL) {
1116 len = pm_strcpy(jcr->acl_data, acl_text);
1117 actuallyfree(acl_text);
1120 return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT_T, len);
1124 Jmsg2(jcr, M_ERROR, 0, _("acltotext error on file \"%s\": ERR=%s\n"),
1125 jcr->last_fname, be.bstrerror());
1126 Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",
1127 jcr->acl_data, jcr->last_fname, be.bstrerror());
1134 static bool solaris_parse_acl_stream(JCR *jcr, int stream)
1139 acls = aclfromtext(jcr->acl_data, &n);
1142 Jmsg2(jcr, M_ERROR, 0, _("aclfromtext error on file \"%s\": ERR=%s\n"),
1143 jcr->last_fname, be.bstrerror());
1144 Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",
1145 jcr->acl_data, jcr->last_fname, be.bstrerror());
1151 * Restore the ACLs, but don't complain about links which really should
1152 * not have attributes, and the file it is linked to may not yet be restored.
1154 if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
1156 Jmsg2(jcr, M_ERROR, 0, _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
1157 jcr->last_fname, be.bstrerror());
1158 Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
1159 jcr->acl_data, jcr->last_fname, be.bstrerror());
1169 #endif /* HAVE_EXTENDED_ACL */
1170 #endif /* HAVE_SUN_OS */
1173 * Entry points when compiled with support for ACLs on a supported platform.
1177 * Read and send an ACL for the last encountered file.
1179 bool build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1182 * Call the appropriate function, the ifdefs make sure the proper code is compiled.
1184 #if defined(HAVE_AIX_OS)
1185 return aix_build_acl_streams(jcr, ff_pkt);
1186 #elif defined(HAVE_DARWIN_OS)
1187 return darwin_build_acl_streams(jcr, ff_pkt);
1188 #elif defined(HAVE_FREEBSD_OS)
1189 return freebsd_build_acl_streams(jcr, ff_pkt);
1190 #elif defined(HAVE_HPUX_OS)
1191 return hpux_build_acl_streams(jcr, ff_pkt);
1192 #elif defined(HAVE_IRIX_OS)
1193 return irix_build_acl_streams(jcr, ff_pkt);
1194 #elif defined(HAVE_LINUX_OS)
1195 return linux_build_acl_streams(jcr, ff_pkt);
1196 #elif defined(HAVE_OSF1_OS)
1197 return tru64_build_acl_streams(jcr, ff_pkt);
1198 #elif defined(HAVE_SUN_OS)
1199 return solaris_build_acl_streams(jcr, ff_pkt);
1203 bool parse_acl_stream(JCR *jcr, int stream)
1206 * Based on the stream being passed in dispatch to the right function
1207 * for parsing and restoring a specific acl. The platform determines
1208 * which streams are recognized and parsed and which are handled by
1209 * the default case and ignored. The old STREAM_UNIX_ACCESS_ACL and
1210 * STREAM_UNIX_DEFAULT_ACL is handled as a legacy stream by each function.
1211 * As only one of the platform defines is true per compile we never end
1212 * up with duplicate switch values.
1215 #if defined(HAVE_AIX_OS)
1216 case STREAM_UNIX_ACCESS_ACL:
1217 case STREAM_UNIX_DEFAULT_ACL:
1218 case STREAM_ACL_AIX_TEXT:
1219 return aix_parse_acl_stream(jcr, stream);
1220 #elif defined(HAVE_DARWIN_OS)
1221 case STREAM_UNIX_ACCESS_ACL:
1222 case STREAM_ACL_DARWIN_ACCESS_ACL_T:
1223 return darwin_parse_acl_stream(jcr, stream);
1224 #elif defined(HAVE_FREEBSD_OS)
1225 case STREAM_UNIX_ACCESS_ACL:
1226 case STREAM_UNIX_DEFAULT_ACL:
1227 case STREAM_ACL_FREEBSD_DEFAULT_ACL_T:
1228 case STREAM_ACL_FREEBSD_ACCESS_ACL_T:
1229 return freebsd_parse_acl_stream(jcr, stream);
1230 #elif defined(HAVE_HPUX_OS)
1231 case STREAM_UNIX_ACCESS_ACL:
1232 case STREAM_ACL_HPUX_ACL_ENTRY:
1233 return hpux_parse_acl_stream(jcr, stream);
1234 #elif defined(HAVE_IRIX_OS)
1235 case STREAM_UNIX_ACCESS_ACL:
1236 case STREAM_UNIX_DEFAULT_ACL:
1237 case STREAM_ACL_IRIX_DEFAULT_ACL_T:
1238 case STREAM_ACL_IRIX_ACCESS_ACL_T:
1239 return irix_parse_acl_stream(jcr, stream);
1240 #elif defined(HAVE_LINUX_OS)
1241 case STREAM_UNIX_ACCESS_ACL:
1242 case STREAM_UNIX_DEFAULT_ACL:
1243 case STREAM_ACL_LINUX_DEFAULT_ACL_T:
1244 case STREAM_ACL_LINUX_ACCESS_ACL_T:
1245 return linux_parse_acl_stream(jcr, stream);
1246 #elif defined(HAVE_OSF1_OS)
1247 case STREAM_UNIX_ACCESS_ACL:
1248 case STREAM_UNIX_DEFAULT_ACL:
1249 case STREAM_ACL_TRU64_DEFAULT_ACL_T:
1250 case STREAM_ACL_TRU64_ACCESS_ACL_T:
1251 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL_T:
1252 return tru64_parse_acl_stream(jcr, stream);
1253 #elif defined(HAVE_SUN_OS)
1254 case STREAM_UNIX_ACCESS_ACL:
1255 case STREAM_ACL_SOLARIS_ACLENT_T:
1256 #if defined(HAVE_EXTENDED_ACL)
1257 case STREAM_ACL_SOLARIS_ACE_T:
1259 return solaris_parse_acl_stream(jcr, stream);
1263 * Issue a warning and discard the message. But pretend the restore was ok.
1265 Qmsg2(jcr, M_WARNING, 0,
1266 _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
1267 jcr->last_fname, stream);
1269 } /* end switch (stream) */