2 Bacula® - The Network Backup Solution
4 Copyright (C) 2004-2012 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Functions to handle ACLs for bacula.
31 * Currently we support the following OSes:
32 * - AIX (pre-5.3 and post 5.3 acls, acl_get and aclx_get interface)
34 * - FreeBSD (POSIX and NFSv4/ZFS acls)
38 * - Solaris (POSIX and NFSv4/ZFS acls)
41 * Next to OS specific acls we support AFS acls using the pioctl interface.
43 * We handle two different types of ACLs: access and default ACLS.
44 * On most systems that support default ACLs they only apply to directories.
46 * On some systems (eg. linux and FreeBSD) we must obtain the two ACLs
47 * independently, while others (eg. Solaris) provide both in one call.
49 * The Filed saves ACLs in their native format and uses different streams
50 * for all different platforms. Currently we only allow ACLs to be restored
51 * which were saved in the native format of the platform they are extracted
52 * on. Later on we might add conversion functions for mapping from one
53 * platform to an other or allow restores of systems that use the same
56 * Its also interesting to see what the exact format of acl text is on
57 * certain platforms and if they use they same encoding we might allow
58 * different platform streams to be decoded on an other similar platform.
60 * Original written by Preben 'Peppe' Guldberg, December 2004
61 * Major rewrite by Marco van Wieringen, November 2008
62 * Major overhaul by Marco van Wieringen, January 2012
68 #if !defined(HAVE_ACL) && !defined(HAVE_AFS_ACL)
70 * Entry points when compiled without support for ACLs or on an unsupported platform.
72 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
74 return bacl_exit_fatal;
77 bacl_exit_code parse_acl_streams(JCR *jcr,
80 uint32_t content_length)
82 return bacl_exit_fatal;
86 * Send an ACL stream to the SD.
88 static bacl_exit_code send_acl_stream(JCR *jcr, int stream)
90 BSOCK *sd = jcr->store_bsock;
92 #ifdef FD_NO_SEND_TEST
99 if (jcr->acl_data->u.build->content_length <= 0) {
106 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
107 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
109 return bacl_exit_fatal;
113 * Send the buffer to the storage deamon
115 Dmsg1(400, "Backing up ACL <%s>\n", jcr->acl_data->u.build->content);
117 sd->msg = jcr->acl_data->u.build->content;
118 sd->msglen = jcr->acl_data->u.build->content_length + 1;
122 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
124 return bacl_exit_fatal;
127 jcr->JobBytes += sd->msglen;
129 if (!sd->signal(BNET_EOD)) {
130 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
132 return bacl_exit_fatal;
135 Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
140 * First the native ACLs.
142 #if defined(HAVE_ACL)
143 #if defined(HAVE_AIX_OS)
145 #if defined(HAVE_EXTENDED_ACL)
147 #include <sys/access.h>
150 static bool acl_is_trivial(struct acl *acl)
152 return (acl_last(acl) != acl->acl_ext ? false : true);
155 static bool acl_nfs4_is_trivial(nfs4_acl_int_t *acl)
158 return (acl->aclEntryN > 0 ? false : true);
161 int count = acl->aclEntryN;
164 for (i = 0; i < count; i++) {
165 ace = &acl->aclEntry[i];
166 if (!((ace->flags & ACE4_ID_SPECIAL) != 0 &&
167 (ace->aceWho.special_whoid == ACE4_WHO_OWNER ||
168 ace->aceWho.special_whoid == ACE4_WHO_GROUP ||
169 ace->aceWho.special_whoid == ACE4_WHO_EVERYONE) &&
170 ace->aceType == ACE4_ACCESS_ALLOWED_ACE_TYPE &&
171 ace->aceFlags == 0 &&
172 (ace->aceMask & ~(ACE4_READ_DATA |
173 ACE4_LIST_DIRECTORY |
176 ACE4_EXECUTE)) == 0)) {
185 * Define the supported ACL streams for this OS
187 static int os_access_acl_streams[3] = {
192 static int os_default_acl_streams[1] = {
196 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
200 size_t aclsize, acltxtsize;
201 bacl_exit_code retval = bacl_exit_error;
202 POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
205 * First see how big the buffers should be.
207 memset(&type, 0, sizeof(acl_type_t));
209 if (aclx_get(jcr->last_fname, GET_ACLINFO_ONLY, &type, NULL, &aclsize, &mode) < 0) {
214 retval = bacl_exit_ok;
218 * If the filesystem reports it doesn't support ACLs we clear the
219 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
220 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
221 * when we change from one filesystem to an other.
223 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
224 retval = bacl_exit_ok;
228 _("aclx_get error on file \"%s\": ERR=%s\n"),
229 jcr->last_fname, be.bstrerror());
230 Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
231 jcr->last_fname, be.bstrerror());
237 * Make sure the buffers are big enough.
239 aclbuf = check_pool_memory_size(aclbuf, aclsize + 1);
242 * Retrieve the ACL info.
244 if (aclx_get(jcr->last_fname, 0, &type, aclbuf, &aclsize, &mode) < 0) {
249 retval = bacl_exit_ok;
253 _("aclx_get error on file \"%s\": ERR=%s\n"),
254 jcr->last_fname, be.bstrerror());
255 Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
256 jcr->last_fname, be.bstrerror());
262 * See if the acl is non trivial.
266 if (acl_is_trivial((struct acl *)aclbuf)) {
267 retval = bacl_exit_ok;
272 if (acl_nfs4_is_trivial((nfs4_acl_int_t *)aclbuf)) {
273 retval = bacl_exit_ok;
279 _("Unknown acl type encountered on file \"%s\": %ld\n"),
280 jcr->last_fname, type.u64);
281 Dmsg2(100, "Unknown acl type encountered on file \"%s\": %ld\n",
282 jcr->last_fname, type.u64);
287 * We have a non-trivial acl lets convert it into some ASCII form.
289 acltxtsize = sizeof_pool_memory(jcr->acl_data->u.build->content);
290 if (aclx_printStr(jcr->acl_data->u.build->content, &acltxtsize, aclbuf,
291 aclsize, type, jcr->last_fname, 0) < 0) {
295 * Our buffer is not big enough, acltxtsize should be updated with the value
296 * the aclx_printStr really need. So we increase the buffer and try again.
298 jcr->acl_data->u.build->content =
299 check_pool_memory_size(jcr->acl_data->u.build->content, acltxtsize + 1);
300 if (aclx_printStr(jcr->acl_data->u.build->content, &acltxtsize, aclbuf,
301 aclsize, type, jcr->last_fname, 0) < 0) {
303 _("Failed to convert acl into text on file \"%s\"\n"),
305 Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
306 jcr->last_fname, type.u64);
312 _("Failed to convert acl into text on file \"%s\"\n"),
314 Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
315 jcr->last_fname, type.u64);
320 jcr->acl_data->u.build->content_length = strlen(jcr->acl_data->u.build->content) + 1;
323 retval = send_acl_stream(jcr, STREAM_ACL_AIX_AIXC);
325 retval = send_acl_stream(jcr, STREAM_ACL_AIX_NFS4);
329 free_pool_memory(aclbuf);
335 * See if a specific type of ACLs are supported on the filesystem
336 * the file is located on.
338 static inline bool aix_query_acl_support(JCR *jcr,
340 acl_type_t *pacl_type_info)
343 acl_types_list_t acl_type_list;
344 size_t acl_type_list_len = sizeof(acl_types_list_t);
346 memset(&acl_type_list, 0, sizeof(acl_type_list));
347 if (aclx_gettypes(jcr->last_fname, &acl_type_list, &acl_type_list_len)) {
351 for (i = 0; i < acl_type_list.num_entries; i++) {
352 if (acl_type_list.entries[i].u64 == aclType) {
353 memcpy(pacl_type_info, acl_type_list.entries + i, sizeof(acl_type_t));
360 static bacl_exit_code aix_parse_acl_streams(JCR *jcr,
363 uint32_t content_length)
368 bacl_exit_code retval = bacl_exit_error;
369 POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
372 case STREAM_ACL_AIX_TEXT:
374 * Handle the old stream using the old system call for now.
376 if (acl_put(jcr->last_fname, content, 0) != 0) {
377 retval = bacl_exit_error;
380 retval = bacl_exit_ok;
382 case STREAM_ACL_AIX_AIXC:
383 if (!aix_query_acl_support(jcr, ACL_AIXC, &type)) {
385 _("Trying to restore POSIX acl on file \"%s\" on filesystem without AIXC acl support\n"),
390 case STREAM_ACL_AIX_NFS4:
391 if (!aix_query_acl_support(jcr, ACL_NFS4, &type)) {
393 _("Trying to restore NFSv4 acl on file \"%s\" on filesystem without NFS4 acl support\n"),
400 } /* end switch (stream) */
403 * Set the acl buffer to an initial size. For now we set it
404 * to the same size as the ASCII representation.
406 aclbuf = check_pool_memory_size(aclbuf, content_length);
407 aclsize = content_length;
408 if (aclx_scanStr(content, aclbuf, &aclsize, type) < 0) {
414 * The buffer isn't big enough. The man page doesn't say that aclsize
415 * is updated to the needed size as what is done with aclx_printStr.
416 * So for now we try to increase the buffer a maximum of 3 times
417 * and retry the conversion.
419 for (cnt = 0; cnt < 3; cnt++) {
420 aclsize = 2 * aclsize;
421 aclbuf = check_pool_memory_size(aclbuf, aclsize);
423 if (aclx_scanStr(content, aclbuf, &aclsize, type) == 0) {
428 * See why we failed this time, ENOSPC retry if max retries not met,
441 _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
442 jcr->last_fname, be.bstrerror(errno));
443 Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
444 jcr->last_fname, be.bstrerror());
451 _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
452 jcr->last_fname, be.bstrerror());
453 Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
454 jcr->last_fname, be.bstrerror());
458 if (aclx_put(jcr->last_fname, SET_ACL, type, aclbuf, aclsize, 0) < 0) {
463 retval = bacl_exit_ok;
467 * If the filesystem reports it doesn't support ACLs we clear the
468 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
469 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
470 * when we change from one filesystem to an other.
472 jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
473 retval = bacl_exit_ok;
477 _("aclx_put error on file \"%s\": ERR=%s\n"),
478 jcr->last_fname, be.bstrerror());
479 Dmsg2(100, "aclx_put error file=%s ERR=%s\n",
480 jcr->last_fname, be.bstrerror());
485 retval = bacl_exit_ok;
488 free_pool_memory(aclbuf);
493 #else /* HAVE_EXTENDED_ACL */
495 #include <sys/access.h>
498 * Define the supported ACL streams for this OS
500 static int os_access_acl_streams[1] = {
503 static int os_default_acl_streams[1] = {
507 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
511 if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
512 jcr->acl_data->u.build->content_length =
513 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
514 actuallyfree(acl_text);
515 return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT);
517 return bacl_exit_error;
520 static bacl_exit_code aix_parse_acl_streams(JCR *jcr,
523 uint32_t content_length)
525 if (acl_put(jcr->last_fname, content, 0) != 0) {
526 return bacl_exit_error;
530 #endif /* HAVE_EXTENDED_ACL */
533 * For this OS setup the build and parse function pointer to the OS specific functions.
535 static bacl_exit_code (*os_build_acl_streams)
536 (JCR *jcr, FF_PKT *ff_pkt) =
537 aix_build_acl_streams;
538 static bacl_exit_code (*os_parse_acl_streams)
539 (JCR *jcr, int stream, char *content, uint32_t content_length) =
540 aix_parse_acl_streams;
542 #elif defined(HAVE_DARWIN_OS) || \
543 defined(HAVE_FREEBSD_OS) || \
544 defined(HAVE_IRIX_OS) || \
545 defined(HAVE_OSF1_OS) || \
546 defined(HAVE_LINUX_OS)
548 #include <sys/types.h>
550 #ifdef HAVE_SYS_ACL_H
553 #error "configure failed to detect availability of sys/acl.h"
557 * On IRIX we can get shortened ACLs
559 #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
560 #define acl_to_text(acl,len) acl_to_short_text((acl), (len))
564 * On Linux we can get numeric and/or shorted ACLs
566 #if defined(HAVE_LINUX_OS)
567 #if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
568 #define BACL_ALTERNATE_TEXT (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
569 #elif defined(BACL_WANT_SHORT_ACLS)
570 #define BACL_ALTERNATE_TEXT TEXT_ABBREVIATE
571 #elif defined(BACL_WANT_NUMERIC_IDS)
572 #define BACL_ALTERNATE_TEXT TEXT_NUMERIC_IDS
574 #ifdef BACL_ALTERNATE_TEXT
575 #include <acl/libacl.h>
576 #define acl_to_text(acl,len) (acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
581 * On FreeBSD we can get numeric ACLs
583 #if defined(HAVE_FREEBSD_OS)
584 #if defined(BACL_WANT_NUMERIC_IDS)
585 #define BACL_ALTERNATE_TEXT ACL_TEXT_NUMERIC_IDS
587 #ifdef BACL_ALTERNATE_TEXT
588 #define acl_to_text(acl,len) (acl_to_text_np((acl), (len), BACL_ALTERNATE_TEXT))
593 * Some generic functions used by multiple OSes.
595 static acl_type_t bac_to_os_acltype(bacl_type acltype)
600 case BACL_TYPE_ACCESS:
601 ostype = ACL_TYPE_ACCESS;
603 case BACL_TYPE_DEFAULT:
604 ostype = ACL_TYPE_DEFAULT;
606 #ifdef HAVE_ACL_TYPE_NFS4
608 * FreeBSD has an additional acl type named ACL_TYPE_NFS4.
611 ostype = ACL_TYPE_NFS4;
614 #ifdef HAVE_ACL_TYPE_DEFAULT_DIR
615 case BACL_TYPE_DEFAULT_DIR:
617 * TRU64 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
619 ostype = ACL_TYPE_DEFAULT_DIR;
622 #ifdef HAVE_ACL_TYPE_EXTENDED
623 case BACL_TYPE_EXTENDED:
625 * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
627 ostype = ACL_TYPE_EXTENDED;
632 * This should never happen, as the per OS version function only tries acl
633 * types supported on a certain platform.
635 ostype = (acl_type_t)ACL_TYPE_NONE;
641 static int acl_count_entries(acl_t acl)
644 #if defined(HAVE_FREEBSD_OS) || \
645 defined(HAVE_LINUX_OS)
649 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
650 while (entry_available == 1) {
652 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
654 #elif defined(HAVE_IRIX_OS)
655 count = acl->acl_cnt;
656 #elif defined(HAVE_OSF1_OS)
657 count = acl->acl_num;
658 #elif defined(HAVE_DARWIN_OS)
662 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
663 while (entry_available == 0) {
665 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
671 #if !defined(HAVE_DARWIN_OS)
673 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
674 * There is no need to store those acls as we already store the stat bits too.
676 static bool acl_is_trivial(acl_t acl)
679 * acl is trivial if it has only the following entries:
686 #if defined(HAVE_FREEBSD_OS) || \
687 defined(HAVE_LINUX_OS)
690 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
691 while (entry_available == 1) {
693 * Get the tag type of this acl entry.
694 * If we fail to get the tagtype we call the acl non-trivial.
696 if (acl_get_tag_type(ace, &tag) < 0)
699 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
701 if (tag != ACL_USER_OBJ &&
702 tag != ACL_GROUP_OBJ &&
705 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
708 #elif defined(HAVE_IRIX_OS)
711 for (n = 0; n < acl->acl_cnt; n++) {
712 ace = &acl->acl_entry[n];
716 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
718 if (tag != ACL_USER_OBJ &&
719 tag != ACL_GROUP_OBJ &&
720 tag != ACL_OTHER_OBJ)
724 #elif defined(HAVE_OSF1_OS)
727 ace = acl->acl_first;
728 count = acl->acl_num;
731 tag = ace->entry->acl_type;
733 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
735 if (tag != ACL_USER_OBJ &&
736 tag != ACL_GROUP_OBJ &&
740 * On Tru64, perm can also contain non-standard bits such as
741 * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
743 if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
754 * Generic wrapper around acl_get_file call.
756 static bacl_exit_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
761 bacl_exit_code retval = bacl_exit_ok;
763 ostype = bac_to_os_acltype(acltype);
764 acl = acl_get_file(jcr->last_fname, ostype);
767 * From observation, IRIX's acl_get_file() seems to return a
768 * non-NULL acl with a count field of -1 when a file has no ACL
769 * defined, while IRIX's acl_to_text() returns NULL when presented
772 * For all other implmentations we check if there are more then
773 * zero entries in the acl returned.
775 if (acl_count_entries(acl) <= 0) {
780 * Make sure this is not just a trivial ACL.
782 #if !defined(HAVE_DARWIN_OS)
783 if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
785 * The ACLs simply reflect the (already known) standard permissions
786 * So we don't send an ACL stream to the SD.
791 #if defined(HAVE_FREEBSD_OS) && defined(_PC_ACL_NFS4)
792 if (acltype == BACL_TYPE_NFS4) {
794 if (acl_is_trivial_np(acl, &trivial) == 0) {
797 * The ACLs simply reflect the (already known) standard permissions
798 * So we don't send an ACL stream to the SD.
807 * Convert the internal acl representation into a text representation.
809 if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
810 jcr->acl_data->u.build->content_length =
811 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
819 _("acl_to_text error on file \"%s\": ERR=%s\n"),
820 jcr->last_fname, be.bstrerror());
821 Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",
822 jcr->last_fname, be.bstrerror());
824 retval = bacl_exit_error;
830 * Handle errors gracefully.
833 #if defined(BACL_ENOTSUP)
836 * If the filesystem reports it doesn't support ACLs we clear the
837 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
838 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
839 * when we change from one filesystem to an other.
841 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
847 /* Some real error */
849 _("acl_get_file error on file \"%s\": ERR=%s\n"),
850 jcr->last_fname, be.bstrerror());
851 Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",
852 jcr->last_fname, be.bstrerror());
854 retval = bacl_exit_error;
863 pm_strcpy(jcr->acl_data->u.build->content, "");
864 jcr->acl_data->u.build->content_length = 0;
869 * Generic wrapper around acl_set_file call.
871 static bacl_exit_code generic_set_acl_on_os(JCR *jcr,
874 uint32_t content_length)
880 * If we get empty default ACLs, clear ACLs now
882 ostype = bac_to_os_acltype(acltype);
883 if (ostype == ACL_TYPE_DEFAULT && strlen(content) == 0) {
884 if (acl_delete_def_file(jcr->last_fname) == 0) {
892 #if defined(BACL_ENOTSUP)
895 * If the filesystem reports it doesn't support ACLs we clear the
896 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
897 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
898 * when we change from one filesystem to an other.
900 jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
902 _("acl_delete_def_file error on file \"%s\": filesystem doesn't support ACLs\n"),
904 return bacl_exit_error;
908 _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
909 jcr->last_fname, be.bstrerror());
910 return bacl_exit_error;
914 acl = acl_from_text(content);
919 _("acl_from_text error on file \"%s\": ERR=%s\n"),
920 jcr->last_fname, be.bstrerror());
921 Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",
922 content, jcr->last_fname, be.bstrerror());
923 return bacl_exit_error;
926 #ifndef HAVE_FREEBSD_OS
928 * FreeBSD always fails acl_valid() - at least on valid input...
929 * As it does the right thing, given valid input, just ignore acl_valid().
931 if (acl_valid(acl) != 0) {
935 _("acl_valid error on file \"%s\": ERR=%s\n"),
936 jcr->last_fname, be.bstrerror());
937 Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",
938 content, jcr->last_fname, be.bstrerror());
940 return bacl_exit_error;
945 * Restore the ACLs, but don't complain about links which really should
946 * not have attributes, and the file it is linked to may not yet be restored.
947 * This is only true for the old acl streams as in the new implementation we
948 * don't save acls of symlinks (which cannot have acls anyhow)
950 if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
957 #if defined(BACL_ENOTSUP)
960 * If the filesystem reports it doesn't support ACLs we clear the
961 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
962 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
963 * when we change from one filesystem to an other.
965 jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
967 _("acl_set_file error on file \"%s\": filesystem doesn't support ACLs\n"),
969 Dmsg2(100, "acl_set_file error acl=%s file=%s filesystem doesn't support ACLs\n",
970 content, jcr->last_fname);
972 return bacl_exit_error;
976 _("acl_set_file error on file \"%s\": ERR=%s\n"),
977 jcr->last_fname, be.bstrerror());
978 Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
979 content, jcr->last_fname, be.bstrerror());
981 return bacl_exit_error;
989 * OS specific functions for handling different types of acl streams.
991 #if defined(HAVE_DARWIN_OS)
993 * Define the supported ACL streams for this OS
995 static int os_access_acl_streams[1] = {
996 STREAM_ACL_DARWIN_ACCESS_ACL
998 static int os_default_acl_streams[1] = {
1002 static bacl_exit_code darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1004 #if defined(HAVE_ACL_TYPE_EXTENDED)
1006 * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
1007 * and acl_get_file (name, ACL_TYPE_DEFAULT)
1008 * always return NULL / EINVAL. There is no point in making
1009 * these two useless calls. The real ACL is retrieved through
1010 * acl_get_file (name, ACL_TYPE_EXTENDED).
1012 * Read access ACLs for files, dirs and links
1014 if (generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED) == bacl_exit_fatal)
1015 return bacl_exit_fatal;
1018 * Read access ACLs for files, dirs and links
1020 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1021 return bacl_exit_fatal;
1024 if (jcr->acl_data->u.build->content_length > 0) {
1025 return send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL);
1027 return bacl_exit_ok;
1030 static bacl_exit_code darwin_parse_acl_streams(JCR *jcr,
1033 uint32_t content_length)
1035 #if defined(HAVE_ACL_TYPE_EXTENDED)
1036 return generic_set_acl_on_os(jcr, BACL_TYPE_EXTENDED, content, content_length);
1038 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1043 * For this OS setup the build and parse function pointer to the OS specific functions.
1045 static bacl_exit_code (*os_build_acl_streams)
1046 (JCR *jcr, FF_PKT *ff_pkt) =
1047 darwin_build_acl_streams;
1048 static bacl_exit_code (*os_parse_acl_streams)
1049 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1050 darwin_parse_acl_streams;
1052 #elif defined(HAVE_FREEBSD_OS)
1054 * Define the supported ACL streams for these OSes
1056 static int os_access_acl_streams[2] = {
1057 STREAM_ACL_FREEBSD_ACCESS_ACL,
1058 STREAM_ACL_FREEBSD_NFS4_ACL
1060 static int os_default_acl_streams[1] = {
1061 STREAM_ACL_FREEBSD_DEFAULT_ACL
1064 static bacl_exit_code freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1066 int acl_enabled = 0;
1067 bacl_type acltype = BACL_TYPE_NONE;
1069 #if defined(_PC_ACL_NFS4)
1071 * See if filesystem supports NFS4 acls.
1073 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
1074 switch (acl_enabled) {
1080 return bacl_exit_ok;
1083 _("pathconf error on file \"%s\": ERR=%s\n"),
1084 jcr->last_fname, be.bstrerror());
1085 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
1086 jcr->last_fname, be.bstrerror());
1087 return bacl_exit_error;
1093 acltype = BACL_TYPE_NFS4;
1098 if (acl_enabled == 0) {
1100 * See if filesystem supports POSIX acls.
1102 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
1103 switch (acl_enabled) {
1109 return bacl_exit_ok;
1112 _("pathconf error on file \"%s\": ERR=%s\n"),
1113 jcr->last_fname, be.bstrerror());
1114 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
1115 jcr->last_fname, be.bstrerror());
1116 return bacl_exit_error;
1122 acltype = BACL_TYPE_ACCESS;
1128 * If the filesystem reports it doesn't support ACLs we clear the
1129 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1130 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1131 * when we change from one filesystem to an other.
1133 if (acl_enabled == 0) {
1134 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1135 pm_strcpy(jcr->acl_data->u.build->content, "");
1136 jcr->acl_data->u.build->content_length = 0;
1137 return bacl_exit_ok;
1141 * Based on the supported ACLs retrieve and store them.
1144 case BACL_TYPE_NFS4:
1146 * Read NFS4 ACLs for files, dirs and links
1148 if (generic_get_acl_from_os(jcr, BACL_TYPE_NFS4) == bacl_exit_fatal)
1149 return bacl_exit_fatal;
1151 if (jcr->acl_data->u.build->content_length > 0) {
1152 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_NFS4_ACL) == bacl_exit_fatal)
1153 return bacl_exit_fatal;
1156 case BACL_TYPE_ACCESS:
1158 * Read access ACLs for files, dirs and links
1160 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1161 return bacl_exit_fatal;
1163 if (jcr->acl_data->u.build->content_length > 0) {
1164 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_ACCESS_ACL) == bacl_exit_fatal)
1165 return bacl_exit_fatal;
1169 * Directories can have default ACLs too
1171 if (ff_pkt->type == FT_DIREND) {
1172 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
1173 return bacl_exit_fatal;
1174 if (jcr->acl_data->u.build->content_length > 0) {
1175 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_DEFAULT_ACL) == bacl_exit_fatal)
1176 return bacl_exit_fatal;
1184 return bacl_exit_ok;
1187 static bacl_exit_code freebsd_parse_acl_streams(JCR *jcr,
1190 uint32_t content_length)
1192 int acl_enabled = 0;
1193 const char *acl_type_name;
1196 * First make sure the filesystem supports acls.
1199 case STREAM_UNIX_ACCESS_ACL:
1200 case STREAM_ACL_FREEBSD_ACCESS_ACL:
1201 case STREAM_UNIX_DEFAULT_ACL:
1202 case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1203 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
1204 acl_type_name = "POSIX";
1206 case STREAM_ACL_FREEBSD_NFS4_ACL:
1207 #if defined(_PC_ACL_NFS4)
1208 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
1210 acl_type_name = "NFS4";
1213 acl_type_name = "unknown";
1217 switch (acl_enabled) {
1223 return bacl_exit_ok;
1226 _("pathconf error on file \"%s\": ERR=%s\n"),
1227 jcr->last_fname, be.bstrerror());
1228 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1229 content, jcr->last_fname, be.bstrerror());
1230 return bacl_exit_error;
1235 * If the filesystem reports it doesn't support ACLs we clear the
1236 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
1237 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
1238 * when we change from one filesystem to an other.
1240 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1242 _("Trying to restore acl on file \"%s\" on filesystem without %s acl support\n"),
1243 jcr->last_fname, acl_type_name);
1244 return bacl_exit_error;
1253 case STREAM_UNIX_ACCESS_ACL:
1254 case STREAM_ACL_FREEBSD_ACCESS_ACL:
1255 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1256 case STREAM_UNIX_DEFAULT_ACL:
1257 case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1258 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1259 case STREAM_ACL_FREEBSD_NFS4_ACL:
1260 return generic_set_acl_on_os(jcr, BACL_TYPE_NFS4, content, content_length);
1264 return bacl_exit_error;
1268 * For this OSes setup the build and parse function pointer to the OS specific functions.
1270 static bacl_exit_code (*os_build_acl_streams)
1271 (JCR *jcr, FF_PKT *ff_pkt) =
1272 freebsd_build_acl_streams;
1273 static bacl_exit_code (*os_parse_acl_streams)
1274 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1275 freebsd_parse_acl_streams;
1277 #elif defined(HAVE_IRIX_OS) || \
1278 defined(HAVE_LINUX_OS)
1280 * Define the supported ACL streams for these OSes
1282 #if defined(HAVE_IRIX_OS)
1283 static int os_access_acl_streams[1] = {
1284 STREAM_ACL_IRIX_ACCESS_ACL
1286 static int os_default_acl_streams[1] = {
1287 STREAM_ACL_IRIX_DEFAULT_ACL
1289 #elif defined(HAVE_LINUX_OS)
1290 static int os_access_acl_streams[1] = {
1291 STREAM_ACL_LINUX_ACCESS_ACL
1293 static int os_default_acl_streams[1] = {
1294 STREAM_ACL_LINUX_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;