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);
315 retval = send_acl_stream(jcr, STREAM_ACL_AIX_NFS4);
320 free_pool_memory(aclbuf);
326 * See if a specific type of ACLs are supported on the filesystem
327 * the file is located on.
329 static inline bool aix_query_acl_support(JCR *jcr,
331 acl_type_t *pacl_type_info)
334 acl_types_list_t acl_type_list;
335 size_t acl_type_list_len = sizeof(acl_types_list_t);
337 memset(&acl_type_list, 0, sizeof(acl_type_list));
338 if (aclx_gettypes(jcr->last_fname, &acl_type_list, &acl_type_list_len)) {
342 for (i = 0; i < acl_type_list.num_entries; i++) {
343 if (acl_type_list.entries[i].u64 == aclType) {
344 memcpy(pacl_type_info, acl_type_list.entries + i, sizeof(acl_type_t));
351 static bacl_exit_code aix_parse_acl_streams(JCR *jcr,
354 uint32_t content_length)
359 bacl_exit_code retval = bacl_exit_error;
360 POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
363 case STREAM_ACL_AIX_TEXT:
365 * Handle the old stream using the old system call for now.
367 if (acl_put(jcr->last_fname, content, 0) != 0) {
368 retval = bacl_exit_error;
371 retval = bacl_exit_ok;
373 case STREAM_ACL_AIX_AIXC:
374 if (!aix_query_acl_support(jcr, ACL_AIXC, &type)) {
376 _("Trying to restore POSIX acl on file \"%s\" on filesystem without AIXC acl support\n"),
381 case STREAM_ACL_AIX_NFS4:
382 if (!aix_query_acl_support(jcr, ACL_NFS4, &type)) {
384 _("Trying to restore NFSv4 acl on file \"%s\" on filesystem without NFS4 acl support\n"),
391 } /* end switch (stream) */
394 * Set the acl buffer to an initial size. For now we set it
395 * to the same size as the ASCII representation.
397 aclbuf = check_pool_memory_size(aclbuf, content_length);
398 aclsize = content_length;
399 if (aclx_scanStr(content, aclbuf, &aclsize, type) < 0) {
405 * The buffer isn't big enough. The man page doesn't say that aclsize
406 * is updated to the needed size as what is done with aclx_printStr.
407 * So for now we try to increase the buffer a maximum of 3 times
408 * and retry the conversion.
410 for (cnt = 0; cnt < 3; cnt++) {
411 aclsize = 2 * aclsize;
412 aclbuf = check_pool_memory_size(aclbuf, aclsize);
414 if (aclx_scanStr(content, aclbuf, &aclsize, type) == 0) {
419 * See why we failed this time, ENOSPC retry if max retries not met,
432 _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
433 jcr->last_fname, be.bstrerror(errno));
434 Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
435 jcr->last_fname, be.bstrerror());
442 _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
443 jcr->last_fname, be.bstrerror());
444 Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
445 jcr->last_fname, be.bstrerror());
449 if (aclx_put(jcr->last_fname, SET_ACL, type, aclbuf, aclsize, 0) < 0) {
454 retval = bacl_exit_ok;
458 * If the filesystem reports it doesn't support ACLs we clear the
459 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
460 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
461 * when we change from one filesystem to an other.
463 jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
464 retval = bacl_exit_ok;
468 _("aclx_put error on file \"%s\": ERR=%s\n"),
469 jcr->last_fname, be.bstrerror());
470 Dmsg2(100, "aclx_put error file=%s ERR=%s\n",
471 jcr->last_fname, be.bstrerror());
476 retval = bacl_exit_ok;
479 free_pool_memory(aclbuf);
484 #else /* HAVE_EXTENDED_ACL */
486 #include <sys/access.h>
489 * Define the supported ACL streams for this OS
491 static int os_access_acl_streams[1] = {
494 static int os_default_acl_streams[1] = {
498 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
502 if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
503 jcr->acl_data->u.build->content_length =
504 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
505 actuallyfree(acl_text);
506 return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT);
508 return bacl_exit_error;
511 static bacl_exit_code aix_parse_acl_streams(JCR *jcr,
514 uint32_t content_length)
516 if (acl_put(jcr->last_fname, content, 0) != 0) {
517 return bacl_exit_error;
521 #endif /* HAVE_EXTENDED_ACL */
524 * For this OS setup the build and parse function pointer to the OS specific functions.
526 static bacl_exit_code (*os_build_acl_streams)
527 (JCR *jcr, FF_PKT *ff_pkt) =
528 aix_build_acl_streams;
529 static bacl_exit_code (*os_parse_acl_streams)
530 (JCR *jcr, int stream, char *content, uint32_t content_length) =
531 aix_parse_acl_streams;
533 #elif defined(HAVE_DARWIN_OS) || \
534 defined(HAVE_FREEBSD_OS) || \
535 defined(HAVE_IRIX_OS) || \
536 defined(HAVE_OSF1_OS) || \
537 defined(HAVE_LINUX_OS) || \
538 defined(HAVE_HURD_OS)
540 #include <sys/types.h>
542 #ifdef HAVE_SYS_ACL_H
545 #error "configure failed to detect availability of sys/acl.h"
549 * On IRIX we can get shortened ACLs
551 #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
552 #define acl_to_text(acl,len) acl_to_short_text((acl), (len))
556 * On Linux we can get numeric and/or shorted ACLs
558 #if defined(HAVE_LINUX_OS)
559 #if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
560 #define BACL_ALTERNATE_TEXT (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
561 #elif defined(BACL_WANT_SHORT_ACLS)
562 #define BACL_ALTERNATE_TEXT TEXT_ABBREVIATE
563 #elif defined(BACL_WANT_NUMERIC_IDS)
564 #define BACL_ALTERNATE_TEXT TEXT_NUMERIC_IDS
566 #ifdef BACL_ALTERNATE_TEXT
567 #include <acl/libacl.h>
568 #define acl_to_text(acl,len) (acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
573 * On FreeBSD we can get numeric ACLs
575 #if defined(HAVE_FREEBSD_OS)
576 #if defined(BACL_WANT_NUMERIC_IDS)
577 #define BACL_ALTERNATE_TEXT ACL_TEXT_NUMERIC_IDS
579 #ifdef BACL_ALTERNATE_TEXT
580 #define acl_to_text(acl,len) (acl_to_text_np((acl), (len), BACL_ALTERNATE_TEXT))
585 * Some generic functions used by multiple OSes.
587 static acl_type_t bac_to_os_acltype(bacl_type acltype)
592 case BACL_TYPE_ACCESS:
593 ostype = ACL_TYPE_ACCESS;
595 case BACL_TYPE_DEFAULT:
596 ostype = ACL_TYPE_DEFAULT;
598 #ifdef HAVE_ACL_TYPE_NFS4
600 * FreeBSD has an additional acl type named ACL_TYPE_NFS4.
603 ostype = ACL_TYPE_NFS4;
606 #ifdef HAVE_ACL_TYPE_DEFAULT_DIR
607 case BACL_TYPE_DEFAULT_DIR:
609 * TRU64 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
611 ostype = ACL_TYPE_DEFAULT_DIR;
614 #ifdef HAVE_ACL_TYPE_EXTENDED
615 case BACL_TYPE_EXTENDED:
617 * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
619 ostype = ACL_TYPE_EXTENDED;
624 * This should never happen, as the per OS version function only tries acl
625 * types supported on a certain platform.
627 ostype = (acl_type_t)ACL_TYPE_NONE;
633 static int acl_count_entries(acl_t acl)
636 #if defined(HAVE_FREEBSD_OS) || \
637 defined(HAVE_LINUX_OS) || \
638 defined(HAVE_HURD_OS)
642 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
643 while (entry_available == 1) {
645 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
647 #elif defined(HAVE_IRIX_OS)
648 count = acl->acl_cnt;
649 #elif defined(HAVE_OSF1_OS)
650 count = acl->acl_num;
651 #elif defined(HAVE_DARWIN_OS)
655 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
656 while (entry_available == 0) {
658 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
664 #if !defined(HAVE_DARWIN_OS)
666 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
667 * There is no need to store those acls as we already store the stat bits too.
669 static bool acl_is_trivial(acl_t acl)
672 * acl is trivial if it has only the following entries:
679 #if defined(HAVE_FREEBSD_OS) || \
680 defined(HAVE_LINUX_OS) || \
681 defined(HAVE_HURD_OS)
684 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
685 while (entry_available == 1) {
687 * Get the tag type of this acl entry.
688 * If we fail to get the tagtype we call the acl non-trivial.
690 if (acl_get_tag_type(ace, &tag) < 0)
693 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
695 if (tag != ACL_USER_OBJ &&
696 tag != ACL_GROUP_OBJ &&
699 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
702 #elif defined(HAVE_IRIX_OS)
705 for (n = 0; n < acl->acl_cnt; n++) {
706 ace = &acl->acl_entry[n];
710 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
712 if (tag != ACL_USER_OBJ &&
713 tag != ACL_GROUP_OBJ &&
714 tag != ACL_OTHER_OBJ)
718 #elif defined(HAVE_OSF1_OS)
721 ace = acl->acl_first;
722 count = acl->acl_num;
725 tag = ace->entry->acl_type;
727 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
729 if (tag != ACL_USER_OBJ &&
730 tag != ACL_GROUP_OBJ &&
734 * On Tru64, perm can also contain non-standard bits such as
735 * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
737 if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
748 * Generic wrapper around acl_get_file call.
750 static bacl_exit_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
755 bacl_exit_code retval = bacl_exit_ok;
757 ostype = bac_to_os_acltype(acltype);
758 acl = acl_get_file(jcr->last_fname, ostype);
761 * From observation, IRIX's acl_get_file() seems to return a
762 * non-NULL acl with a count field of -1 when a file has no ACL
763 * defined, while IRIX's acl_to_text() returns NULL when presented
766 * For all other implmentations we check if there are more then
767 * zero entries in the acl returned.
769 if (acl_count_entries(acl) <= 0) {
774 * Make sure this is not just a trivial ACL.
776 #if !defined(HAVE_DARWIN_OS)
777 if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
779 * The ACLs simply reflect the (already known) standard permissions
780 * So we don't send an ACL stream to the SD.
785 #if defined(HAVE_FREEBSD_OS) && defined(_PC_ACL_NFS4)
786 if (acltype == BACL_TYPE_NFS4) {
788 if (acl_is_trivial_np(acl, &trivial) == 0) {
791 * The ACLs simply reflect the (already known) standard permissions
792 * So we don't send an ACL stream to the SD.
801 * Convert the internal acl representation into a text representation.
803 if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
804 jcr->acl_data->u.build->content_length =
805 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
813 _("acl_to_text error on file \"%s\": ERR=%s\n"),
814 jcr->last_fname, be.bstrerror());
815 Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",
816 jcr->last_fname, be.bstrerror());
818 retval = bacl_exit_error;
824 * Handle errors gracefully.
827 #if defined(BACL_ENOTSUP)
830 * If the filesystem reports it doesn't support ACLs we clear the
831 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
832 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
833 * when we change from one filesystem to an other.
835 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
841 /* Some real error */
843 _("acl_get_file error on file \"%s\": ERR=%s\n"),
844 jcr->last_fname, be.bstrerror());
845 Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",
846 jcr->last_fname, be.bstrerror());
848 retval = bacl_exit_error;
857 pm_strcpy(jcr->acl_data->u.build->content, "");
858 jcr->acl_data->u.build->content_length = 0;
863 * Generic wrapper around acl_set_file call.
865 static bacl_exit_code generic_set_acl_on_os(JCR *jcr,
868 uint32_t content_length)
874 * If we get empty default ACLs, clear ACLs now
876 ostype = bac_to_os_acltype(acltype);
877 if (ostype == ACL_TYPE_DEFAULT && strlen(content) == 0) {
878 if (acl_delete_def_file(jcr->last_fname) == 0) {
886 #if defined(BACL_ENOTSUP)
889 * If the filesystem reports it doesn't support ACLs we clear the
890 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
891 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
892 * when we change from one filesystem to an other.
894 jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
896 _("acl_delete_def_file error on file \"%s\": filesystem doesn't support ACLs\n"),
898 return bacl_exit_error;
902 _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
903 jcr->last_fname, be.bstrerror());
904 return bacl_exit_error;
908 acl = acl_from_text(content);
913 _("acl_from_text error on file \"%s\": ERR=%s\n"),
914 jcr->last_fname, be.bstrerror());
915 Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",
916 content, jcr->last_fname, be.bstrerror());
917 return bacl_exit_error;
920 #ifndef HAVE_FREEBSD_OS
922 * FreeBSD always fails acl_valid() - at least on valid input...
923 * As it does the right thing, given valid input, just ignore acl_valid().
925 if (acl_valid(acl) != 0) {
929 _("acl_valid error on file \"%s\": ERR=%s\n"),
930 jcr->last_fname, be.bstrerror());
931 Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",
932 content, jcr->last_fname, be.bstrerror());
934 return bacl_exit_error;
939 * Restore the ACLs, but don't complain about links which really should
940 * not have attributes, and the file it is linked to may not yet be restored.
941 * This is only true for the old acl streams as in the new implementation we
942 * don't save acls of symlinks (which cannot have acls anyhow)
944 if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
951 #if defined(BACL_ENOTSUP)
954 * If the filesystem reports it doesn't support ACLs we clear the
955 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
956 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
957 * when we change from one filesystem to an other.
959 jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
961 _("acl_set_file error on file \"%s\": filesystem doesn't support ACLs\n"),
963 Dmsg2(100, "acl_set_file error acl=%s file=%s filesystem doesn't support ACLs\n",
964 content, jcr->last_fname);
966 return bacl_exit_error;
970 _("acl_set_file error on file \"%s\": ERR=%s\n"),
971 jcr->last_fname, be.bstrerror());
972 Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
973 content, jcr->last_fname, be.bstrerror());
975 return bacl_exit_error;
983 * OS specific functions for handling different types of acl streams.
985 #if defined(HAVE_DARWIN_OS)
987 * Define the supported ACL streams for this OS
989 static int os_access_acl_streams[1] = {
990 STREAM_ACL_DARWIN_ACCESS_ACL
992 static int os_default_acl_streams[1] = {
996 static bacl_exit_code darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
998 #if defined(HAVE_ACL_TYPE_EXTENDED)
1000 * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
1001 * and acl_get_file (name, ACL_TYPE_DEFAULT)
1002 * always return NULL / EINVAL. There is no point in making
1003 * these two useless calls. The real ACL is retrieved through
1004 * acl_get_file (name, ACL_TYPE_EXTENDED).
1006 * Read access ACLs for files, dirs and links
1008 if (generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED) == bacl_exit_fatal)
1009 return bacl_exit_fatal;
1012 * Read access ACLs for files, dirs and links
1014 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1015 return bacl_exit_fatal;
1018 if (jcr->acl_data->u.build->content_length > 0) {
1019 return send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL);
1021 return bacl_exit_ok;
1024 static bacl_exit_code darwin_parse_acl_streams(JCR *jcr,
1027 uint32_t content_length)
1029 #if defined(HAVE_ACL_TYPE_EXTENDED)
1030 return generic_set_acl_on_os(jcr, BACL_TYPE_EXTENDED, content, content_length);
1032 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1037 * For this OS setup the build and parse function pointer to the OS specific functions.
1039 static bacl_exit_code (*os_build_acl_streams)
1040 (JCR *jcr, FF_PKT *ff_pkt) =
1041 darwin_build_acl_streams;
1042 static bacl_exit_code (*os_parse_acl_streams)
1043 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1044 darwin_parse_acl_streams;
1046 #elif defined(HAVE_FREEBSD_OS)
1048 * Define the supported ACL streams for these OSes
1050 static int os_access_acl_streams[2] = {
1051 STREAM_ACL_FREEBSD_ACCESS_ACL,
1052 STREAM_ACL_FREEBSD_NFS4_ACL
1054 static int os_default_acl_streams[1] = {
1055 STREAM_ACL_FREEBSD_DEFAULT_ACL
1058 static bacl_exit_code freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1060 int acl_enabled = 0;
1061 bacl_type acltype = BACL_TYPE_NONE;
1063 #if defined(_PC_ACL_NFS4)
1065 * See if filesystem supports NFS4 acls.
1067 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
1068 switch (acl_enabled) {
1074 return bacl_exit_ok;
1077 _("pathconf error on file \"%s\": ERR=%s\n"),
1078 jcr->last_fname, be.bstrerror());
1079 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
1080 jcr->last_fname, be.bstrerror());
1081 return bacl_exit_error;
1087 acltype = BACL_TYPE_NFS4;
1092 if (acl_enabled == 0) {
1094 * See if filesystem supports POSIX acls.
1096 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
1097 switch (acl_enabled) {
1103 return bacl_exit_ok;
1106 _("pathconf error on file \"%s\": ERR=%s\n"),
1107 jcr->last_fname, be.bstrerror());
1108 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
1109 jcr->last_fname, be.bstrerror());
1110 return bacl_exit_error;
1116 acltype = BACL_TYPE_ACCESS;
1122 * If the filesystem reports it doesn't support ACLs we clear the
1123 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1124 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1125 * when we change from one filesystem to an other.
1127 if (acl_enabled == 0) {
1128 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1129 pm_strcpy(jcr->acl_data->u.build->content, "");
1130 jcr->acl_data->u.build->content_length = 0;
1131 return bacl_exit_ok;
1135 * Based on the supported ACLs retrieve and store them.
1138 case BACL_TYPE_NFS4:
1140 * Read NFS4 ACLs for files, dirs and links
1142 if (generic_get_acl_from_os(jcr, BACL_TYPE_NFS4) == bacl_exit_fatal)
1143 return bacl_exit_fatal;
1145 if (jcr->acl_data->u.build->content_length > 0) {
1146 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_NFS4_ACL) == bacl_exit_fatal)
1147 return bacl_exit_fatal;
1150 case BACL_TYPE_ACCESS:
1152 * Read access ACLs for files, dirs and links
1154 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1155 return bacl_exit_fatal;
1157 if (jcr->acl_data->u.build->content_length > 0) {
1158 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_ACCESS_ACL) == bacl_exit_fatal)
1159 return bacl_exit_fatal;
1163 * Directories can have default ACLs too
1165 if (ff_pkt->type == FT_DIREND) {
1166 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
1167 return bacl_exit_fatal;
1168 if (jcr->acl_data->u.build->content_length > 0) {
1169 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_DEFAULT_ACL) == bacl_exit_fatal)
1170 return bacl_exit_fatal;
1178 return bacl_exit_ok;
1181 static bacl_exit_code freebsd_parse_acl_streams(JCR *jcr,
1184 uint32_t content_length)
1186 int acl_enabled = 0;
1187 const char *acl_type_name;
1190 * First make sure the filesystem supports acls.
1193 case STREAM_UNIX_ACCESS_ACL:
1194 case STREAM_ACL_FREEBSD_ACCESS_ACL:
1195 case STREAM_UNIX_DEFAULT_ACL:
1196 case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1197 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
1198 acl_type_name = "POSIX";
1200 case STREAM_ACL_FREEBSD_NFS4_ACL:
1201 #if defined(_PC_ACL_NFS4)
1202 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
1204 acl_type_name = "NFS4";
1207 acl_type_name = "unknown";
1211 switch (acl_enabled) {
1217 return bacl_exit_ok;
1220 _("pathconf error on file \"%s\": ERR=%s\n"),
1221 jcr->last_fname, be.bstrerror());
1222 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1223 content, jcr->last_fname, be.bstrerror());
1224 return bacl_exit_error;
1229 * If the filesystem reports it doesn't support ACLs we clear the
1230 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
1231 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
1232 * when we change from one filesystem to an other.
1234 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1236 _("Trying to restore acl on file \"%s\" on filesystem without %s acl support\n"),
1237 jcr->last_fname, acl_type_name);
1238 return bacl_exit_error;
1247 case STREAM_UNIX_ACCESS_ACL:
1248 case STREAM_ACL_FREEBSD_ACCESS_ACL:
1249 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1250 case STREAM_UNIX_DEFAULT_ACL:
1251 case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1252 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1253 case STREAM_ACL_FREEBSD_NFS4_ACL:
1254 return generic_set_acl_on_os(jcr, BACL_TYPE_NFS4, content, content_length);
1258 return bacl_exit_error;
1262 * For this OSes setup the build and parse function pointer to the OS specific functions.
1264 static bacl_exit_code (*os_build_acl_streams)
1265 (JCR *jcr, FF_PKT *ff_pkt) =
1266 freebsd_build_acl_streams;
1267 static bacl_exit_code (*os_parse_acl_streams)
1268 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1269 freebsd_parse_acl_streams;
1271 #elif defined(HAVE_IRIX_OS) || \
1272 defined(HAVE_LINUX_OS) || \
1273 defined(HAVE_HURD_OS)
1275 * Define the supported ACL streams for these OSes
1277 #if defined(HAVE_IRIX_OS)
1278 static int os_access_acl_streams[1] = {
1279 STREAM_ACL_IRIX_ACCESS_ACL
1281 static int os_default_acl_streams[1] = {
1282 STREAM_ACL_IRIX_DEFAULT_ACL
1284 #elif defined(HAVE_LINUX_OS)
1285 static int os_access_acl_streams[1] = {
1286 STREAM_ACL_LINUX_ACCESS_ACL
1288 static int os_default_acl_streams[1] = {
1289 STREAM_ACL_LINUX_DEFAULT_ACL
1291 #elif defined(HAVE_HURD_OS)
1292 static int os_access_acl_streams[1] = {
1293 STREAM_ACL_HURD_ACCESS_ACL
1295 static int os_default_acl_streams[1] = {
1296 STREAM_ACL_HURD_DEFAULT_ACL
1300 static bacl_exit_code generic_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1303 * Read access ACLs for files, dirs and links
1305 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1306 return bacl_exit_fatal;
1308 if (jcr->acl_data->u.build->content_length > 0) {
1309 if (send_acl_stream(jcr, os_access_acl_streams[0]) == bacl_exit_fatal)
1310 return bacl_exit_fatal;
1314 * Directories can have default ACLs too
1316 if (ff_pkt->type == FT_DIREND) {
1317 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
1318 return bacl_exit_fatal;
1319 if (jcr->acl_data->u.build->content_length > 0) {
1320 if (send_acl_stream(jcr, os_default_acl_streams[0]) == bacl_exit_fatal)
1321 return bacl_exit_fatal;
1324 return bacl_exit_ok;
1327 static bacl_exit_code generic_parse_acl_streams(JCR *jcr,
1330 uint32_t content_length)
1335 case STREAM_UNIX_ACCESS_ACL:
1336 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1337 case STREAM_UNIX_DEFAULT_ACL:
1338 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1341 * See what type of acl it is.
1343 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1344 if (os_access_acl_streams[cnt] == stream) {
1345 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1348 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1349 if (os_default_acl_streams[cnt] == stream) {
1350 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1355 return bacl_exit_error;
1359 * For this OSes setup the build and parse function pointer to the OS specific functions.
1361 static bacl_exit_code (*os_build_acl_streams)
1362 (JCR *jcr, FF_PKT *ff_pkt) =
1363 generic_build_acl_streams;
1364 static bacl_exit_code (*os_parse_acl_streams)
1365 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1366 generic_parse_acl_streams;
1368 #elif defined(HAVE_OSF1_OS)
1371 * Define the supported ACL streams for this OS
1373 static int os_access_acl_streams[1] = {
1374 STREAM_ACL_TRU64_ACCESS_ACL
1376 static int os_default_acl_streams[2] = {
1377 STREAM_ACL_TRU64_DEFAULT_ACL,
1378 STREAM_ACL_TRU64_DEFAULT_DIR_ACL
1381 static bacl_exit_code tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1384 * Read access ACLs for files, dirs and links
1386 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal) {
1387 return bacl_exit_error;
1388 if (jcr->acl_data->u.build->content_length > 0) {
1389 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL))
1390 return bacl_exit_error;
1393 * Directories can have default ACLs too
1395 if (ff_pkt->type == FT_DIREND) {
1396 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal) {
1397 return bacl_exit_error;
1398 if (jcr->acl_data->u.build->content_length > 0) {
1399 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL))
1400 return bacl_exit_error;
1403 * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
1404 * This is an inherited acl for all subdirs.
1405 * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
1406 * Section 21.5 Default ACLs
1408 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR) == bacl_exit_fatal) {
1409 return bacl_exit_error;
1410 if (jcr->acl_data->u.build->content_length > 0) {
1411 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL))
1412 return bacl_exit_error;
1415 return bacl_exit_ok;
1418 static bacl_exit_code tru64_parse_acl_streams(JCR *jcr,
1421 uint32_t content_length)
1424 case STREAM_UNIX_ACCESS_ACL:
1425 case STREAM_ACL_TRU64_ACCESS_ACL:
1426 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1427 case STREAM_UNIX_DEFAULT_ACL:
1428 case STREAM_ACL_TRU64_DEFAULT_ACL:
1429 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1430 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
1431 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR, content, content_length);
1435 * For this OS setup the build and parse function pointer to the OS specific functions.
1437 static bacl_exit_code (*os_build_acl_streams)
1438 (JCR *jcr, FF_PKT *ff_pkt) =
1439 tru64_build_acl_streams;
1440 static bacl_exit_code (*os_parse_acl_streams)
1441 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1442 tru64_parse_acl_streams;
1446 #elif defined(HAVE_HPUX_OS)
1447 #ifdef HAVE_SYS_ACL_H
1448 #include <sys/acl.h>
1450 #error "configure failed to detect availability of sys/acl.h"
1456 * Define the supported ACL streams for this OS
1458 static int os_access_acl_streams[1] = {
1459 STREAM_ACL_HPUX_ACL_ENTRY
1461 static int os_default_acl_streams[1] = {
1466 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1467 * There is no need to store those acls as we already store the stat bits too.
1469 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
1472 struct acl_entry ace
1474 for (n = 0; n < count; n++) {
1477 * See if this acl just is the stat mode in acl form.
1479 if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
1480 (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
1481 (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
1488 * OS specific functions for handling different types of acl streams.
1490 static bacl_exit_code hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1493 struct acl_entry acls[NACLENTRIES];
1496 if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
1500 #if defined(BACL_ENOTSUP)
1503 * Not supported, just pretend there is nothing to see
1505 * If the filesystem reports it doesn't support ACLs we clear the
1506 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1507 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1508 * when we change from one filesystem to an other.
1510 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1511 pm_strcpy(jcr->acl_data->u.build->content, "");
1512 jcr->acl_data->u.build->content_length = 0;
1513 return bacl_exit_ok;
1516 pm_strcpy(jcr->acl_data->u.build->content, "");
1517 jcr->acl_data->u.build->content_length = 0;
1518 return bacl_exit_ok;
1521 _("getacl error on file \"%s\": ERR=%s\n"),
1522 jcr->last_fname, be.bstrerror());
1523 Dmsg2(100, "getacl error file=%s ERR=%s\n",
1524 jcr->last_fname, be.bstrerror());
1526 pm_strcpy(jcr->acl_data->u.build->content, "");
1527 jcr->acl_data->u.build->content_length = 0;
1528 return bacl_exit_error;
1532 pm_strcpy(jcr->acl_data->u.build->content, "");
1533 jcr->acl_data->u.build->content_length = 0;
1534 return bacl_exit_ok;
1536 if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
1537 if (acl_is_trivial(n, acls, ff_pkt->statp)) {
1539 * The ACLs simply reflect the (already known) standard permissions
1540 * So we don't send an ACL stream to the SD.
1542 pm_strcpy(jcr->acl_data->u.build->content, "");
1543 jcr->acl_data->u.build->content_length = 0;
1544 return bacl_exit_ok;
1546 if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
1547 jcr->acl_data->u.build->content_length =
1548 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
1549 actuallyfree(acl_text);
1551 return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
1556 _("acltostr error on file \"%s\": ERR=%s\n"),
1557 jcr->last_fname, be.bstrerror());
1558 Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",
1559 jcr->acl_data->u.build->content, jcr->last_fname, be.bstrerror());
1560 return bacl_exit_error;
1562 return bacl_exit_error;
1565 static bacl_exit_code hpux_parse_acl_streams(JCR *jcr,
1568 uint32_t content_length)
1571 struct acl_entry acls[NACLENTRIES];
1573 n = strtoacl(content, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
1578 _("strtoacl error on file \"%s\": ERR=%s\n"),
1579 jcr->last_fname, be.bstrerror());
1580 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
1581 content, jcr->last_fname, be.bstrerror());
1582 return bacl_exit_error;
1584 if (strtoacl(content, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
1588 _("strtoacl error on file \"%s\": ERR=%s\n"),
1589 jcr->last_fname, be.bstrerror());
1590 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
1591 content, jcr->last_fname, be.bstrerror());
1593 return bacl_exit_error;
1596 * Restore the ACLs, but don't complain about links which really should
1597 * not have attributes, and the file it is linked to may not yet be restored.
1598 * This is only true for the old acl streams as in the new implementation we
1599 * don't save acls of symlinks (which cannot have acls anyhow)
1601 if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
1606 return bacl_exit_ok;
1607 #if defined(BACL_ENOTSUP)
1610 * If the filesystem reports it doesn't support ACLs we clear the
1611 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
1612 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
1613 * when we change from one filesystem to an other.
1615 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1617 _("setacl error on file \"%s\": filesystem doesn't support ACLs\n"),
1619 Dmsg2(100, "setacl error acl=%s file=%s filesystem doesn't support ACLs\n",
1620 content, jcr->last_fname);
1621 return bacl_exit_error;
1625 _("setacl error on file \"%s\": ERR=%s\n"),
1626 jcr->last_fname, be.bstrerror());
1627 Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
1628 content, jcr->last_fname, be.bstrerror());
1629 return bacl_exit_error;
1632 return bacl_exit_ok;
1636 * For this OS setup the build and parse function pointer to the OS specific functions.
1638 static bacl_exit_code (*os_build_acl_streams)
1639 (JCR *jcr, FF_PKT *ff_pkt) =
1640 hpux_build_acl_streams;
1641 static bacl_exit_code (*os_parse_acl_streams)
1642 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1643 hpux_parse_acl_streams;
1645 #elif defined(HAVE_SUN_OS)
1646 #ifdef HAVE_SYS_ACL_H
1647 #include <sys/acl.h>
1649 #error "configure failed to detect availability of sys/acl.h"
1652 #if defined(HAVE_EXTENDED_ACL)
1654 * We define some internals of the Solaris acl libs here as those
1655 * are not exposed yet. Probably because they want us to see the
1656 * acls as opague data. But as we need to support different platforms
1657 * and versions of Solaris we need to expose some data to be able
1658 * to determine the type of acl used to stuff it into the correct
1659 * data stream. I know this is far from portable, but maybe the
1660 * proper interface is exposed later on and we can get ride of
1661 * this kludge. Newer versions of Solaris include sys/acl_impl.h
1662 * which has implementation details of acls, if thats included we
1663 * don't have to define it ourself.
1665 #if !defined(_SYS_ACL_IMPL_H)
1666 typedef enum acl_type {
1673 * Two external references to functions in the libsec library function not in current include files.
1676 int acl_type(acl_t *);
1677 char *acl_strerror(int);
1681 * Define the supported ACL streams for this OS
1683 static int os_access_acl_streams[2] = {
1684 STREAM_ACL_SOLARIS_ACLENT,
1685 STREAM_ACL_SOLARIS_ACE
1687 static int os_default_acl_streams[1] = {
1692 * As the new libsec interface with acl_totext and acl_fromtext also handles
1693 * the old format from acltotext we can use the new functions even
1694 * for acls retrieved and stored in the database with older fd versions. If the
1695 * new interface is not defined (Solaris 9 and older we fall back to the old code)
1697 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1699 int acl_enabled, flags;
1702 bacl_exit_code stream_status = bacl_exit_error;
1705 * See if filesystem supports acls.
1707 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1708 switch (acl_enabled) {
1711 * If the filesystem reports it doesn't support ACLs we clear the
1712 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1713 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1714 * when we change from one filesystem to an other.
1716 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1717 pm_strcpy(jcr->acl_data->u.build->content, "");
1718 jcr->acl_data->u.build->content_length = 0;
1719 return bacl_exit_ok;
1725 return bacl_exit_ok;
1728 _("pathconf error on file \"%s\": ERR=%s\n"),
1729 jcr->last_fname, be.bstrerror());
1730 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
1731 jcr->last_fname, be.bstrerror());
1732 return bacl_exit_error;
1740 * Get ACL info: don't bother allocating space if there is only a trivial ACL.
1742 if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
1747 return bacl_exit_ok;
1750 _("acl_get error on file \"%s\": ERR=%s\n"),
1751 jcr->last_fname, acl_strerror(errno));
1752 Dmsg2(100, "acl_get error file=%s ERR=%s\n",
1753 jcr->last_fname, acl_strerror(errno));
1754 return bacl_exit_error;
1760 * The ACLs simply reflect the (already known) standard permissions
1761 * So we don't send an ACL stream to the SD.
1763 pm_strcpy(jcr->acl_data->u.build->content, "");
1764 jcr->acl_data->u.build->content_length = 0;
1765 return bacl_exit_ok;
1768 #if defined(ACL_SID_FMT)
1770 * New format flag added in newer Solaris versions.
1772 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
1774 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
1775 #endif /* ACL_SID_FMT */
1777 if ((acl_text = acl_totext(aclp, flags)) != NULL) {
1778 jcr->acl_data->u.build->content_length =
1779 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
1780 actuallyfree(acl_text);
1782 switch (acl_type(aclp)) {
1784 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1787 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE);
1795 return stream_status;
1798 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr,
1801 uint32_t content_length)
1804 int acl_enabled, error;
1807 case STREAM_UNIX_ACCESS_ACL:
1808 case STREAM_ACL_SOLARIS_ACLENT:
1809 case STREAM_ACL_SOLARIS_ACE:
1811 * First make sure the filesystem supports acls.
1813 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1814 switch (acl_enabled) {
1817 * If the filesystem reports it doesn't support ACLs we clear the
1818 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
1819 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
1820 * when we change from one filesystem to an other.
1822 jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
1824 _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
1826 return bacl_exit_error;
1832 return bacl_exit_ok;
1835 _("pathconf error on file \"%s\": ERR=%s\n"),
1836 jcr->last_fname, be.bstrerror());
1837 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1838 content, jcr->last_fname, be.bstrerror());
1839 return bacl_exit_error;
1844 * On a filesystem with ACL support make sure this particular ACL type can be restored.
1847 case STREAM_ACL_SOLARIS_ACLENT:
1849 * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
1851 if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
1853 _("Trying to restore POSIX acl on file \"%s\" on filesystem without aclent acl support\n"),
1855 return bacl_exit_error;
1858 case STREAM_ACL_SOLARIS_ACE:
1860 * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
1862 if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
1864 _("Trying to restore NFSv4 acl on file \"%s\" on filesystem without ace acl support\n"),
1866 return bacl_exit_error;
1871 * Stream id which doesn't describe the type of acl which is encoded.
1878 if ((error = acl_fromtext(content, &aclp)) != 0) {
1880 _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1881 jcr->last_fname, acl_strerror(error));
1882 Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",
1883 content, jcr->last_fname, acl_strerror(error));
1884 return bacl_exit_error;
1888 * Validate that the conversion gave us the correct acl type.
1891 case STREAM_ACL_SOLARIS_ACLENT:
1892 if (acl_type(aclp) != ACLENT_T) {
1894 _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1896 return bacl_exit_error;
1899 case STREAM_ACL_SOLARIS_ACE:
1900 if (acl_type(aclp) != ACE_T) {
1902 _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1904 return bacl_exit_error;
1909 * Stream id which doesn't describe the type of acl which is encoded.
1915 * Restore the ACLs, but don't complain about links which really should
1916 * not have attributes, and the file it is linked to may not yet be restored.
1917 * This is only true for the old acl streams as in the new implementation we
1918 * don't save acls of symlinks (which cannot have acls anyhow)
1920 if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1924 return bacl_exit_ok;
1927 _("acl_set error on file \"%s\": ERR=%s\n"),
1928 jcr->last_fname, acl_strerror(error));
1929 Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",
1930 content, jcr->last_fname, acl_strerror(error));
1932 return bacl_exit_error;
1937 return bacl_exit_ok;
1939 return bacl_exit_error;
1940 } /* end switch (stream) */
1943 #else /* HAVE_EXTENDED_ACL */
1946 * Define the supported ACL streams for this OS
1948 static int os_access_acl_streams[1] = {
1949 STREAM_ACL_SOLARIS_ACLENT
1951 static int os_default_acl_streams[1] = {
1956 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1957 * There is no need to store those acls as we already store the stat bits too.
1959 static bool acl_is_trivial(int count, aclent_t *entries)
1964 for (n = 0; n < count; n++) {
1967 if (!(ace->a_type == USER_OBJ ||
1968 ace->a_type == GROUP_OBJ ||
1969 ace->a_type == OTHER_OBJ ||
1970 ace->a_type == CLASS_OBJ))
1977 * OS specific functions for handling different types of acl streams.
1979 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1985 n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1986 if (n < MIN_ACL_ENTRIES) {
1987 return bacl_exit_error;
1990 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1991 if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1992 if (acl_is_trivial(n, acls)) {
1994 * The ACLs simply reflect the (already known) standard permissions
1995 * So we don't send an ACL stream to the SD.
1998 pm_strcpy(jcr->acl_data->u.build->content, "");
1999 jcr->acl_data->u.build->content_length = 0;
2000 return bacl_exit_ok;
2003 if ((acl_text = acltotext(acls, n)) != NULL) {
2004 jcr->acl_data->u.build->content_length =
2005 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
2006 actuallyfree(acl_text);
2008 return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
2013 _("acltotext error on file \"%s\": ERR=%s\n"),
2014 jcr->last_fname, be.bstrerror());
2015 Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",
2016 jcr->acl_data->u.build->content, jcr->last_fname, be.bstrerror());
2020 return bacl_exit_error;
2023 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr,
2026 uint32_t content_length)
2031 acls = aclfromtext(content, &n);
2036 _("aclfromtext error on file \"%s\": ERR=%s\n"),
2037 jcr->last_fname, be.bstrerror());
2038 Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",
2039 content, jcr->last_fname, be.bstrerror());
2040 return bacl_exit_error;
2044 * Restore the ACLs, but don't complain about links which really should
2045 * not have attributes, and the file it is linked to may not yet be restored.
2047 if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
2053 return bacl_exit_ok;
2056 _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
2057 jcr->last_fname, be.bstrerror());
2058 Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
2059 content, jcr->last_fname, be.bstrerror());
2061 return bacl_exit_error;
2065 return bacl_exit_ok;
2067 #endif /* HAVE_EXTENDED_ACL */
2070 * For this OS setup the build and parse function pointer to the OS specific functions.
2072 static bacl_exit_code (*os_build_acl_streams)
2073 (JCR *jcr, FF_PKT *ff_pkt) =
2074 solaris_build_acl_streams;
2075 static bacl_exit_code (*os_parse_acl_streams)
2076 (JCR *jcr, int stream, char *content, uint32_t content_length) =
2077 solaris_parse_acl_streams;
2079 #endif /* HAVE_SUN_OS */
2080 #endif /* HAVE_ACL */
2082 #if defined(HAVE_AFS_ACL)
2084 #if defined(HAVE_AFS_AFSINT_H) && defined(HAVE_AFS_VENUS_H)
2085 #include <afs/afsint.h>
2086 #include <afs/venus.h>
2088 #error "configure failed to detect availability of afs/afsint.h and/or afs/venus.h"
2092 * External references to functions in the libsys library function not in current include files.
2095 long pioctl(char *pathp, long opcode, struct ViceIoctl *blobp, int follow);
2098 static bacl_exit_code afs_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
2101 struct ViceIoctl vip;
2102 char acl_text[BUFSIZ];
2105 * AFS ACLs can only be set on a directory, so no need to try to
2106 * request them for anything other then that.
2108 if (ff_pkt->type != FT_DIREND) {
2109 return bacl_exit_ok;
2115 vip.out_size = sizeof(acl_text);
2116 memset((caddr_t)acl_text, 0, sizeof(acl_text));
2118 if ((error = pioctl(jcr->last_fname, VIOCGETAL, &vip, 0)) < 0) {
2122 _("pioctl VIOCGETAL error on file \"%s\": ERR=%s\n"),
2123 jcr->last_fname, be.bstrerror());
2124 Dmsg2(100, "pioctl VIOCGETAL error file=%s ERR=%s\n",
2125 jcr->last_fname, be.bstrerror());
2126 return bacl_exit_error;
2128 jcr->acl_data->u.build->content_length =
2129 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
2130 return send_acl_stream(jcr, STREAM_ACL_AFS_TEXT);
2133 static bacl_exit_code afs_parse_acl_stream(JCR *jcr,
2136 uint32_t content_length)
2139 struct ViceIoctl vip;
2142 vip.in_size = content_length;
2146 if ((error = pioctl(jcr->last_fname, VIOCSETAL, &vip, 0)) < 0) {
2150 _("pioctl VIOCSETAL error on file \"%s\": ERR=%s\n"),
2151 jcr->last_fname, be.bstrerror());
2152 Dmsg2(100, "pioctl VIOCSETAL error file=%s ERR=%s\n",
2153 jcr->last_fname, be.bstrerror());
2155 return bacl_exit_error;
2157 return bacl_exit_ok;
2159 #endif /* HAVE_AFS_ACL */
2162 * Entry points when compiled with support for ACLs on a supported platform.
2166 * Read and send an ACL for the last encountered file.
2168 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
2171 * See if we are changing from one device to an other.
2172 * We save the current device we are scanning and compare
2173 * it with the current st_dev in the last stat performed on
2174 * the file we are currently storing.
2176 if (jcr->acl_data->current_dev != ff_pkt->statp.st_dev) {
2178 * Reset the acl save flags.
2180 jcr->acl_data->flags = 0;
2182 #if defined(HAVE_AFS_ACL)
2184 * AFS is a non OS specific filesystem so see if this path is on an AFS filesystem
2185 * Set the BACL_FLAG_SAVE_AFS flag if it is. If not set the BACL_FLAG_SAVE_NATIVE flag.
2187 if (fstype_equals(jcr->last_fname, "afs")) {
2188 jcr->acl_data->flags |= BACL_FLAG_SAVE_AFS;
2190 jcr->acl_data->flags |= BACL_FLAG_SAVE_NATIVE;
2193 jcr->acl_data->flags |= BACL_FLAG_SAVE_NATIVE;
2197 * Save that we started scanning a new filesystem.
2199 jcr->acl_data->current_dev = ff_pkt->statp.st_dev;
2202 #if defined(HAVE_AFS_ACL)
2204 * See if the BACL_FLAG_SAVE_AFS flag is set which lets us know if we should
2207 if (jcr->acl_data->flags & BACL_FLAG_SAVE_AFS) {
2208 return afs_build_acl_streams(jcr, ff_pkt);
2211 #if defined(HAVE_ACL)
2213 * See if the BACL_FLAG_SAVE_NATIVE flag is set which lets us know if we should
2216 if (jcr->acl_data->flags & BACL_FLAG_SAVE_NATIVE) {
2218 * Call the appropriate function.
2220 if (os_build_acl_streams) {
2221 return os_build_acl_streams(jcr, ff_pkt);
2224 return bacl_exit_ok;
2227 return bacl_exit_error;
2230 bacl_exit_code parse_acl_streams(JCR *jcr,
2233 uint32_t content_length)
2240 * See if we are changing from one device to an other.
2241 * We save the current device we are restoring to and compare
2242 * it with the current st_dev in the last stat performed on
2243 * the file we are currently restoring.
2245 ret = lstat(jcr->last_fname, &st);
2252 return bacl_exit_ok;
2255 _("Unable to stat file \"%s\": ERR=%s\n"),
2256 jcr->last_fname, be.bstrerror());
2257 Dmsg2(100, "Unable to stat file \"%s\": ERR=%s\n",
2258 jcr->last_fname, be.bstrerror());
2259 return bacl_exit_error;
2266 if (jcr->acl_data->current_dev != st.st_dev) {
2268 * Reset the acl save flags.
2270 jcr->acl_data->flags = 0;
2272 #if defined(HAVE_AFS_ACL)
2274 * AFS is a non OS specific filesystem so see if this path is on an AFS filesystem
2275 * Set the BACL_FLAG_RESTORE_AFS flag if it is. If not set the BACL_FLAG_RETORE_NATIVE flag.
2277 if (fstype_equals(jcr->last_fname, "afs")) {
2278 jcr->acl_data->flags |= BACL_FLAG_RESTORE_AFS;
2280 jcr->acl_data->flags |= BACL_FLAG_RESTORE_NATIVE;
2283 jcr->acl_data->flags |= BACL_FLAG_RESTORE_NATIVE;
2287 * Save that we started restoring to a new filesystem.
2289 jcr->acl_data->current_dev = st.st_dev;
2293 #if defined(HAVE_AFS_ACL)
2294 case STREAM_ACL_AFS_TEXT:
2295 if (jcr->acl_data->flags & BACL_FLAG_RESTORE_AFS) {
2296 return afs_parse_acl_stream(jcr, stream, content, content_length);
2299 * Increment error count but don't log an error again for the same filesystem.
2301 jcr->acl_data->u.parse->nr_errors++;
2302 return bacl_exit_ok;
2305 #if defined(HAVE_ACL)
2306 case STREAM_UNIX_ACCESS_ACL:
2307 case STREAM_UNIX_DEFAULT_ACL:
2309 * Handle legacy ACL streams.
2311 if ((jcr->acl_data->flags & BACL_FLAG_RESTORE_NATIVE) && os_parse_acl_streams) {
2312 return os_parse_acl_streams(jcr, stream, content, content_length);
2315 * Increment error count but don't log an error again for the same filesystem.
2317 jcr->acl_data->u.parse->nr_errors++;
2318 return bacl_exit_ok;
2322 if ((jcr->acl_data->flags & BACL_FLAG_RESTORE_NATIVE) && os_parse_acl_streams) {
2324 * Walk the os_access_acl_streams array with the supported Access ACL streams for this OS.
2326 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
2327 if (os_access_acl_streams[cnt] == stream) {
2328 return os_parse_acl_streams(jcr, stream, content, content_length);
2332 * Walk the os_default_acl_streams array with the supported Default ACL streams for this OS.
2334 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
2335 if (os_default_acl_streams[cnt] == stream) {
2336 return os_parse_acl_streams(jcr, stream, content, content_length);
2341 * Increment error count but don't log an error again for the same filesystem.
2343 jcr->acl_data->u.parse->nr_errors++;
2344 return bacl_exit_ok;
2352 Qmsg2(jcr, M_WARNING, 0,
2353 _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
2354 jcr->last_fname, stream);
2355 return bacl_exit_error;