2 Bacula® - The Network Backup Solution
4 Copyright (C) 2004-2014 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from many
7 others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 Bacula® is a registered trademark of Kern Sibbald.
17 * Functions to handle ACLs for bacula.
19 * Currently we support the following OSes:
20 * - AIX (pre-5.3 and post 5.3 acls, acl_get and aclx_get interface)
22 * - FreeBSD (POSIX and NFSv4/ZFS acls)
27 * - Solaris (POSIX and NFSv4/ZFS acls)
30 * Next to OS specific acls we support AFS acls using the pioctl interface.
32 * We handle two different types of ACLs: access and default ACLS.
33 * On most systems that support default ACLs they only apply to directories.
35 * On some systems (eg. linux and FreeBSD) we must obtain the two ACLs
36 * independently, while others (eg. Solaris) provide both in one call.
38 * The Filed saves ACLs in their native format and uses different streams
39 * for all different platforms. Currently we only allow ACLs to be restored
40 * which were saved in the native format of the platform they are extracted
41 * on. Later on we might add conversion functions for mapping from one
42 * platform to an other or allow restores of systems that use the same
45 * Its also interesting to see what the exact format of acl text is on
46 * certain platforms and if they use they same encoding we might allow
47 * different platform streams to be decoded on an other similar platform.
49 * Original written by Preben 'Peppe' Guldberg, December 2004
50 * Major rewrite by Marco van Wieringen, November 2008
51 * Major overhaul by Marco van Wieringen, January 2012
57 #if !defined(HAVE_ACL) && !defined(HAVE_AFS_ACL)
59 * Entry points when compiled without support for ACLs or on an unsupported platform.
61 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
63 return bacl_exit_fatal;
66 bacl_exit_code parse_acl_streams(JCR *jcr,
69 uint32_t content_length)
71 return bacl_exit_fatal;
75 * Send an ACL stream to the SD.
77 static bacl_exit_code send_acl_stream(JCR *jcr, int stream)
79 BSOCK *sd = jcr->store_bsock;
81 #ifdef FD_NO_SEND_TEST
88 if (jcr->acl_data->u.build->content_length <= 0) {
95 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
96 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
98 return bacl_exit_fatal;
102 * Send the buffer to the storage deamon
104 Dmsg1(400, "Backing up ACL <%s>\n", jcr->acl_data->u.build->content);
106 sd->msg = jcr->acl_data->u.build->content;
107 sd->msglen = jcr->acl_data->u.build->content_length + 1;
111 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
113 return bacl_exit_fatal;
116 jcr->JobBytes += sd->msglen;
118 if (!sd->signal(BNET_EOD)) {
119 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
121 return bacl_exit_fatal;
124 Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
129 * First the native ACLs.
131 #if defined(HAVE_ACL)
132 #if defined(HAVE_AIX_OS)
134 #if defined(HAVE_EXTENDED_ACL)
136 #include <sys/access.h>
139 static bool acl_is_trivial(struct acl *acl)
141 return (acl_last(acl) != acl->acl_ext ? false : true);
144 static bool acl_nfs4_is_trivial(nfs4_acl_int_t *acl)
147 return (acl->aclEntryN > 0 ? false : true);
150 int count = acl->aclEntryN;
153 for (i = 0; i < count; i++) {
154 ace = &acl->aclEntry[i];
155 if (!((ace->flags & ACE4_ID_SPECIAL) != 0 &&
156 (ace->aceWho.special_whoid == ACE4_WHO_OWNER ||
157 ace->aceWho.special_whoid == ACE4_WHO_GROUP ||
158 ace->aceWho.special_whoid == ACE4_WHO_EVERYONE) &&
159 ace->aceType == ACE4_ACCESS_ALLOWED_ACE_TYPE &&
160 ace->aceFlags == 0 &&
161 (ace->aceMask & ~(ACE4_READ_DATA |
162 ACE4_LIST_DIRECTORY |
165 ACE4_EXECUTE)) == 0)) {
174 * Define the supported ACL streams for this OS
176 static int os_access_acl_streams[3] = {
181 static int os_default_acl_streams[1] = {
185 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
189 size_t aclsize, acltxtsize;
190 bacl_exit_code retval = bacl_exit_error;
191 POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
194 * First see how big the buffers should be.
196 memset(&type, 0, sizeof(acl_type_t));
198 if (aclx_get(jcr->last_fname, GET_ACLINFO_ONLY, &type, NULL, &aclsize, &mode) < 0) {
203 retval = bacl_exit_ok;
207 * If the filesystem reports it doesn't support ACLs we clear the
208 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
209 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
210 * when we change from one filesystem to an other.
212 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
213 retval = bacl_exit_ok;
217 _("aclx_get error on file \"%s\": ERR=%s\n"),
218 jcr->last_fname, be.bstrerror());
219 Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
220 jcr->last_fname, be.bstrerror());
226 * Make sure the buffers are big enough.
228 aclbuf = check_pool_memory_size(aclbuf, aclsize + 1);
231 * Retrieve the ACL info.
233 if (aclx_get(jcr->last_fname, 0, &type, aclbuf, &aclsize, &mode) < 0) {
238 retval = bacl_exit_ok;
242 _("aclx_get error on file \"%s\": ERR=%s\n"),
243 jcr->last_fname, be.bstrerror());
244 Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
245 jcr->last_fname, be.bstrerror());
251 * See if the acl is non trivial.
255 if (acl_is_trivial((struct acl *)aclbuf)) {
256 retval = bacl_exit_ok;
261 if (acl_nfs4_is_trivial((nfs4_acl_int_t *)aclbuf)) {
262 retval = bacl_exit_ok;
268 _("Unknown acl type encountered on file \"%s\": %ld\n"),
269 jcr->last_fname, type.u64);
270 Dmsg2(100, "Unknown acl type encountered on file \"%s\": %ld\n",
271 jcr->last_fname, type.u64);
276 * We have a non-trivial acl lets convert it into some ASCII form.
278 acltxtsize = sizeof_pool_memory(jcr->acl_data->u.build->content);
279 if (aclx_printStr(jcr->acl_data->u.build->content, &acltxtsize, aclbuf,
280 aclsize, type, jcr->last_fname, 0) < 0) {
284 * Our buffer is not big enough, acltxtsize should be updated with the value
285 * the aclx_printStr really need. So we increase the buffer and try again.
287 jcr->acl_data->u.build->content =
288 check_pool_memory_size(jcr->acl_data->u.build->content, acltxtsize + 1);
289 if (aclx_printStr(jcr->acl_data->u.build->content, &acltxtsize, aclbuf,
290 aclsize, type, jcr->last_fname, 0) < 0) {
292 _("Failed to convert acl into text on file \"%s\"\n"),
294 Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
295 jcr->last_fname, type.u64);
301 _("Failed to convert acl into text on file \"%s\"\n"),
303 Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
304 jcr->last_fname, type.u64);
309 jcr->acl_data->u.build->content_length = strlen(jcr->acl_data->u.build->content) + 1;
312 retval = send_acl_stream(jcr, STREAM_ACL_AIX_AIXC);
314 retval = send_acl_stream(jcr, STREAM_ACL_AIX_NFS4);
318 free_pool_memory(aclbuf);
324 * See if a specific type of ACLs are supported on the filesystem
325 * the file is located on.
327 static inline bool aix_query_acl_support(JCR *jcr,
329 acl_type_t *pacl_type_info)
332 acl_types_list_t acl_type_list;
333 size_t acl_type_list_len = sizeof(acl_types_list_t);
335 memset(&acl_type_list, 0, sizeof(acl_type_list));
336 if (aclx_gettypes(jcr->last_fname, &acl_type_list, &acl_type_list_len)) {
340 for (i = 0; i < acl_type_list.num_entries; i++) {
341 if (acl_type_list.entries[i].u64 == aclType) {
342 memcpy(pacl_type_info, acl_type_list.entries + i, sizeof(acl_type_t));
349 static bacl_exit_code aix_parse_acl_streams(JCR *jcr,
352 uint32_t content_length)
357 bacl_exit_code retval = bacl_exit_error;
358 POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
361 case STREAM_ACL_AIX_TEXT:
363 * Handle the old stream using the old system call for now.
365 if (acl_put(jcr->last_fname, content, 0) != 0) {
366 retval = bacl_exit_error;
369 retval = bacl_exit_ok;
371 case STREAM_ACL_AIX_AIXC:
372 if (!aix_query_acl_support(jcr, ACL_AIXC, &type)) {
374 _("Trying to restore POSIX acl on file \"%s\" on filesystem without AIXC acl support\n"),
379 case STREAM_ACL_AIX_NFS4:
380 if (!aix_query_acl_support(jcr, ACL_NFS4, &type)) {
382 _("Trying to restore NFSv4 acl on file \"%s\" on filesystem without NFS4 acl support\n"),
389 } /* end switch (stream) */
392 * Set the acl buffer to an initial size. For now we set it
393 * to the same size as the ASCII representation.
395 aclbuf = check_pool_memory_size(aclbuf, content_length);
396 aclsize = content_length;
397 if (aclx_scanStr(content, aclbuf, &aclsize, type) < 0) {
403 * The buffer isn't big enough. The man page doesn't say that aclsize
404 * is updated to the needed size as what is done with aclx_printStr.
405 * So for now we try to increase the buffer a maximum of 3 times
406 * and retry the conversion.
408 for (cnt = 0; cnt < 3; cnt++) {
409 aclsize = 2 * aclsize;
410 aclbuf = check_pool_memory_size(aclbuf, aclsize);
412 if (aclx_scanStr(content, aclbuf, &aclsize, type) == 0) {
417 * See why we failed this time, ENOSPC retry if max retries not met,
430 _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
431 jcr->last_fname, be.bstrerror(errno));
432 Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
433 jcr->last_fname, be.bstrerror());
440 _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
441 jcr->last_fname, be.bstrerror());
442 Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
443 jcr->last_fname, be.bstrerror());
447 if (aclx_put(jcr->last_fname, SET_ACL, type, aclbuf, aclsize, 0) < 0) {
452 retval = bacl_exit_ok;
456 * If the filesystem reports it doesn't support ACLs we clear the
457 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
458 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
459 * when we change from one filesystem to an other.
461 jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
462 retval = bacl_exit_ok;
466 _("aclx_put error on file \"%s\": ERR=%s\n"),
467 jcr->last_fname, be.bstrerror());
468 Dmsg2(100, "aclx_put error file=%s ERR=%s\n",
469 jcr->last_fname, be.bstrerror());
474 retval = bacl_exit_ok;
477 free_pool_memory(aclbuf);
482 #else /* HAVE_EXTENDED_ACL */
484 #include <sys/access.h>
487 * Define the supported ACL streams for this OS
489 static int os_access_acl_streams[1] = {
492 static int os_default_acl_streams[1] = {
496 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
500 if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
501 jcr->acl_data->u.build->content_length =
502 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
503 actuallyfree(acl_text);
504 return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT);
506 return bacl_exit_error;
509 static bacl_exit_code aix_parse_acl_streams(JCR *jcr,
512 uint32_t content_length)
514 if (acl_put(jcr->last_fname, content, 0) != 0) {
515 return bacl_exit_error;
519 #endif /* HAVE_EXTENDED_ACL */
522 * For this OS setup the build and parse function pointer to the OS specific functions.
524 static bacl_exit_code (*os_build_acl_streams)
525 (JCR *jcr, FF_PKT *ff_pkt) =
526 aix_build_acl_streams;
527 static bacl_exit_code (*os_parse_acl_streams)
528 (JCR *jcr, int stream, char *content, uint32_t content_length) =
529 aix_parse_acl_streams;
531 #elif defined(HAVE_DARWIN_OS) || \
532 defined(HAVE_FREEBSD_OS) || \
533 defined(HAVE_IRIX_OS) || \
534 defined(HAVE_OSF1_OS) || \
535 defined(HAVE_LINUX_OS) || \
536 defined(HAVE_HURD_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) || \
636 defined(HAVE_HURD_OS)
640 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
641 while (entry_available == 1) {
643 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
645 #elif defined(HAVE_IRIX_OS)
646 count = acl->acl_cnt;
647 #elif defined(HAVE_OSF1_OS)
648 count = acl->acl_num;
649 #elif defined(HAVE_DARWIN_OS)
653 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
654 while (entry_available == 0) {
656 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
662 #if !defined(HAVE_DARWIN_OS)
664 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
665 * There is no need to store those acls as we already store the stat bits too.
667 static bool acl_is_trivial(acl_t acl)
670 * acl is trivial if it has only the following entries:
677 #if defined(HAVE_FREEBSD_OS) || \
678 defined(HAVE_LINUX_OS) || \
679 defined(HAVE_HURD_OS)
682 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
683 while (entry_available == 1) {
685 * Get the tag type of this acl entry.
686 * If we fail to get the tagtype we call the acl non-trivial.
688 if (acl_get_tag_type(ace, &tag) < 0)
691 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
693 if (tag != ACL_USER_OBJ &&
694 tag != ACL_GROUP_OBJ &&
697 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
700 #elif defined(HAVE_IRIX_OS)
703 for (n = 0; n < acl->acl_cnt; n++) {
704 ace = &acl->acl_entry[n];
708 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
710 if (tag != ACL_USER_OBJ &&
711 tag != ACL_GROUP_OBJ &&
712 tag != ACL_OTHER_OBJ)
716 #elif defined(HAVE_OSF1_OS)
719 ace = acl->acl_first;
720 count = acl->acl_num;
723 tag = ace->entry->acl_type;
725 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
727 if (tag != ACL_USER_OBJ &&
728 tag != ACL_GROUP_OBJ &&
732 * On Tru64, perm can also contain non-standard bits such as
733 * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
735 if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
746 * Generic wrapper around acl_get_file call.
748 static bacl_exit_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
753 bacl_exit_code retval = bacl_exit_ok;
755 ostype = bac_to_os_acltype(acltype);
756 acl = acl_get_file(jcr->last_fname, ostype);
759 * From observation, IRIX's acl_get_file() seems to return a
760 * non-NULL acl with a count field of -1 when a file has no ACL
761 * defined, while IRIX's acl_to_text() returns NULL when presented
764 * For all other implmentations we check if there are more then
765 * zero entries in the acl returned.
767 if (acl_count_entries(acl) <= 0) {
772 * Make sure this is not just a trivial ACL.
774 #if !defined(HAVE_DARWIN_OS)
775 if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
777 * The ACLs simply reflect the (already known) standard permissions
778 * So we don't send an ACL stream to the SD.
783 #if defined(HAVE_FREEBSD_OS) && defined(_PC_ACL_NFS4)
784 if (acltype == BACL_TYPE_NFS4) {
786 if (acl_is_trivial_np(acl, &trivial) == 0) {
789 * The ACLs simply reflect the (already known) standard permissions
790 * So we don't send an ACL stream to the SD.
799 * Convert the internal acl representation into a text representation.
801 if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
802 jcr->acl_data->u.build->content_length =
803 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
811 _("acl_to_text error on file \"%s\": ERR=%s\n"),
812 jcr->last_fname, be.bstrerror());
813 Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",
814 jcr->last_fname, be.bstrerror());
816 retval = bacl_exit_error;
822 * Handle errors gracefully.
825 #if defined(BACL_ENOTSUP)
828 * If the filesystem reports it doesn't support ACLs we clear the
829 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
830 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
831 * when we change from one filesystem to an other.
833 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
839 /* Some real error */
841 _("acl_get_file error on file \"%s\": ERR=%s\n"),
842 jcr->last_fname, be.bstrerror());
843 Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",
844 jcr->last_fname, be.bstrerror());
846 retval = bacl_exit_error;
855 pm_strcpy(jcr->acl_data->u.build->content, "");
856 jcr->acl_data->u.build->content_length = 0;
861 * Generic wrapper around acl_set_file call.
863 static bacl_exit_code generic_set_acl_on_os(JCR *jcr,
866 uint32_t content_length)
872 * If we get empty default ACLs, clear ACLs now
874 ostype = bac_to_os_acltype(acltype);
875 if (ostype == ACL_TYPE_DEFAULT && strlen(content) == 0) {
876 if (acl_delete_def_file(jcr->last_fname) == 0) {
884 #if defined(BACL_ENOTSUP)
887 * If the filesystem reports it doesn't support ACLs we clear the
888 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
889 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
890 * when we change from one filesystem to an other.
892 jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
894 _("acl_delete_def_file error on file \"%s\": filesystem doesn't support ACLs\n"),
896 return bacl_exit_error;
900 _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
901 jcr->last_fname, be.bstrerror());
902 return bacl_exit_error;
906 acl = acl_from_text(content);
911 _("acl_from_text error on file \"%s\": ERR=%s\n"),
912 jcr->last_fname, be.bstrerror());
913 Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",
914 content, jcr->last_fname, be.bstrerror());
915 return bacl_exit_error;
918 #ifndef HAVE_FREEBSD_OS
920 * FreeBSD always fails acl_valid() - at least on valid input...
921 * As it does the right thing, given valid input, just ignore acl_valid().
923 if (acl_valid(acl) != 0) {
927 _("acl_valid error on file \"%s\": ERR=%s\n"),
928 jcr->last_fname, be.bstrerror());
929 Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",
930 content, jcr->last_fname, be.bstrerror());
932 return bacl_exit_error;
937 * Restore the ACLs, but don't complain about links which really should
938 * not have attributes, and the file it is linked to may not yet be restored.
939 * This is only true for the old acl streams as in the new implementation we
940 * don't save acls of symlinks (which cannot have acls anyhow)
942 if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
949 #if defined(BACL_ENOTSUP)
952 * If the filesystem reports it doesn't support ACLs we clear the
953 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
954 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
955 * when we change from one filesystem to an other.
957 jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
959 _("acl_set_file error on file \"%s\": filesystem doesn't support ACLs\n"),
961 Dmsg2(100, "acl_set_file error acl=%s file=%s filesystem doesn't support ACLs\n",
962 content, jcr->last_fname);
964 return bacl_exit_error;
968 _("acl_set_file error on file \"%s\": ERR=%s\n"),
969 jcr->last_fname, be.bstrerror());
970 Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
971 content, jcr->last_fname, be.bstrerror());
973 return bacl_exit_error;
981 * OS specific functions for handling different types of acl streams.
983 #if defined(HAVE_DARWIN_OS)
985 * Define the supported ACL streams for this OS
987 static int os_access_acl_streams[1] = {
988 STREAM_ACL_DARWIN_ACCESS_ACL
990 static int os_default_acl_streams[1] = {
994 static bacl_exit_code darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
996 #if defined(HAVE_ACL_TYPE_EXTENDED)
998 * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
999 * and acl_get_file (name, ACL_TYPE_DEFAULT)
1000 * always return NULL / EINVAL. There is no point in making
1001 * these two useless calls. The real ACL is retrieved through
1002 * acl_get_file (name, ACL_TYPE_EXTENDED).
1004 * Read access ACLs for files, dirs and links
1006 if (generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED) == bacl_exit_fatal)
1007 return bacl_exit_fatal;
1010 * Read access ACLs for files, dirs and links
1012 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1013 return bacl_exit_fatal;
1016 if (jcr->acl_data->u.build->content_length > 0) {
1017 return send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL);
1019 return bacl_exit_ok;
1022 static bacl_exit_code darwin_parse_acl_streams(JCR *jcr,
1025 uint32_t content_length)
1027 #if defined(HAVE_ACL_TYPE_EXTENDED)
1028 return generic_set_acl_on_os(jcr, BACL_TYPE_EXTENDED, content, content_length);
1030 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1035 * For this OS setup the build and parse function pointer to the OS specific functions.
1037 static bacl_exit_code (*os_build_acl_streams)
1038 (JCR *jcr, FF_PKT *ff_pkt) =
1039 darwin_build_acl_streams;
1040 static bacl_exit_code (*os_parse_acl_streams)
1041 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1042 darwin_parse_acl_streams;
1044 #elif defined(HAVE_FREEBSD_OS)
1046 * Define the supported ACL streams for these OSes
1048 static int os_access_acl_streams[2] = {
1049 STREAM_ACL_FREEBSD_ACCESS_ACL,
1050 STREAM_ACL_FREEBSD_NFS4_ACL
1052 static int os_default_acl_streams[1] = {
1053 STREAM_ACL_FREEBSD_DEFAULT_ACL
1056 static bacl_exit_code freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1058 int acl_enabled = 0;
1059 bacl_type acltype = BACL_TYPE_NONE;
1061 #if defined(_PC_ACL_NFS4)
1063 * See if filesystem supports NFS4 acls.
1065 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
1066 switch (acl_enabled) {
1072 return bacl_exit_ok;
1075 _("pathconf error on file \"%s\": ERR=%s\n"),
1076 jcr->last_fname, be.bstrerror());
1077 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
1078 jcr->last_fname, be.bstrerror());
1079 return bacl_exit_error;
1085 acltype = BACL_TYPE_NFS4;
1090 if (acl_enabled == 0) {
1092 * See if filesystem supports POSIX acls.
1094 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
1095 switch (acl_enabled) {
1101 return bacl_exit_ok;
1104 _("pathconf error on file \"%s\": ERR=%s\n"),
1105 jcr->last_fname, be.bstrerror());
1106 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
1107 jcr->last_fname, be.bstrerror());
1108 return bacl_exit_error;
1114 acltype = BACL_TYPE_ACCESS;
1120 * If the filesystem reports it doesn't support ACLs we clear the
1121 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1122 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1123 * when we change from one filesystem to an other.
1125 if (acl_enabled == 0) {
1126 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1127 pm_strcpy(jcr->acl_data->u.build->content, "");
1128 jcr->acl_data->u.build->content_length = 0;
1129 return bacl_exit_ok;
1133 * Based on the supported ACLs retrieve and store them.
1136 case BACL_TYPE_NFS4:
1138 * Read NFS4 ACLs for files, dirs and links
1140 if (generic_get_acl_from_os(jcr, BACL_TYPE_NFS4) == bacl_exit_fatal)
1141 return bacl_exit_fatal;
1143 if (jcr->acl_data->u.build->content_length > 0) {
1144 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_NFS4_ACL) == bacl_exit_fatal)
1145 return bacl_exit_fatal;
1148 case BACL_TYPE_ACCESS:
1150 * Read access ACLs for files, dirs and links
1152 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1153 return bacl_exit_fatal;
1155 if (jcr->acl_data->u.build->content_length > 0) {
1156 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_ACCESS_ACL) == bacl_exit_fatal)
1157 return bacl_exit_fatal;
1161 * Directories can have default ACLs too
1163 if (ff_pkt->type == FT_DIREND) {
1164 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
1165 return bacl_exit_fatal;
1166 if (jcr->acl_data->u.build->content_length > 0) {
1167 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_DEFAULT_ACL) == bacl_exit_fatal)
1168 return bacl_exit_fatal;
1176 return bacl_exit_ok;
1179 static bacl_exit_code freebsd_parse_acl_streams(JCR *jcr,
1182 uint32_t content_length)
1184 int acl_enabled = 0;
1185 const char *acl_type_name;
1188 * First make sure the filesystem supports acls.
1191 case STREAM_UNIX_ACCESS_ACL:
1192 case STREAM_ACL_FREEBSD_ACCESS_ACL:
1193 case STREAM_UNIX_DEFAULT_ACL:
1194 case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1195 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
1196 acl_type_name = "POSIX";
1198 case STREAM_ACL_FREEBSD_NFS4_ACL:
1199 #if defined(_PC_ACL_NFS4)
1200 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
1202 acl_type_name = "NFS4";
1205 acl_type_name = "unknown";
1209 switch (acl_enabled) {
1215 return bacl_exit_ok;
1218 _("pathconf error on file \"%s\": ERR=%s\n"),
1219 jcr->last_fname, be.bstrerror());
1220 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1221 content, jcr->last_fname, be.bstrerror());
1222 return bacl_exit_error;
1227 * If the filesystem reports it doesn't support ACLs we clear the
1228 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
1229 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
1230 * when we change from one filesystem to an other.
1232 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1234 _("Trying to restore acl on file \"%s\" on filesystem without %s acl support\n"),
1235 jcr->last_fname, acl_type_name);
1236 return bacl_exit_error;
1245 case STREAM_UNIX_ACCESS_ACL:
1246 case STREAM_ACL_FREEBSD_ACCESS_ACL:
1247 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1248 case STREAM_UNIX_DEFAULT_ACL:
1249 case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1250 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1251 case STREAM_ACL_FREEBSD_NFS4_ACL:
1252 return generic_set_acl_on_os(jcr, BACL_TYPE_NFS4, content, content_length);
1256 return bacl_exit_error;
1260 * For this OSes setup the build and parse function pointer to the OS specific functions.
1262 static bacl_exit_code (*os_build_acl_streams)
1263 (JCR *jcr, FF_PKT *ff_pkt) =
1264 freebsd_build_acl_streams;
1265 static bacl_exit_code (*os_parse_acl_streams)
1266 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1267 freebsd_parse_acl_streams;
1269 #elif defined(HAVE_IRIX_OS) || \
1270 defined(HAVE_LINUX_OS) || \
1271 defined(HAVE_HURD_OS)
1273 * Define the supported ACL streams for these OSes
1275 #if defined(HAVE_IRIX_OS)
1276 static int os_access_acl_streams[1] = {
1277 STREAM_ACL_IRIX_ACCESS_ACL
1279 static int os_default_acl_streams[1] = {
1280 STREAM_ACL_IRIX_DEFAULT_ACL
1282 #elif defined(HAVE_LINUX_OS)
1283 static int os_access_acl_streams[1] = {
1284 STREAM_ACL_LINUX_ACCESS_ACL
1286 static int os_default_acl_streams[1] = {
1287 STREAM_ACL_LINUX_DEFAULT_ACL
1289 #elif defined(HAVE_HURD_OS)
1290 static int os_access_acl_streams[1] = {
1291 STREAM_ACL_HURD_ACCESS_ACL
1293 static int os_default_acl_streams[1] = {
1294 STREAM_ACL_HURD_DEFAULT_ACL
1298 static bacl_exit_code generic_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1301 * Read access ACLs for files, dirs and links
1303 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1304 return bacl_exit_fatal;
1306 if (jcr->acl_data->u.build->content_length > 0) {
1307 if (send_acl_stream(jcr, os_access_acl_streams[0]) == bacl_exit_fatal)
1308 return bacl_exit_fatal;
1312 * Directories can have default ACLs too
1314 if (ff_pkt->type == FT_DIREND) {
1315 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
1316 return bacl_exit_fatal;
1317 if (jcr->acl_data->u.build->content_length > 0) {
1318 if (send_acl_stream(jcr, os_default_acl_streams[0]) == bacl_exit_fatal)
1319 return bacl_exit_fatal;
1322 return bacl_exit_ok;
1325 static bacl_exit_code generic_parse_acl_streams(JCR *jcr,
1328 uint32_t content_length)
1333 case STREAM_UNIX_ACCESS_ACL:
1334 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1335 case STREAM_UNIX_DEFAULT_ACL:
1336 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1339 * See what type of acl it is.
1341 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1342 if (os_access_acl_streams[cnt] == stream) {
1343 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1346 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1347 if (os_default_acl_streams[cnt] == stream) {
1348 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1353 return bacl_exit_error;
1357 * For this OSes setup the build and parse function pointer to the OS specific functions.
1359 static bacl_exit_code (*os_build_acl_streams)
1360 (JCR *jcr, FF_PKT *ff_pkt) =
1361 generic_build_acl_streams;
1362 static bacl_exit_code (*os_parse_acl_streams)
1363 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1364 generic_parse_acl_streams;
1366 #elif defined(HAVE_OSF1_OS)
1369 * Define the supported ACL streams for this OS
1371 static int os_access_acl_streams[1] = {
1372 STREAM_ACL_TRU64_ACCESS_ACL
1374 static int os_default_acl_streams[2] = {
1375 STREAM_ACL_TRU64_DEFAULT_ACL,
1376 STREAM_ACL_TRU64_DEFAULT_DIR_ACL
1379 static bacl_exit_code tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1382 * Read access ACLs for files, dirs and links
1384 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal) {
1385 return bacl_exit_error;
1386 if (jcr->acl_data->u.build->content_length > 0) {
1387 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL))
1388 return bacl_exit_error;
1391 * Directories can have default ACLs too
1393 if (ff_pkt->type == FT_DIREND) {
1394 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal) {
1395 return bacl_exit_error;
1396 if (jcr->acl_data->u.build->content_length > 0) {
1397 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL))
1398 return bacl_exit_error;
1401 * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
1402 * This is an inherited acl for all subdirs.
1403 * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
1404 * Section 21.5 Default ACLs
1406 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR) == bacl_exit_fatal) {
1407 return bacl_exit_error;
1408 if (jcr->acl_data->u.build->content_length > 0) {
1409 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL))
1410 return bacl_exit_error;
1413 return bacl_exit_ok;
1416 static bacl_exit_code tru64_parse_acl_streams(JCR *jcr,
1419 uint32_t content_length)
1422 case STREAM_UNIX_ACCESS_ACL:
1423 case STREAM_ACL_TRU64_ACCESS_ACL:
1424 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1425 case STREAM_UNIX_DEFAULT_ACL:
1426 case STREAM_ACL_TRU64_DEFAULT_ACL:
1427 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1428 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
1429 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR, content, content_length);
1433 * For this OS setup the build and parse function pointer to the OS specific functions.
1435 static bacl_exit_code (*os_build_acl_streams)
1436 (JCR *jcr, FF_PKT *ff_pkt) =
1437 tru64_build_acl_streams;
1438 static bacl_exit_code (*os_parse_acl_streams)
1439 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1440 tru64_parse_acl_streams;
1444 #elif defined(HAVE_HPUX_OS)
1445 #ifdef HAVE_SYS_ACL_H
1446 #include <sys/acl.h>
1448 #error "configure failed to detect availability of sys/acl.h"
1454 * Define the supported ACL streams for this OS
1456 static int os_access_acl_streams[1] = {
1457 STREAM_ACL_HPUX_ACL_ENTRY
1459 static int os_default_acl_streams[1] = {
1464 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1465 * There is no need to store those acls as we already store the stat bits too.
1467 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
1470 struct acl_entry ace
1472 for (n = 0; n < count; n++) {
1475 * See if this acl just is the stat mode in acl form.
1477 if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
1478 (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
1479 (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
1486 * OS specific functions for handling different types of acl streams.
1488 static bacl_exit_code hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1491 struct acl_entry acls[NACLENTRIES];
1494 if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
1498 #if defined(BACL_ENOTSUP)
1501 * Not supported, just pretend there is nothing to see
1503 * If the filesystem reports it doesn't support ACLs we clear the
1504 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1505 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1506 * when we change from one filesystem to an other.
1508 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1509 pm_strcpy(jcr->acl_data->u.build->content, "");
1510 jcr->acl_data->u.build->content_length = 0;
1511 return bacl_exit_ok;
1514 pm_strcpy(jcr->acl_data->u.build->content, "");
1515 jcr->acl_data->u.build->content_length = 0;
1516 return bacl_exit_ok;
1519 _("getacl error on file \"%s\": ERR=%s\n"),
1520 jcr->last_fname, be.bstrerror());
1521 Dmsg2(100, "getacl error file=%s ERR=%s\n",
1522 jcr->last_fname, be.bstrerror());
1524 pm_strcpy(jcr->acl_data->u.build->content, "");
1525 jcr->acl_data->u.build->content_length = 0;
1526 return bacl_exit_error;
1530 pm_strcpy(jcr->acl_data->u.build->content, "");
1531 jcr->acl_data->u.build->content_length = 0;
1532 return bacl_exit_ok;
1534 if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
1535 if (acl_is_trivial(n, acls, ff_pkt->statp)) {
1537 * The ACLs simply reflect the (already known) standard permissions
1538 * So we don't send an ACL stream to the SD.
1540 pm_strcpy(jcr->acl_data->u.build->content, "");
1541 jcr->acl_data->u.build->content_length = 0;
1542 return bacl_exit_ok;
1544 if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
1545 jcr->acl_data->u.build->content_length =
1546 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
1547 actuallyfree(acl_text);
1549 return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
1554 _("acltostr error on file \"%s\": ERR=%s\n"),
1555 jcr->last_fname, be.bstrerror());
1556 Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",
1557 jcr->acl_data->u.build->content, jcr->last_fname, be.bstrerror());
1558 return bacl_exit_error;
1560 return bacl_exit_error;
1563 static bacl_exit_code hpux_parse_acl_streams(JCR *jcr,
1566 uint32_t content_length)
1569 struct acl_entry acls[NACLENTRIES];
1571 n = strtoacl(content, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
1576 _("strtoacl error on file \"%s\": ERR=%s\n"),
1577 jcr->last_fname, be.bstrerror());
1578 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
1579 content, jcr->last_fname, be.bstrerror());
1580 return bacl_exit_error;
1582 if (strtoacl(content, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
1586 _("strtoacl error on file \"%s\": ERR=%s\n"),
1587 jcr->last_fname, be.bstrerror());
1588 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
1589 content, jcr->last_fname, be.bstrerror());
1591 return bacl_exit_error;
1594 * Restore the ACLs, but don't complain about links which really should
1595 * not have attributes, and the file it is linked to may not yet be restored.
1596 * This is only true for the old acl streams as in the new implementation we
1597 * don't save acls of symlinks (which cannot have acls anyhow)
1599 if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
1604 return bacl_exit_ok;
1605 #if defined(BACL_ENOTSUP)
1608 * If the filesystem reports it doesn't support ACLs we clear the
1609 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
1610 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
1611 * when we change from one filesystem to an other.
1613 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1615 _("setacl error on file \"%s\": filesystem doesn't support ACLs\n"),
1617 Dmsg2(100, "setacl error acl=%s file=%s filesystem doesn't support ACLs\n",
1618 content, jcr->last_fname);
1619 return bacl_exit_error;
1623 _("setacl error on file \"%s\": ERR=%s\n"),
1624 jcr->last_fname, be.bstrerror());
1625 Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
1626 content, jcr->last_fname, be.bstrerror());
1627 return bacl_exit_error;
1630 return bacl_exit_ok;
1634 * For this OS setup the build and parse function pointer to the OS specific functions.
1636 static bacl_exit_code (*os_build_acl_streams)
1637 (JCR *jcr, FF_PKT *ff_pkt) =
1638 hpux_build_acl_streams;
1639 static bacl_exit_code (*os_parse_acl_streams)
1640 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1641 hpux_parse_acl_streams;
1643 #elif defined(HAVE_SUN_OS)
1644 #ifdef HAVE_SYS_ACL_H
1645 #include <sys/acl.h>
1647 #error "configure failed to detect availability of sys/acl.h"
1650 #if defined(HAVE_EXTENDED_ACL)
1652 * We define some internals of the Solaris acl libs here as those
1653 * are not exposed yet. Probably because they want us to see the
1654 * acls as opague data. But as we need to support different platforms
1655 * and versions of Solaris we need to expose some data to be able
1656 * to determine the type of acl used to stuff it into the correct
1657 * data stream. I know this is far from portable, but maybe the
1658 * proper interface is exposed later on and we can get ride of
1659 * this kludge. Newer versions of Solaris include sys/acl_impl.h
1660 * which has implementation details of acls, if thats included we
1661 * don't have to define it ourself.
1663 #if !defined(_SYS_ACL_IMPL_H)
1664 typedef enum acl_type {
1671 * Two external references to functions in the libsec library function not in current include files.
1674 int acl_type(acl_t *);
1675 char *acl_strerror(int);
1679 * Define the supported ACL streams for this OS
1681 static int os_access_acl_streams[2] = {
1682 STREAM_ACL_SOLARIS_ACLENT,
1683 STREAM_ACL_SOLARIS_ACE
1685 static int os_default_acl_streams[1] = {
1690 * As the new libsec interface with acl_totext and acl_fromtext also handles
1691 * the old format from acltotext we can use the new functions even
1692 * for acls retrieved and stored in the database with older fd versions. If the
1693 * new interface is not defined (Solaris 9 and older we fall back to the old code)
1695 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1697 int acl_enabled, flags;
1700 bacl_exit_code stream_status = bacl_exit_error;
1703 * See if filesystem supports acls.
1705 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1706 switch (acl_enabled) {
1709 * If the filesystem reports it doesn't support ACLs we clear the
1710 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1711 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1712 * when we change from one filesystem to an other.
1714 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1715 pm_strcpy(jcr->acl_data->u.build->content, "");
1716 jcr->acl_data->u.build->content_length = 0;
1717 return bacl_exit_ok;
1723 return bacl_exit_ok;
1726 _("pathconf error on file \"%s\": ERR=%s\n"),
1727 jcr->last_fname, be.bstrerror());
1728 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
1729 jcr->last_fname, be.bstrerror());
1730 return bacl_exit_error;
1738 * Get ACL info: don't bother allocating space if there is only a trivial ACL.
1740 if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
1745 return bacl_exit_ok;
1748 _("acl_get error on file \"%s\": ERR=%s\n"),
1749 jcr->last_fname, acl_strerror(errno));
1750 Dmsg2(100, "acl_get error file=%s ERR=%s\n",
1751 jcr->last_fname, acl_strerror(errno));
1752 return bacl_exit_error;
1758 * The ACLs simply reflect the (already known) standard permissions
1759 * So we don't send an ACL stream to the SD.
1761 pm_strcpy(jcr->acl_data->u.build->content, "");
1762 jcr->acl_data->u.build->content_length = 0;
1763 return bacl_exit_ok;
1766 #if defined(ACL_SID_FMT)
1768 * New format flag added in newer Solaris versions.
1770 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
1772 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
1773 #endif /* ACL_SID_FMT */
1775 if ((acl_text = acl_totext(aclp, flags)) != NULL) {
1776 jcr->acl_data->u.build->content_length =
1777 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
1778 actuallyfree(acl_text);
1780 switch (acl_type(aclp)) {
1782 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1785 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE);
1793 return stream_status;
1796 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr,
1799 uint32_t content_length)
1802 int acl_enabled, error;
1805 case STREAM_UNIX_ACCESS_ACL:
1806 case STREAM_ACL_SOLARIS_ACLENT:
1807 case STREAM_ACL_SOLARIS_ACE:
1809 * First make sure the filesystem supports acls.
1811 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1812 switch (acl_enabled) {
1815 * If the filesystem reports it doesn't support ACLs we clear the
1816 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
1817 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
1818 * when we change from one filesystem to an other.
1820 jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
1822 _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
1824 return bacl_exit_error;
1830 return bacl_exit_ok;
1833 _("pathconf error on file \"%s\": ERR=%s\n"),
1834 jcr->last_fname, be.bstrerror());
1835 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1836 content, jcr->last_fname, be.bstrerror());
1837 return bacl_exit_error;
1842 * On a filesystem with ACL support make sure this particular ACL type can be restored.
1845 case STREAM_ACL_SOLARIS_ACLENT:
1847 * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
1849 if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
1851 _("Trying to restore POSIX acl on file \"%s\" on filesystem without aclent acl support\n"),
1853 return bacl_exit_error;
1856 case STREAM_ACL_SOLARIS_ACE:
1858 * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
1860 if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
1862 _("Trying to restore NFSv4 acl on file \"%s\" on filesystem without ace acl support\n"),
1864 return bacl_exit_error;
1869 * Stream id which doesn't describe the type of acl which is encoded.
1876 if ((error = acl_fromtext(content, &aclp)) != 0) {
1878 _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1879 jcr->last_fname, acl_strerror(error));
1880 Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",
1881 content, jcr->last_fname, acl_strerror(error));
1882 return bacl_exit_error;
1886 * Validate that the conversion gave us the correct acl type.
1889 case STREAM_ACL_SOLARIS_ACLENT:
1890 if (acl_type(aclp) != ACLENT_T) {
1892 _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1894 return bacl_exit_error;
1897 case STREAM_ACL_SOLARIS_ACE:
1898 if (acl_type(aclp) != ACE_T) {
1900 _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1902 return bacl_exit_error;
1907 * Stream id which doesn't describe the type of acl which is encoded.
1913 * Restore the ACLs, but don't complain about links which really should
1914 * not have attributes, and the file it is linked to may not yet be restored.
1915 * This is only true for the old acl streams as in the new implementation we
1916 * don't save acls of symlinks (which cannot have acls anyhow)
1918 if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1922 return bacl_exit_ok;
1925 _("acl_set error on file \"%s\": ERR=%s\n"),
1926 jcr->last_fname, acl_strerror(error));
1927 Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",
1928 content, jcr->last_fname, acl_strerror(error));
1930 return bacl_exit_error;
1935 return bacl_exit_ok;
1937 return bacl_exit_error;
1938 } /* end switch (stream) */
1941 #else /* HAVE_EXTENDED_ACL */
1944 * Define the supported ACL streams for this OS
1946 static int os_access_acl_streams[1] = {
1947 STREAM_ACL_SOLARIS_ACLENT
1949 static int os_default_acl_streams[1] = {
1954 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1955 * There is no need to store those acls as we already store the stat bits too.
1957 static bool acl_is_trivial(int count, aclent_t *entries)
1962 for (n = 0; n < count; n++) {
1965 if (!(ace->a_type == USER_OBJ ||
1966 ace->a_type == GROUP_OBJ ||
1967 ace->a_type == OTHER_OBJ ||
1968 ace->a_type == CLASS_OBJ))
1975 * OS specific functions for handling different types of acl streams.
1977 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1983 n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1984 if (n < MIN_ACL_ENTRIES) {
1985 return bacl_exit_error;
1988 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1989 if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1990 if (acl_is_trivial(n, acls)) {
1992 * The ACLs simply reflect the (already known) standard permissions
1993 * So we don't send an ACL stream to the SD.
1996 pm_strcpy(jcr->acl_data->u.build->content, "");
1997 jcr->acl_data->u.build->content_length = 0;
1998 return bacl_exit_ok;
2001 if ((acl_text = acltotext(acls, n)) != NULL) {
2002 jcr->acl_data->u.build->content_length =
2003 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
2004 actuallyfree(acl_text);
2006 return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
2011 _("acltotext error on file \"%s\": ERR=%s\n"),
2012 jcr->last_fname, be.bstrerror());
2013 Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",
2014 jcr->acl_data->u.build->content, jcr->last_fname, be.bstrerror());
2018 return bacl_exit_error;
2021 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr,
2024 uint32_t content_length)
2029 acls = aclfromtext(content, &n);
2034 _("aclfromtext error on file \"%s\": ERR=%s\n"),
2035 jcr->last_fname, be.bstrerror());
2036 Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",
2037 content, jcr->last_fname, be.bstrerror());
2038 return bacl_exit_error;
2042 * Restore the ACLs, but don't complain about links which really should
2043 * not have attributes, and the file it is linked to may not yet be restored.
2045 if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
2051 return bacl_exit_ok;
2054 _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
2055 jcr->last_fname, be.bstrerror());
2056 Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
2057 content, jcr->last_fname, be.bstrerror());
2059 return bacl_exit_error;
2063 return bacl_exit_ok;
2065 #endif /* HAVE_EXTENDED_ACL */
2068 * For this OS setup the build and parse function pointer to the OS specific functions.
2070 static bacl_exit_code (*os_build_acl_streams)
2071 (JCR *jcr, FF_PKT *ff_pkt) =
2072 solaris_build_acl_streams;
2073 static bacl_exit_code (*os_parse_acl_streams)
2074 (JCR *jcr, int stream, char *content, uint32_t content_length) =
2075 solaris_parse_acl_streams;
2077 #endif /* HAVE_SUN_OS */
2078 #endif /* HAVE_ACL */
2080 #if defined(HAVE_AFS_ACL)
2082 #if defined(HAVE_AFS_AFSINT_H) && defined(HAVE_AFS_VENUS_H)
2083 #include <afs/afsint.h>
2084 #include <afs/venus.h>
2086 #error "configure failed to detect availability of afs/afsint.h and/or afs/venus.h"
2090 * External references to functions in the libsys library function not in current include files.
2093 long pioctl(char *pathp, long opcode, struct ViceIoctl *blobp, int follow);
2096 static bacl_exit_code afs_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
2099 struct ViceIoctl vip;
2100 char acl_text[BUFSIZ];
2103 * AFS ACLs can only be set on a directory, so no need to try to
2104 * request them for anything other then that.
2106 if (ff_pkt->type != FT_DIREND) {
2107 return bacl_exit_ok;
2113 vip.out_size = sizeof(acl_text);
2114 memset((caddr_t)acl_text, 0, sizeof(acl_text));
2116 if ((error = pioctl(jcr->last_fname, VIOCGETAL, &vip, 0)) < 0) {
2120 _("pioctl VIOCGETAL error on file \"%s\": ERR=%s\n"),
2121 jcr->last_fname, be.bstrerror());
2122 Dmsg2(100, "pioctl VIOCGETAL error file=%s ERR=%s\n",
2123 jcr->last_fname, be.bstrerror());
2124 return bacl_exit_error;
2126 jcr->acl_data->u.build->content_length =
2127 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
2128 return send_acl_stream(jcr, STREAM_ACL_AFS_TEXT);
2131 static bacl_exit_code afs_parse_acl_stream(JCR *jcr,
2134 uint32_t content_length)
2137 struct ViceIoctl vip;
2140 vip.in_size = content_length;
2144 if ((error = pioctl(jcr->last_fname, VIOCSETAL, &vip, 0)) < 0) {
2148 _("pioctl VIOCSETAL error on file \"%s\": ERR=%s\n"),
2149 jcr->last_fname, be.bstrerror());
2150 Dmsg2(100, "pioctl VIOCSETAL error file=%s ERR=%s\n",
2151 jcr->last_fname, be.bstrerror());
2153 return bacl_exit_error;
2155 return bacl_exit_ok;
2157 #endif /* HAVE_AFS_ACL */
2160 * Entry points when compiled with support for ACLs on a supported platform.
2164 * Read and send an ACL for the last encountered file.
2166 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
2169 * See if we are changing from one device to an other.
2170 * We save the current device we are scanning and compare
2171 * it with the current st_dev in the last stat performed on
2172 * the file we are currently storing.
2174 if (jcr->acl_data->current_dev != ff_pkt->statp.st_dev) {
2176 * Reset the acl save flags.
2178 jcr->acl_data->flags = 0;
2180 #if defined(HAVE_AFS_ACL)
2182 * AFS is a non OS specific filesystem so see if this path is on an AFS filesystem
2183 * Set the BACL_FLAG_SAVE_AFS flag if it is. If not set the BACL_FLAG_SAVE_NATIVE flag.
2185 if (fstype_equals(jcr->last_fname, "afs")) {
2186 jcr->acl_data->flags |= BACL_FLAG_SAVE_AFS;
2188 jcr->acl_data->flags |= BACL_FLAG_SAVE_NATIVE;
2191 jcr->acl_data->flags |= BACL_FLAG_SAVE_NATIVE;
2195 * Save that we started scanning a new filesystem.
2197 jcr->acl_data->current_dev = ff_pkt->statp.st_dev;
2200 #if defined(HAVE_AFS_ACL)
2202 * See if the BACL_FLAG_SAVE_AFS flag is set which lets us know if we should
2205 if (jcr->acl_data->flags & BACL_FLAG_SAVE_AFS) {
2206 return afs_build_acl_streams(jcr, ff_pkt);
2209 #if defined(HAVE_ACL)
2211 * See if the BACL_FLAG_SAVE_NATIVE flag is set which lets us know if we should
2214 if (jcr->acl_data->flags & BACL_FLAG_SAVE_NATIVE) {
2216 * Call the appropriate function.
2218 if (os_build_acl_streams) {
2219 return os_build_acl_streams(jcr, ff_pkt);
2222 return bacl_exit_ok;
2225 return bacl_exit_error;
2228 bacl_exit_code parse_acl_streams(JCR *jcr,
2231 uint32_t content_length)
2238 * See if we are changing from one device to an other.
2239 * We save the current device we are restoring to and compare
2240 * it with the current st_dev in the last stat performed on
2241 * the file we are currently restoring.
2243 ret = lstat(jcr->last_fname, &st);
2250 return bacl_exit_ok;
2253 _("Unable to stat file \"%s\": ERR=%s\n"),
2254 jcr->last_fname, be.bstrerror());
2255 Dmsg2(100, "Unable to stat file \"%s\": ERR=%s\n",
2256 jcr->last_fname, be.bstrerror());
2257 return bacl_exit_error;
2264 if (jcr->acl_data->current_dev != st.st_dev) {
2266 * Reset the acl save flags.
2268 jcr->acl_data->flags = 0;
2270 #if defined(HAVE_AFS_ACL)
2272 * AFS is a non OS specific filesystem so see if this path is on an AFS filesystem
2273 * Set the BACL_FLAG_RESTORE_AFS flag if it is. If not set the BACL_FLAG_RETORE_NATIVE flag.
2275 if (fstype_equals(jcr->last_fname, "afs")) {
2276 jcr->acl_data->flags |= BACL_FLAG_RESTORE_AFS;
2278 jcr->acl_data->flags |= BACL_FLAG_RESTORE_NATIVE;
2281 jcr->acl_data->flags |= BACL_FLAG_RESTORE_NATIVE;
2285 * Save that we started restoring to a new filesystem.
2287 jcr->acl_data->current_dev = st.st_dev;
2291 #if defined(HAVE_AFS_ACL)
2292 case STREAM_ACL_AFS_TEXT:
2293 if (jcr->acl_data->flags & BACL_FLAG_RESTORE_AFS) {
2294 return afs_parse_acl_stream(jcr, stream, content, content_length);
2297 * Increment error count but don't log an error again for the same filesystem.
2299 jcr->acl_data->u.parse->nr_errors++;
2300 return bacl_exit_ok;
2303 #if defined(HAVE_ACL)
2304 case STREAM_UNIX_ACCESS_ACL:
2305 case STREAM_UNIX_DEFAULT_ACL:
2307 * Handle legacy ACL streams.
2309 if ((jcr->acl_data->flags & BACL_FLAG_RESTORE_NATIVE) && os_parse_acl_streams) {
2310 return os_parse_acl_streams(jcr, stream, content, content_length);
2313 * Increment error count but don't log an error again for the same filesystem.
2315 jcr->acl_data->u.parse->nr_errors++;
2316 return bacl_exit_ok;
2320 if ((jcr->acl_data->flags & BACL_FLAG_RESTORE_NATIVE) && os_parse_acl_streams) {
2322 * Walk the os_access_acl_streams array with the supported Access ACL streams for this OS.
2324 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
2325 if (os_access_acl_streams[cnt] == stream) {
2326 return os_parse_acl_streams(jcr, stream, content, content_length);
2330 * Walk the os_default_acl_streams array with the supported Default ACL streams for this OS.
2332 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
2333 if (os_default_acl_streams[cnt] == stream) {
2334 return os_parse_acl_streams(jcr, stream, content, content_length);
2339 * Increment error count but don't log an error again for the same filesystem.
2341 jcr->acl_data->u.parse->nr_errors++;
2342 return bacl_exit_ok;
2350 Qmsg2(jcr, M_WARNING, 0,
2351 _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
2352 jcr->last_fname, stream);
2353 return bacl_exit_error;