2 Bacula® - The Network Backup Solution
4 Copyright (C) 2004-2012 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 three of the GNU Affero 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 Affero 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 * Currently we support the following OSes:
32 * - AIX (pre-5.3 and post 5.3 acls, acl_get and aclx_get interface)
34 * - FreeBSD (POSIX and NFSv4/ZFS acls)
38 * - Solaris (POSIX and NFSv4/ZFS acls)
41 * We handle two different types of ACLs: access and default ACLS.
42 * On most systems that support default ACLs they only apply to directories.
44 * On some systems (eg. linux and FreeBSD) we must obtain the two ACLs
45 * independently, while others (eg. Solaris) provide both in one call.
47 * The Filed saves ACLs in their native format and uses different streams
48 * for all different platforms. Currently we only allow ACLs to be restored
49 * which were saved in the native format of the platform they are extracted
50 * on. Later on we might add conversion functions for mapping from one
51 * platform to an other or allow restores of systems that use the same
54 * Its also interesting to see what the exact format of acl text is on
55 * certain platforms and if they use they same encoding we might allow
56 * different platform streams to be decoded on an other similar platform.
58 * Original written by Preben 'Peppe' Guldberg, December 2004
59 * Major rewrite by Marco van Wieringen, November 2008
60 * Major overhaul by Marco van Wieringen, January 2012
66 #if !defined(HAVE_ACL)
68 * Entry points when compiled without support for ACLs or on an unsupported platform.
70 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
72 return bacl_exit_fatal;
75 bacl_exit_code parse_acl_streams(JCR *jcr,
78 uint32_t content_length)
80 return bacl_exit_fatal;
84 * Send an ACL stream to the SD.
86 static bacl_exit_code send_acl_stream(JCR *jcr, int stream)
88 BSOCK *sd = jcr->store_bsock;
90 #ifdef FD_NO_SEND_TEST
97 if (jcr->acl_data->u.build->content_length <= 0) {
104 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
105 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
107 return bacl_exit_fatal;
111 * Send the buffer to the storage deamon
113 Dmsg1(400, "Backing up ACL <%s>\n", jcr->acl_data->u.build->content);
115 sd->msg = jcr->acl_data->u.build->content;
116 sd->msglen = jcr->acl_data->u.build->content_length + 1;
120 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
122 return bacl_exit_fatal;
125 jcr->JobBytes += sd->msglen;
127 if (!sd->signal(BNET_EOD)) {
128 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
130 return bacl_exit_fatal;
133 Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
138 * First the native ACLs.
140 #if defined(HAVE_ACL)
141 #if defined(HAVE_AIX_OS)
143 #if defined(HAVE_EXTENDED_ACL)
145 #include <sys/access.h>
148 static bool acl_is_trivial(struct acl *acl)
150 return (acl_last(acl) != acl->acl_ext ? false : true);
153 static bool acl_nfs4_is_trivial(nfs4_acl_int_t *acl)
156 return (acl->aclEntryN > 0 ? false : true);
159 int count = acl->aclEntryN;
162 for (i = 0; i < count; i++) {
163 ace = &acl->aclEntry[i];
164 if (!((ace->flags & ACE4_ID_SPECIAL) != 0 &&
165 (ace->aceWho.special_whoid == ACE4_WHO_OWNER ||
166 ace->aceWho.special_whoid == ACE4_WHO_GROUP ||
167 ace->aceWho.special_whoid == ACE4_WHO_EVERYONE) &&
168 ace->aceType == ACE4_ACCESS_ALLOWED_ACE_TYPE &&
169 ace->aceFlags == 0 &&
170 (ace->aceMask & ~(ACE4_READ_DATA |
171 ACE4_LIST_DIRECTORY |
174 ACE4_EXECUTE)) == 0)) {
183 * Define the supported ACL streams for this OS
185 static int os_access_acl_streams[3] = {
190 static int os_default_acl_streams[1] = {
194 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
199 size_t aclsize, acltxtsize;
200 bacl_exit_code retval = bacl_exit_error;
201 POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
204 * First see how big the buffers should be.
206 memset(&type, 0, sizeof(acl_type_t));
208 if (aclx_get(jcr->last_fname, GET_ACLINFO_ONLY, &type, NULL, &aclsize, &mode) < 0) {
211 retval = bacl_exit_ok;
215 * If the filesystem reports it doesn't support ACLs we clear the
216 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
217 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
218 * when we change from one filesystem to an other.
220 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
221 retval = bacl_exit_ok;
225 _("aclx_get error on file \"%s\": ERR=%s\n"),
226 jcr->last_fname, be.bstrerror());
227 Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
228 jcr->last_fname, be.bstrerror());
234 * Make sure the buffers are big enough.
236 aclbuf = check_pool_memory_size(aclbuf, aclsize + 1);
239 * Retrieve the ACL info.
241 if (aclx_get(jcr->last_fname, 0, &type, aclbuf, &aclsize, &mode) < 0) {
244 retval = bacl_exit_ok;
248 _("aclx_get error on file \"%s\": ERR=%s\n"),
249 jcr->last_fname, be.bstrerror());
250 Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
251 jcr->last_fname, be.bstrerror());
257 * See if the acl is non trivial.
261 if (acl_is_trivial((struct acl *)aclbuf)) {
262 retval = bacl_exit_ok;
267 if (acl_nfs4_is_trivial((nfs4_acl_int_t *)aclbuf)) {
268 retval = bacl_exit_ok;
274 _("Unknown acl type encountered on file \"%s\": %ld\n"),
275 jcr->last_fname, type.u64);
276 Dmsg2(100, "Unknown acl type encountered on file \"%s\": %ld\n",
277 jcr->last_fname, type.u64);
282 * We have a non-trivial acl lets convert it into some ASCII form.
284 acltxtsize = sizeof_pool_memory(jcr->acl_data->u.build->content);
285 if (aclx_printStr(jcr->acl_data->u.build->content, &acltxtsize, aclbuf,
286 aclsize, type, jcr->last_fname, 0) < 0) {
290 * Our buffer is not big enough, acltxtsize should be updated with the value
291 * the aclx_printStr really need. So we increase the buffer and try again.
293 jcr->acl_data->u.build->content =
294 check_pool_memory_size(jcr->acl_data->u.build->content, acltxtsize + 1);
295 if (aclx_printStr(jcr->acl_data->u.build->content, &acltxtsize, aclbuf,
296 aclsize, type, jcr->last_fname, 0) < 0) {
298 _("Failed to convert acl into text on file \"%s\"\n"),
300 Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
301 jcr->last_fname, type.u64);
307 _("Failed to convert acl into text on file \"%s\"\n"),
309 Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
310 jcr->last_fname, type.u64);
315 jcr->acl_data->u.build->content_length = strlen(jcr->acl_data->u.build->content) + 1;
318 retval = send_acl_stream(jcr, STREAM_ACL_AIX_AIXC);
320 retval = send_acl_stream(jcr, STREAM_ACL_AIX_NFS4);
324 free_pool_memory(aclbuf);
330 * See if a specific type of ACLs are supported on the filesystem
331 * the file is located on.
333 static inline bool aix_query_acl_support(JCR *jcr,
335 acl_type_t *pacl_type_info)
338 acl_types_list_t acl_type_list;
339 size_t acl_type_list_len = sizeof(acl_types_list_t);
341 memset(&acl_type_list, 0, sizeof(acl_type_list));
342 if (aclx_gettypes(jcr->last_fname, &acl_type_list, &acl_type_list_len)) {
346 for (i = 0; i < acl_type_list.num_entries; i++) {
347 if (acl_type_list.entries[i].u64 == aclType) {
348 memcpy(pacl_type_info, acl_type_list.entries + i, sizeof(acl_type_t));
355 static bacl_exit_code aix_parse_acl_streams(JCR *jcr,
358 uint32_t content_length)
364 bacl_exit_code retval = bacl_exit_error;
365 POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
368 case STREAM_ACL_AIX_TEXT:
370 * Handle the old stream using the old system call for now.
372 if (acl_put(jcr->last_fname, content, 0) != 0) {
373 retval = bacl_exit_error;
376 retval = bacl_exit_ok;
378 case STREAM_ACL_AIX_AIXC:
379 if (!aix_query_acl_support(jcr, ACL_AIXC, &type)) {
381 _("Trying to restore POSIX acl on file \"%s\" on filesystem without AIXC acl support\n"),
386 case STREAM_ACL_AIX_NFS4:
387 if (!aix_query_acl_support(jcr, ACL_NFS4, &type)) {
389 _("Trying to restore NFSv4 acl on file \"%s\" on filesystem without NFS4 acl support\n"),
396 } /* end switch (stream) */
399 * Set the acl buffer to an initial size. For now we set it
400 * to the same size as the ASCII representation.
402 aclbuf = check_pool_memory_size(aclbuf, content_length);
403 aclsize = content_length;
404 if (aclx_scanStr(content, aclbuf, &aclsize, type) < 0) {
408 * The buffer isn't big enough. The man page doesn't say that aclsize
409 * is updated to the needed size as what is done with aclx_printStr.
410 * So for now we try to increase the buffer a maximum of 3 times
411 * and retry the conversion.
413 for (cnt = 0; cnt < 3; cnt++) {
414 aclsize = 2 * aclsize;
415 aclbuf = check_pool_memory_size(aclbuf, aclsize);
417 if (aclx_scanStr(content, aclbuf, &aclsize, type) == 0) {
422 * See why we failed this time, ENOSPC retry if max retries not met,
433 _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
434 jcr->last_fname, be.bstrerror());
435 Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
436 jcr->last_fname, be.bstrerror());
443 _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
444 jcr->last_fname, be.bstrerror());
445 Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
446 jcr->last_fname, be.bstrerror());
450 if (aclx_put(jcr->last_fname, SET_ACL, type, aclbuf, aclsize, 0) < 0) {
453 retval = bacl_exit_ok;
457 * If the filesystem reports it doesn't support ACLs we clear the
458 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
459 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
460 * when we change from one filesystem to an other.
462 jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
463 retval = bacl_exit_ok;
467 _("aclx_put error on file \"%s\": ERR=%s\n"),
468 jcr->last_fname, be.bstrerror());
469 Dmsg2(100, "aclx_put error file=%s ERR=%s\n",
470 jcr->last_fname, be.bstrerror());
475 retval = bacl_exit_ok;
478 free_pool_memory(aclbuf);
483 #else /* HAVE_EXTENDED_ACL */
485 #include <sys/access.h>
488 * Define the supported ACL streams for this OS
490 static int os_access_acl_streams[1] = {
493 static int os_default_acl_streams[1] = {
497 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
501 if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
502 jcr->acl_data->u.build->content_length =
503 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
504 actuallyfree(acl_text);
505 return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT);
507 return bacl_exit_error;
510 static bacl_exit_code aix_parse_acl_streams(JCR *jcr,
513 uint32_t content_length)
515 if (acl_put(jcr->last_fname, content, 0) != 0) {
516 return bacl_exit_error;
520 #endif /* HAVE_EXTENDED_ACL */
523 * For this OS setup the build and parse function pointer to the OS specific functions.
525 static bacl_exit_code (*os_build_acl_streams)
526 (JCR *jcr, FF_PKT *ff_pkt) =
527 aix_build_acl_streams;
528 static bacl_exit_code (*os_parse_acl_streams)
529 (JCR *jcr, int stream, char *content, uint32_t content_length) =
530 aix_parse_acl_streams;
532 #elif defined(HAVE_DARWIN_OS) || \
533 defined(HAVE_FREEBSD_OS) || \
534 defined(HAVE_IRIX_OS) || \
535 defined(HAVE_OSF1_OS) || \
536 defined(HAVE_LINUX_OS)
538 #include <sys/types.h>
540 #ifdef HAVE_SYS_ACL_H
543 #error "configure failed to detect availability of sys/acl.h"
547 * On IRIX we can get shortened ACLs
549 #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
550 #define acl_to_text(acl,len) acl_to_short_text((acl), (len))
554 * On Linux we can get numeric and/or shorted ACLs
556 #if defined(HAVE_LINUX_OS)
557 #if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
558 #define BACL_ALTERNATE_TEXT (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
559 #elif defined(BACL_WANT_SHORT_ACLS)
560 #define BACL_ALTERNATE_TEXT TEXT_ABBREVIATE
561 #elif defined(BACL_WANT_NUMERIC_IDS)
562 #define BACL_ALTERNATE_TEXT TEXT_NUMERIC_IDS
564 #ifdef BACL_ALTERNATE_TEXT
565 #include <acl/libacl.h>
566 #define acl_to_text(acl,len) (acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
571 * On FreeBSD we can get numeric ACLs
573 #if defined(HAVE_FREEBSD_OS)
574 #if defined(BACL_WANT_NUMERIC_IDS)
575 #define BACL_ALTERNATE_TEXT ACL_TEXT_NUMERIC_IDS
577 #ifdef BACL_ALTERNATE_TEXT
578 #define acl_to_text(acl,len) (acl_to_text_np((acl), (len), BACL_ALTERNATE_TEXT))
583 * Some generic functions used by multiple OSes.
585 static acl_type_t bac_to_os_acltype(bacl_type acltype)
590 case BACL_TYPE_ACCESS:
591 ostype = ACL_TYPE_ACCESS;
593 case BACL_TYPE_DEFAULT:
594 ostype = ACL_TYPE_DEFAULT;
596 #ifdef HAVE_ACL_TYPE_NFS4
598 * FreeBSD has an additional acl type named ACL_TYPE_NFS4.
601 ostype = ACL_TYPE_NFS4;
604 #ifdef HAVE_ACL_TYPE_DEFAULT_DIR
605 case BACL_TYPE_DEFAULT_DIR:
607 * TRU64 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
609 ostype = ACL_TYPE_DEFAULT_DIR;
612 #ifdef HAVE_ACL_TYPE_EXTENDED
613 case BACL_TYPE_EXTENDED:
615 * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
617 ostype = ACL_TYPE_EXTENDED;
622 * This should never happen, as the per OS version function only tries acl
623 * types supported on a certain platform.
625 ostype = (acl_type_t)ACL_TYPE_NONE;
631 static int acl_count_entries(acl_t acl)
634 #if defined(HAVE_FREEBSD_OS) || \
635 defined(HAVE_LINUX_OS)
639 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
640 while (entry_available == 1) {
642 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
644 #elif defined(HAVE_IRIX_OS)
645 count = acl->acl_cnt;
646 #elif defined(HAVE_OSF1_OS)
647 count = acl->acl_num;
648 #elif defined(HAVE_DARWIN_OS)
652 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
653 while (entry_available == 0) {
655 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
661 #if !defined(HAVE_DARWIN_OS)
663 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
664 * There is no need to store those acls as we already store the stat bits too.
666 static bool acl_is_trivial(acl_t acl)
669 * acl is trivial if it has only the following entries:
676 #if defined(HAVE_FREEBSD_OS) || \
677 defined(HAVE_LINUX_OS)
680 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
681 while (entry_available == 1) {
683 * Get the tag type of this acl entry.
684 * If we fail to get the tagtype we call the acl non-trivial.
686 if (acl_get_tag_type(ace, &tag) < 0)
689 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
691 if (tag != ACL_USER_OBJ &&
692 tag != ACL_GROUP_OBJ &&
695 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
698 #elif defined(HAVE_IRIX_OS)
701 for (n = 0; n < acl->acl_cnt; n++) {
702 ace = &acl->acl_entry[n];
706 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
708 if (tag != ACL_USER_OBJ &&
709 tag != ACL_GROUP_OBJ &&
710 tag != ACL_OTHER_OBJ)
714 #elif defined(HAVE_OSF1_OS)
717 ace = acl->acl_first;
718 count = acl->acl_num;
721 tag = ace->entry->acl_type;
723 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
725 if (tag != ACL_USER_OBJ &&
726 tag != ACL_GROUP_OBJ &&
730 * On Tru64, perm can also contain non-standard bits such as
731 * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
733 if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
744 * Generic wrapper around acl_get_file call.
746 static bacl_exit_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
752 bacl_exit_code retval = bacl_exit_ok;
754 ostype = bac_to_os_acltype(acltype);
755 acl = acl_get_file(jcr->last_fname, ostype);
758 * From observation, IRIX's acl_get_file() seems to return a
759 * non-NULL acl with a count field of -1 when a file has no ACL
760 * defined, while IRIX's acl_to_text() returns NULL when presented
763 * For all other implmentations we check if there are more then
764 * zero entries in the acl returned.
766 if (acl_count_entries(acl) <= 0) {
771 * Make sure this is not just a trivial ACL.
773 #if !defined(HAVE_DARWIN_OS)
774 if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
776 * The ACLs simply reflect the (already known) standard permissions
777 * So we don't send an ACL stream to the SD.
782 #if defined(HAVE_FREEBSD_OS) && defined(_PC_ACL_NFS4)
783 if (acltype == BACL_TYPE_NFS4) {
785 if (acl_is_trivial_np(acl, &trivial) == 0) {
788 * The ACLs simply reflect the (already known) standard permissions
789 * So we don't send an ACL stream to the SD.
798 * Convert the internal acl representation into a text representation.
800 if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
801 jcr->acl_data->u.build->content_length =
802 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
809 _("acl_to_text error on file \"%s\": ERR=%s\n"),
810 jcr->last_fname, be.bstrerror());
811 Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",
812 jcr->last_fname, be.bstrerror());
814 retval = bacl_exit_error;
818 * Handle errors gracefully.
821 #if defined(BACL_ENOTSUP)
824 * If the filesystem reports it doesn't support ACLs we clear the
825 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
826 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
827 * when we change from one filesystem to an other.
829 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
835 /* Some real error */
837 _("acl_get_file error on file \"%s\": ERR=%s\n"),
838 jcr->last_fname, be.bstrerror());
839 Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",
840 jcr->last_fname, be.bstrerror());
842 retval = bacl_exit_error;
851 pm_strcpy(jcr->acl_data->u.build->content, "");
852 jcr->acl_data->u.build->content_length = 0;
857 * Generic wrapper around acl_set_file call.
859 static bacl_exit_code generic_set_acl_on_os(JCR *jcr,
862 uint32_t content_length)
869 * If we get empty default ACLs, clear ACLs now
871 ostype = bac_to_os_acltype(acltype);
872 if (ostype == ACL_TYPE_DEFAULT && strlen(content) == 0) {
873 if (acl_delete_def_file(jcr->last_fname) == 0) {
879 #if defined(BACL_ENOTSUP)
882 * If the filesystem reports it doesn't support ACLs we clear the
883 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
884 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
885 * when we change from one filesystem to an other.
887 jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
889 _("acl_delete_def_file error on file \"%s\": filesystem doesn't support ACLs\n"),
891 return bacl_exit_error;
895 _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
896 jcr->last_fname, be.bstrerror());
897 return bacl_exit_error;
901 acl = acl_from_text(content);
904 _("acl_from_text error on file \"%s\": ERR=%s\n"),
905 jcr->last_fname, be.bstrerror());
906 Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",
907 content, jcr->last_fname, be.bstrerror());
908 return bacl_exit_error;
911 #ifndef HAVE_FREEBSD_OS
913 * FreeBSD always fails acl_valid() - at least on valid input...
914 * As it does the right thing, given valid input, just ignore acl_valid().
916 if (acl_valid(acl) != 0) {
918 _("acl_valid error on file \"%s\": ERR=%s\n"),
919 jcr->last_fname, be.bstrerror());
920 Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",
921 content, jcr->last_fname, be.bstrerror());
923 return bacl_exit_error;
928 * Restore the ACLs, but don't complain about links which really should
929 * not have attributes, and the file it is linked to may not yet be restored.
930 * This is only true for the old acl streams as in the new implementation we
931 * don't save acls of symlinks (which cannot have acls anyhow)
933 if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
938 #if defined(BACL_ENOTSUP)
941 * If the filesystem reports it doesn't support ACLs we clear the
942 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
943 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
944 * when we change from one filesystem to an other.
946 jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
948 _("acl_set_file error on file \"%s\": filesystem doesn't support ACLs\n"),
950 Dmsg2(100, "acl_set_file error acl=%s file=%s filesystem doesn't support ACLs\n",
951 content, jcr->last_fname);
953 return bacl_exit_error;
957 _("acl_set_file error on file \"%s\": ERR=%s\n"),
958 jcr->last_fname, be.bstrerror());
959 Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
960 content, jcr->last_fname, be.bstrerror());
962 return bacl_exit_error;
970 * OS specific functions for handling different types of acl streams.
972 #if defined(HAVE_DARWIN_OS)
974 * Define the supported ACL streams for this OS
976 static int os_access_acl_streams[1] = {
977 STREAM_ACL_DARWIN_ACCESS_ACL
979 static int os_default_acl_streams[1] = {
983 static bacl_exit_code darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
985 #if defined(HAVE_ACL_TYPE_EXTENDED)
987 * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
988 * and acl_get_file (name, ACL_TYPE_DEFAULT)
989 * always return NULL / EINVAL. There is no point in making
990 * these two useless calls. The real ACL is retrieved through
991 * acl_get_file (name, ACL_TYPE_EXTENDED).
993 * Read access ACLs for files, dirs and links
995 if (generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED) == bacl_exit_fatal)
996 return bacl_exit_fatal;
999 * Read access ACLs for files, dirs and links
1001 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1002 return bacl_exit_fatal;
1005 if (jcr->acl_data->u.build->content_length > 0) {
1006 return send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL);
1008 return bacl_exit_ok;
1011 static bacl_exit_code darwin_parse_acl_streams(JCR *jcr,
1014 uint32_t content_length)
1016 #if defined(HAVE_ACL_TYPE_EXTENDED)
1017 return generic_set_acl_on_os(jcr, BACL_TYPE_EXTENDED, content, content_length);
1019 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1024 * For this OS setup the build and parse function pointer to the OS specific functions.
1026 static bacl_exit_code (*os_build_acl_streams)
1027 (JCR *jcr, FF_PKT *ff_pkt) =
1028 darwin_build_acl_streams;
1029 static bacl_exit_code (*os_parse_acl_streams)
1030 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1031 darwin_parse_acl_streams;
1033 #elif defined(HAVE_FREEBSD_OS)
1035 * Define the supported ACL streams for these OSes
1037 static int os_access_acl_streams[2] = {
1038 STREAM_ACL_FREEBSD_ACCESS_ACL,
1039 STREAM_ACL_FREEBSD_NFS4_ACL
1041 static int os_default_acl_streams[1] = {
1042 STREAM_ACL_FREEBSD_DEFAULT_ACL
1045 static bacl_exit_code freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1047 int acl_enabled = 0;
1048 bacl_type acltype = BACL_TYPE_NONE;
1051 #if defined(_PC_ACL_NFS4)
1053 * See if filesystem supports NFS4 acls.
1055 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
1056 switch (acl_enabled) {
1060 return bacl_exit_ok;
1063 _("pathconf error on file \"%s\": ERR=%s\n"),
1064 jcr->last_fname, be.bstrerror());
1065 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
1066 jcr->last_fname, be.bstrerror());
1067 return bacl_exit_error;
1072 acltype = BACL_TYPE_NFS4;
1077 if (acl_enabled == 0) {
1079 * See if filesystem supports POSIX acls.
1081 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
1082 switch (acl_enabled) {
1086 return bacl_exit_ok;
1089 _("pathconf error on file \"%s\": ERR=%s\n"),
1090 jcr->last_fname, be.bstrerror());
1091 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
1092 jcr->last_fname, be.bstrerror());
1093 return bacl_exit_error;
1098 acltype = BACL_TYPE_ACCESS;
1104 * If the filesystem reports it doesn't support ACLs we clear the
1105 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1106 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1107 * when we change from one filesystem to an other.
1109 if (acl_enabled == 0) {
1110 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1111 pm_strcpy(jcr->acl_data->u.build->content, "");
1112 jcr->acl_data->u.build->content_length = 0;
1113 return bacl_exit_ok;
1117 * Based on the supported ACLs retrieve and store them.
1120 case BACL_TYPE_NFS4:
1122 * Read NFS4 ACLs for files, dirs and links
1124 if (generic_get_acl_from_os(jcr, BACL_TYPE_NFS4) == bacl_exit_fatal)
1125 return bacl_exit_fatal;
1127 if (jcr->acl_data->u.build->content_length > 0) {
1128 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_NFS4_ACL) == bacl_exit_fatal)
1129 return bacl_exit_fatal;
1132 case BACL_TYPE_ACCESS:
1134 * Read access ACLs for files, dirs and links
1136 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1137 return bacl_exit_fatal;
1139 if (jcr->acl_data->u.build->content_length > 0) {
1140 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_ACCESS_ACL) == bacl_exit_fatal)
1141 return bacl_exit_fatal;
1145 * Directories can have default ACLs too
1147 if (ff_pkt->type == FT_DIREND) {
1148 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
1149 return bacl_exit_fatal;
1150 if (jcr->acl_data->u.build->content_length > 0) {
1151 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_DEFAULT_ACL) == bacl_exit_fatal)
1152 return bacl_exit_fatal;
1160 return bacl_exit_ok;
1163 static bacl_exit_code freebsd_parse_acl_streams(JCR *jcr,
1166 uint32_t content_length)
1168 int acl_enabled = 0;
1169 const char *acl_type_name;
1173 * First make sure the filesystem supports acls.
1176 case STREAM_UNIX_ACCESS_ACL:
1177 case STREAM_ACL_FREEBSD_ACCESS_ACL:
1178 case STREAM_UNIX_DEFAULT_ACL:
1179 case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1180 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
1181 acl_type_name = "POSIX";
1183 case STREAM_ACL_FREEBSD_NFS4_ACL:
1184 #if defined(_PC_ACL_NFS4)
1185 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
1187 acl_type_name = "NFS4";
1190 acl_type_name = "unknown";
1194 switch (acl_enabled) {
1198 return bacl_exit_ok;
1201 _("pathconf error on file \"%s\": ERR=%s\n"),
1202 jcr->last_fname, be.bstrerror());
1203 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1204 content, jcr->last_fname, be.bstrerror());
1205 return bacl_exit_error;
1209 * If the filesystem reports it doesn't support ACLs we clear the
1210 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
1211 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
1212 * when we change from one filesystem to an other.
1214 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1216 _("Trying to restore acl on file \"%s\" on filesystem without %s acl support\n"),
1217 jcr->last_fname, acl_type_name);
1218 return bacl_exit_error;
1227 case STREAM_UNIX_ACCESS_ACL:
1228 case STREAM_ACL_FREEBSD_ACCESS_ACL:
1229 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1230 case STREAM_UNIX_DEFAULT_ACL:
1231 case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1232 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1233 case STREAM_ACL_FREEBSD_NFS4_ACL:
1234 return generic_set_acl_on_os(jcr, BACL_TYPE_NFS4, content, content_length);
1238 return bacl_exit_error;
1242 * For this OSes setup the build and parse function pointer to the OS specific functions.
1244 static bacl_exit_code (*os_build_acl_streams)
1245 (JCR *jcr, FF_PKT *ff_pkt) =
1246 freebsd_build_acl_streams;
1247 static bacl_exit_code (*os_parse_acl_streams)
1248 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1249 freebsd_parse_acl_streams;
1251 #elif defined(HAVE_IRIX_OS) || \
1252 defined(HAVE_LINUX_OS)
1254 * Define the supported ACL streams for these OSes
1256 #if defined(HAVE_IRIX_OS)
1257 static int os_access_acl_streams[1] = {
1258 STREAM_ACL_IRIX_ACCESS_ACL
1260 static int os_default_acl_streams[1] = {
1261 STREAM_ACL_IRIX_DEFAULT_ACL
1263 #elif defined(HAVE_LINUX_OS)
1264 static int os_access_acl_streams[1] = {
1265 STREAM_ACL_LINUX_ACCESS_ACL
1267 static int os_default_acl_streams[1] = {
1268 STREAM_ACL_LINUX_DEFAULT_ACL
1272 static bacl_exit_code generic_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1275 * Read access ACLs for files, dirs and links
1277 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1278 return bacl_exit_fatal;
1280 if (jcr->acl_data->u.build->content_length > 0) {
1281 if (send_acl_stream(jcr, os_access_acl_streams[0]) == bacl_exit_fatal)
1282 return bacl_exit_fatal;
1286 * Directories can have default ACLs too
1288 if (ff_pkt->type == FT_DIREND) {
1289 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
1290 return bacl_exit_fatal;
1291 if (jcr->acl_data->u.build->content_length > 0) {
1292 if (send_acl_stream(jcr, os_default_acl_streams[0]) == bacl_exit_fatal)
1293 return bacl_exit_fatal;
1296 return bacl_exit_ok;
1299 static bacl_exit_code generic_parse_acl_streams(JCR *jcr,
1302 uint32_t content_length)
1307 case STREAM_UNIX_ACCESS_ACL:
1308 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1309 case STREAM_UNIX_DEFAULT_ACL:
1310 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1313 * See what type of acl it is.
1315 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1316 if (os_access_acl_streams[cnt] == stream) {
1317 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1320 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1321 if (os_default_acl_streams[cnt] == stream) {
1322 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1327 return bacl_exit_error;
1331 * For this OSes setup the build and parse function pointer to the OS specific functions.
1333 static bacl_exit_code (*os_build_acl_streams)
1334 (JCR *jcr, FF_PKT *ff_pkt) =
1335 generic_build_acl_streams;
1336 static bacl_exit_code (*os_parse_acl_streams)
1337 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1338 generic_parse_acl_streams;
1340 #elif defined(HAVE_OSF1_OS)
1343 * Define the supported ACL streams for this OS
1345 static int os_access_acl_streams[1] = {
1346 STREAM_ACL_TRU64_ACCESS_ACL
1348 static int os_default_acl_streams[2] = {
1349 STREAM_ACL_TRU64_DEFAULT_ACL,
1350 STREAM_ACL_TRU64_DEFAULT_DIR_ACL
1353 static bacl_exit_code tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1356 * Read access ACLs for files, dirs and links
1358 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal) {
1359 return bacl_exit_error;
1360 if (jcr->acl_data->u.build->content_length > 0) {
1361 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL))
1362 return bacl_exit_error;
1365 * Directories can have default ACLs too
1367 if (ff_pkt->type == FT_DIREND) {
1368 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal) {
1369 return bacl_exit_error;
1370 if (jcr->acl_data->u.build->content_length > 0) {
1371 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL))
1372 return bacl_exit_error;
1375 * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
1376 * This is an inherited acl for all subdirs.
1377 * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
1378 * Section 21.5 Default ACLs
1380 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR) == bacl_exit_fatal) {
1381 return bacl_exit_error;
1382 if (jcr->acl_data->u.build->content_length > 0) {
1383 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL))
1384 return bacl_exit_error;
1387 return bacl_exit_ok;
1390 static bacl_exit_code tru64_parse_acl_streams(JCR *jcr,
1393 uint32_t content_length)
1396 case STREAM_UNIX_ACCESS_ACL:
1397 case STREAM_ACL_TRU64_ACCESS_ACL:
1398 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1399 case STREAM_UNIX_DEFAULT_ACL:
1400 case STREAM_ACL_TRU64_DEFAULT_ACL:
1401 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1402 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
1403 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR, content, content_length);
1407 * For this OS setup the build and parse function pointer to the OS specific functions.
1409 static bacl_exit_code (*os_build_acl_streams)
1410 (JCR *jcr, FF_PKT *ff_pkt) =
1411 tru64_build_acl_streams;
1412 static bacl_exit_code (*os_parse_acl_streams)
1413 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1414 tru64_parse_acl_streams;
1418 #elif defined(HAVE_HPUX_OS)
1419 #ifdef HAVE_SYS_ACL_H
1420 #include <sys/acl.h>
1422 #error "configure failed to detect availability of sys/acl.h"
1428 * Define the supported ACL streams for this OS
1430 static int os_access_acl_streams[1] = {
1431 STREAM_ACL_HPUX_ACL_ENTRY
1433 static int os_default_acl_streams[1] = {
1438 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1439 * There is no need to store those acls as we already store the stat bits too.
1441 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
1444 struct acl_entry ace
1446 for (n = 0; n < count; n++) {
1449 * See if this acl just is the stat mode in acl form.
1451 if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
1452 (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
1453 (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
1460 * OS specific functions for handling different types of acl streams.
1462 static bacl_exit_code hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1465 struct acl_entry acls[NACLENTRIES];
1469 if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
1471 #if defined(BACL_ENOTSUP)
1474 * Not supported, just pretend there is nothing to see
1476 * If the filesystem reports it doesn't support ACLs we clear the
1477 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1478 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1479 * when we change from one filesystem to an other.
1481 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1482 pm_strcpy(jcr->acl_data->u.build->content, "");
1483 jcr->acl_data->u.build->content_length = 0;
1484 return bacl_exit_ok;
1487 pm_strcpy(jcr->acl_data->u.build->content, "");
1488 jcr->acl_data->u.build->content_length = 0;
1489 return bacl_exit_ok;
1492 _("getacl error on file \"%s\": ERR=%s\n"),
1493 jcr->last_fname, be.bstrerror());
1494 Dmsg2(100, "getacl error file=%s ERR=%s\n",
1495 jcr->last_fname, be.bstrerror());
1497 pm_strcpy(jcr->acl_data->u.build->content, "");
1498 jcr->acl_data->u.build->content_length = 0;
1499 return bacl_exit_error;
1503 pm_strcpy(jcr->acl_data->u.build->content, "");
1504 jcr->acl_data->u.build->content_length = 0;
1505 return bacl_exit_ok;
1507 if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
1508 if (acl_is_trivial(n, acls, ff_pkt->statp)) {
1510 * The ACLs simply reflect the (already known) standard permissions
1511 * So we don't send an ACL stream to the SD.
1513 pm_strcpy(jcr->acl_data->u.build->content, "");
1514 jcr->acl_data->u.build->content_length = 0;
1515 return bacl_exit_ok;
1517 if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
1518 jcr->acl_data->u.build->content_length =
1519 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
1520 actuallyfree(acl_text);
1522 return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
1525 _("acltostr error on file \"%s\": ERR=%s\n"),
1526 jcr->last_fname, be.bstrerror());
1527 Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",
1528 jcr->acl_data->u.build->content, jcr->last_fname, be.bstrerror());
1529 return bacl_exit_error;
1531 return bacl_exit_error;
1534 static bacl_exit_code hpux_parse_acl_streams(JCR *jcr,
1537 uint32_t content_length)
1540 struct acl_entry acls[NACLENTRIES];
1543 n = strtoacl(content, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
1546 _("strtoacl error on file \"%s\": ERR=%s\n"),
1547 jcr->last_fname, be.bstrerror());
1548 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
1549 content, jcr->last_fname, be.bstrerror());
1550 return bacl_exit_error;
1552 if (strtoacl(content, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
1554 _("strtoacl error on file \"%s\": ERR=%s\n"),
1555 jcr->last_fname, be.bstrerror());
1556 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
1557 content, jcr->last_fname, be.bstrerror());
1559 return bacl_exit_error;
1562 * Restore the ACLs, but don't complain about links which really should
1563 * not have attributes, and the file it is linked to may not yet be restored.
1564 * This is only true for the old acl streams as in the new implementation we
1565 * don't save acls of symlinks (which cannot have acls anyhow)
1567 if (setacl(jcr->last_fname, n, acls) != 0 &&
1568 jcr->last_type != FT_LNK) {
1571 return bacl_exit_ok;
1572 #if defined(BACL_ENOTSUP)
1575 * If the filesystem reports it doesn't support ACLs we clear the
1576 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
1577 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
1578 * when we change from one filesystem to an other.
1580 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1582 _("setacl error on file \"%s\": filesystem doesn't support ACLs\n"),
1584 Dmsg2(100, "setacl error acl=%s file=%s filesystem doesn't support ACLs\n",
1585 content, jcr->last_fname);
1586 return bacl_exit_error;
1590 _("setacl error on file \"%s\": ERR=%s\n"),
1591 jcr->last_fname, be.bstrerror());
1592 Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
1593 content, jcr->last_fname, be.bstrerror());
1594 return bacl_exit_error;
1597 return bacl_exit_ok;
1601 * For this OS setup the build and parse function pointer to the OS specific functions.
1603 static bacl_exit_code (*os_build_acl_streams)
1604 (JCR *jcr, FF_PKT *ff_pkt) =
1605 hpux_build_acl_streams;
1606 static bacl_exit_code (*os_parse_acl_streams)
1607 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1608 hpux_parse_acl_streams;
1610 #elif defined(HAVE_SUN_OS)
1611 #ifdef HAVE_SYS_ACL_H
1612 #include <sys/acl.h>
1614 #error "configure failed to detect availability of sys/acl.h"
1617 #if defined(HAVE_EXTENDED_ACL)
1619 * We define some internals of the Solaris acl libs here as those
1620 * are not exposed yet. Probably because they want us to see the
1621 * acls as opague data. But as we need to support different platforms
1622 * and versions of Solaris we need to expose some data to be able
1623 * to determine the type of acl used to stuff it into the correct
1624 * data stream. I know this is far from portable, but maybe the
1625 * proper interface is exposed later on and we can get ride of
1626 * this kludge. Newer versions of Solaris include sys/acl_impl.h
1627 * which has implementation details of acls, if thats included we
1628 * don't have to define it ourself.
1630 #if !defined(_SYS_ACL_IMPL_H)
1631 typedef enum acl_type {
1638 * Two external references to functions in the libsec library function not in current include files.
1641 int acl_type(acl_t *);
1642 char *acl_strerror(int);
1646 * Define the supported ACL streams for this OS
1648 static int os_access_acl_streams[2] = {
1649 STREAM_ACL_SOLARIS_ACLENT,
1650 STREAM_ACL_SOLARIS_ACE
1652 static int os_default_acl_streams[1] = {
1657 * As the new libsec interface with acl_totext and acl_fromtext also handles
1658 * the old format from acltotext we can use the new functions even
1659 * for acls retrieved and stored in the database with older fd versions. If the
1660 * new interface is not defined (Solaris 9 and older we fall back to the old code)
1662 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1664 int acl_enabled, flags;
1667 bacl_exit_code stream_status = bacl_exit_error;
1671 * See if filesystem supports acls.
1673 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1674 switch (acl_enabled) {
1677 * If the filesystem reports it doesn't support ACLs we clear the
1678 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1679 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1680 * when we change from one filesystem to an other.
1682 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1683 pm_strcpy(jcr->acl_data->u.build->content, "");
1684 jcr->acl_data->u.build->content_length = 0;
1685 return bacl_exit_ok;
1689 return bacl_exit_ok;
1692 _("pathconf error on file \"%s\": ERR=%s\n"),
1693 jcr->last_fname, be.bstrerror());
1694 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
1695 jcr->last_fname, be.bstrerror());
1696 return bacl_exit_error;
1703 * Get ACL info: don't bother allocating space if there is only a trivial ACL.
1705 if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
1708 return bacl_exit_ok;
1711 _("acl_get error on file \"%s\": ERR=%s\n"),
1712 jcr->last_fname, acl_strerror(errno));
1713 Dmsg2(100, "acl_get error file=%s ERR=%s\n",
1714 jcr->last_fname, acl_strerror(errno));
1715 return bacl_exit_error;
1721 * The ACLs simply reflect the (already known) standard permissions
1722 * So we don't send an ACL stream to the SD.
1724 pm_strcpy(jcr->acl_data->u.build->content, "");
1725 jcr->acl_data->u.build->content_length = 0;
1726 return bacl_exit_ok;
1729 #if defined(ACL_SID_FMT)
1731 * New format flag added in newer Solaris versions.
1733 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
1735 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
1736 #endif /* ACL_SID_FMT */
1738 if ((acl_text = acl_totext(aclp, flags)) != NULL) {
1739 jcr->acl_data->u.build->content_length =
1740 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
1741 actuallyfree(acl_text);
1743 switch (acl_type(aclp)) {
1745 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1748 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE);
1756 return stream_status;
1759 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr,
1762 uint32_t content_length)
1765 int acl_enabled, error;
1769 case STREAM_UNIX_ACCESS_ACL:
1770 case STREAM_ACL_SOLARIS_ACLENT:
1771 case STREAM_ACL_SOLARIS_ACE:
1773 * First make sure the filesystem supports acls.
1775 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1776 switch (acl_enabled) {
1779 * If the filesystem reports it doesn't support ACLs we clear the
1780 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
1781 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
1782 * when we change from one filesystem to an other.
1784 jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
1786 _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
1788 return bacl_exit_error;
1792 return bacl_exit_ok;
1795 _("pathconf error on file \"%s\": ERR=%s\n"),
1796 jcr->last_fname, be.bstrerror());
1797 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1798 content, jcr->last_fname, be.bstrerror());
1799 return bacl_exit_error;
1803 * On a filesystem with ACL support make sure this particular ACL type can be restored.
1806 case STREAM_ACL_SOLARIS_ACLENT:
1808 * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
1810 if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
1812 _("Trying to restore POSIX acl on file \"%s\" on filesystem without aclent acl support\n"),
1814 return bacl_exit_error;
1817 case STREAM_ACL_SOLARIS_ACE:
1819 * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
1821 if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
1823 _("Trying to restore NFSv4 acl on file \"%s\" on filesystem without ace acl support\n"),
1825 return bacl_exit_error;
1830 * Stream id which doesn't describe the type of acl which is encoded.
1837 if ((error = acl_fromtext(content, &aclp)) != 0) {
1839 _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1840 jcr->last_fname, acl_strerror(error));
1841 Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",
1842 content, jcr->last_fname, acl_strerror(error));
1843 return bacl_exit_error;
1847 * Validate that the conversion gave us the correct acl type.
1850 case STREAM_ACL_SOLARIS_ACLENT:
1851 if (acl_type(aclp) != ACLENT_T) {
1853 _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1855 return bacl_exit_error;
1858 case STREAM_ACL_SOLARIS_ACE:
1859 if (acl_type(aclp) != ACE_T) {
1861 _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1863 return bacl_exit_error;
1868 * Stream id which doesn't describe the type of acl which is encoded.
1874 * Restore the ACLs, but don't complain about links which really should
1875 * not have attributes, and the file it is linked to may not yet be restored.
1876 * This is only true for the old acl streams as in the new implementation we
1877 * don't save acls of symlinks (which cannot have acls anyhow)
1879 if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1883 return bacl_exit_ok;
1886 _("acl_set error on file \"%s\": ERR=%s\n"),
1887 jcr->last_fname, acl_strerror(error));
1888 Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",
1889 content, jcr->last_fname, acl_strerror(error));
1891 return bacl_exit_error;
1896 return bacl_exit_ok;
1898 return bacl_exit_error;
1899 } /* end switch (stream) */
1902 #else /* HAVE_EXTENDED_ACL */
1905 * Define the supported ACL streams for this OS
1907 static int os_access_acl_streams[1] = {
1908 STREAM_ACL_SOLARIS_ACLENT
1910 static int os_default_acl_streams[1] = {
1915 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1916 * There is no need to store those acls as we already store the stat bits too.
1918 static bool acl_is_trivial(int count, aclent_t *entries)
1923 for (n = 0; n < count; n++) {
1926 if (!(ace->a_type == USER_OBJ ||
1927 ace->a_type == GROUP_OBJ ||
1928 ace->a_type == OTHER_OBJ ||
1929 ace->a_type == CLASS_OBJ))
1936 * OS specific functions for handling different types of acl streams.
1938 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1945 n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1946 if (n < MIN_ACL_ENTRIES)
1947 return bacl_exit_error;
1949 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1950 if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1951 if (acl_is_trivial(n, acls)) {
1953 * The ACLs simply reflect the (already known) standard permissions
1954 * So we don't send an ACL stream to the SD.
1957 pm_strcpy(jcr->acl_data->u.build->content, "");
1958 jcr->acl_data->u.build->content_length = 0;
1959 return bacl_exit_ok;
1962 if ((acl_text = acltotext(acls, n)) != NULL) {
1963 jcr->acl_data->u.build->content_length =
1964 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
1965 actuallyfree(acl_text);
1967 return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1971 _("acltotext error on file \"%s\": ERR=%s\n"),
1972 jcr->last_fname, be.bstrerror());
1973 Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",
1974 jcr->acl_data->u.build->content, jcr->last_fname, be.bstrerror());
1978 return bacl_exit_error;
1981 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr,
1984 uint32_t content_length)
1990 acls = aclfromtext(content, &n);
1993 _("aclfromtext error on file \"%s\": ERR=%s\n"),
1994 jcr->last_fname, be.bstrerror());
1995 Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",
1996 content, jcr->last_fname, be.bstrerror());
1997 return bacl_exit_error;
2001 * Restore the ACLs, but don't complain about links which really should
2002 * not have attributes, and the file it is linked to may not yet be restored.
2004 if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
2008 return bacl_exit_ok;
2011 _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
2012 jcr->last_fname, be.bstrerror());
2013 Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
2014 content, jcr->last_fname, be.bstrerror());
2016 return bacl_exit_error;
2020 return bacl_exit_ok;
2022 #endif /* HAVE_EXTENDED_ACL */
2025 * For this OS setup the build and parse function pointer to the OS specific functions.
2027 static bacl_exit_code (*os_build_acl_streams)
2028 (JCR *jcr, FF_PKT *ff_pkt) =
2029 solaris_build_acl_streams;
2030 static bacl_exit_code (*os_parse_acl_streams)
2031 (JCR *jcr, int stream, char *content, uint32_t content_length) =
2032 solaris_parse_acl_streams;
2034 #endif /* HAVE_SUN_OS */
2035 #endif /* HAVE_ACL */
2038 * Entry points when compiled with support for ACLs on a supported platform.
2042 * Read and send an ACL for the last encountered file.
2044 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
2047 * See if we are changing from one device to an other.
2048 * We save the current device we are restoring to and compare
2049 * it with the current st_dev in the last stat performed on
2050 * the file we are currently storing.
2052 if (jcr->acl_data->current_dev != ff_pkt->statp.st_dev) {
2054 * Reset the acl save flags.
2056 jcr->acl_data->flags = 0;
2058 jcr->acl_data->flags |= BACL_FLAG_SAVE_NATIVE;
2061 * Save that we started scanning a new filesystem.
2063 jcr->acl_data->current_dev = ff_pkt->statp.st_dev;
2066 #if defined(HAVE_ACL)
2068 * See if the BACL_FLAG_SAVE_NATIVE flag is set which lets us know if we should
2071 if (jcr->acl_data->flags & BACL_FLAG_SAVE_NATIVE) {
2073 * Call the appropriate function.
2075 if (os_build_acl_streams) {
2076 return os_build_acl_streams(jcr, ff_pkt);
2079 return bacl_exit_ok;
2082 return bacl_exit_error;
2085 bacl_exit_code parse_acl_streams(JCR *jcr,
2088 uint32_t content_length)
2096 * See if we are changing from one device to an other.
2097 * We save the current device we are restoring to and compare
2098 * it with the current st_dev in the last stat performed on
2099 * the file we are currently restoring.
2101 ret = lstat(jcr->last_fname, &st);
2106 return bacl_exit_ok;
2109 _("Unable to stat file \"%s\": ERR=%s\n"),
2110 jcr->last_fname, be.bstrerror());
2111 Dmsg2(100, "Unable to stat file \"%s\": ERR=%s\n",
2112 jcr->last_fname, be.bstrerror());
2113 return bacl_exit_error;
2119 if (jcr->acl_data->current_dev != st.st_dev) {
2121 * Reset the acl save flags.
2123 jcr->acl_data->flags = 0;
2124 jcr->acl_data->flags |= BACL_FLAG_RESTORE_NATIVE;
2127 * Save that we started restoring to a new filesystem.
2129 jcr->acl_data->current_dev = st.st_dev;
2133 #if defined(HAVE_ACL)
2134 case STREAM_UNIX_ACCESS_ACL:
2135 case STREAM_UNIX_DEFAULT_ACL:
2137 * Handle legacy ACL streams.
2139 if ((jcr->acl_data->flags & BACL_FLAG_RESTORE_NATIVE) && os_parse_acl_streams) {
2140 return os_parse_acl_streams(jcr, stream, content, content_length);
2143 * Increment error count but don't log an error again for the same filesystem.
2145 jcr->acl_data->u.parse->nr_errors++;
2146 return bacl_exit_ok;
2150 if ((jcr->acl_data->flags & BACL_FLAG_RESTORE_NATIVE) && os_parse_acl_streams) {
2152 * Walk the os_access_acl_streams array with the supported Access ACL streams for this OS.
2154 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
2155 if (os_access_acl_streams[cnt] == stream) {
2156 return os_parse_acl_streams(jcr, stream, content, content_length);
2160 * Walk the os_default_acl_streams array with the supported Default ACL streams for this OS.
2162 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
2163 if (os_default_acl_streams[cnt] == stream) {
2164 return os_parse_acl_streams(jcr, stream, content, content_length);
2169 * Increment error count but don't log an error again for the same filesystem.
2171 jcr->acl_data->u.parse->nr_errors++;
2172 return bacl_exit_ok;
2180 Qmsg2(jcr, M_WARNING, 0,
2181 _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
2182 jcr->last_fname, stream);
2183 return bacl_exit_error;