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)
39 * - Solaris (POSIX and NFSv4/ZFS acls)
42 * Next to OS specific acls we support AFS acls using the pioctl interface.
44 * We handle two different types of ACLs: access and default ACLS.
45 * On most systems that support default ACLs they only apply to directories.
47 * On some systems (eg. linux and FreeBSD) we must obtain the two ACLs
48 * independently, while others (eg. Solaris) provide both in one call.
50 * The Filed saves ACLs in their native format and uses different streams
51 * for all different platforms. Currently we only allow ACLs to be restored
52 * which were saved in the native format of the platform they are extracted
53 * on. Later on we might add conversion functions for mapping from one
54 * platform to an other or allow restores of systems that use the same
57 * Its also interesting to see what the exact format of acl text is on
58 * certain platforms and if they use they same encoding we might allow
59 * different platform streams to be decoded on an other similar platform.
61 * Original written by Preben 'Peppe' Guldberg, December 2004
62 * Major rewrite by Marco van Wieringen, November 2008
63 * Major overhaul by Marco van Wieringen, January 2012
69 #if !defined(HAVE_ACL) && !defined(HAVE_AFS_ACL)
71 * Entry points when compiled without support for ACLs or on an unsupported platform.
73 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
75 return bacl_exit_fatal;
78 bacl_exit_code parse_acl_streams(JCR *jcr,
81 uint32_t content_length)
83 return bacl_exit_fatal;
87 * Send an ACL stream to the SD.
89 static bacl_exit_code send_acl_stream(JCR *jcr, int stream)
91 BSOCK *sd = jcr->store_bsock;
93 #ifdef FD_NO_SEND_TEST
100 if (jcr->acl_data->u.build->content_length <= 0) {
107 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
108 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
110 return bacl_exit_fatal;
114 * Send the buffer to the storage deamon
116 Dmsg1(400, "Backing up ACL <%s>\n", jcr->acl_data->u.build->content);
118 sd->msg = jcr->acl_data->u.build->content;
119 sd->msglen = jcr->acl_data->u.build->content_length + 1;
123 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
125 return bacl_exit_fatal;
128 jcr->JobBytes += sd->msglen;
130 if (!sd->signal(BNET_EOD)) {
131 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
133 return bacl_exit_fatal;
136 Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
141 * First the native ACLs.
143 #if defined(HAVE_ACL)
144 #if defined(HAVE_AIX_OS)
146 #if defined(HAVE_EXTENDED_ACL)
148 #include <sys/access.h>
151 static bool acl_is_trivial(struct acl *acl)
153 return (acl_last(acl) != acl->acl_ext ? false : true);
156 static bool acl_nfs4_is_trivial(nfs4_acl_int_t *acl)
159 return (acl->aclEntryN > 0 ? false : true);
162 int count = acl->aclEntryN;
165 for (i = 0; i < count; i++) {
166 ace = &acl->aclEntry[i];
167 if (!((ace->flags & ACE4_ID_SPECIAL) != 0 &&
168 (ace->aceWho.special_whoid == ACE4_WHO_OWNER ||
169 ace->aceWho.special_whoid == ACE4_WHO_GROUP ||
170 ace->aceWho.special_whoid == ACE4_WHO_EVERYONE) &&
171 ace->aceType == ACE4_ACCESS_ALLOWED_ACE_TYPE &&
172 ace->aceFlags == 0 &&
173 (ace->aceMask & ~(ACE4_READ_DATA |
174 ACE4_LIST_DIRECTORY |
177 ACE4_EXECUTE)) == 0)) {
186 * Define the supported ACL streams for this OS
188 static int os_access_acl_streams[3] = {
193 static int os_default_acl_streams[1] = {
197 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
201 size_t aclsize, acltxtsize;
202 bacl_exit_code retval = bacl_exit_error;
203 POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
206 * First see how big the buffers should be.
208 memset(&type, 0, sizeof(acl_type_t));
210 if (aclx_get(jcr->last_fname, GET_ACLINFO_ONLY, &type, NULL, &aclsize, &mode) < 0) {
215 retval = bacl_exit_ok;
219 * If the filesystem reports it doesn't support ACLs we clear the
220 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
221 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
222 * when we change from one filesystem to an other.
224 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
225 retval = bacl_exit_ok;
229 _("aclx_get error on file \"%s\": ERR=%s\n"),
230 jcr->last_fname, be.bstrerror());
231 Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
232 jcr->last_fname, be.bstrerror());
238 * Make sure the buffers are big enough.
240 aclbuf = check_pool_memory_size(aclbuf, aclsize + 1);
243 * Retrieve the ACL info.
245 if (aclx_get(jcr->last_fname, 0, &type, aclbuf, &aclsize, &mode) < 0) {
250 retval = bacl_exit_ok;
254 _("aclx_get error on file \"%s\": ERR=%s\n"),
255 jcr->last_fname, be.bstrerror());
256 Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
257 jcr->last_fname, be.bstrerror());
263 * See if the acl is non trivial.
267 if (acl_is_trivial((struct acl *)aclbuf)) {
268 retval = bacl_exit_ok;
273 if (acl_nfs4_is_trivial((nfs4_acl_int_t *)aclbuf)) {
274 retval = bacl_exit_ok;
280 _("Unknown acl type encountered on file \"%s\": %ld\n"),
281 jcr->last_fname, type.u64);
282 Dmsg2(100, "Unknown acl type encountered on file \"%s\": %ld\n",
283 jcr->last_fname, type.u64);
288 * We have a non-trivial acl lets convert it into some ASCII form.
290 acltxtsize = sizeof_pool_memory(jcr->acl_data->u.build->content);
291 if (aclx_printStr(jcr->acl_data->u.build->content, &acltxtsize, aclbuf,
292 aclsize, type, jcr->last_fname, 0) < 0) {
296 * Our buffer is not big enough, acltxtsize should be updated with the value
297 * the aclx_printStr really need. So we increase the buffer and try again.
299 jcr->acl_data->u.build->content =
300 check_pool_memory_size(jcr->acl_data->u.build->content, acltxtsize + 1);
301 if (aclx_printStr(jcr->acl_data->u.build->content, &acltxtsize, aclbuf,
302 aclsize, type, jcr->last_fname, 0) < 0) {
304 _("Failed to convert acl into text on file \"%s\"\n"),
306 Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
307 jcr->last_fname, type.u64);
313 _("Failed to convert acl into text on file \"%s\"\n"),
315 Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
316 jcr->last_fname, type.u64);
321 jcr->acl_data->u.build->content_length = strlen(jcr->acl_data->u.build->content) + 1;
324 retval = send_acl_stream(jcr, STREAM_ACL_AIX_AIXC);
326 retval = send_acl_stream(jcr, STREAM_ACL_AIX_NFS4);
330 free_pool_memory(aclbuf);
336 * See if a specific type of ACLs are supported on the filesystem
337 * the file is located on.
339 static inline bool aix_query_acl_support(JCR *jcr,
341 acl_type_t *pacl_type_info)
344 acl_types_list_t acl_type_list;
345 size_t acl_type_list_len = sizeof(acl_types_list_t);
347 memset(&acl_type_list, 0, sizeof(acl_type_list));
348 if (aclx_gettypes(jcr->last_fname, &acl_type_list, &acl_type_list_len)) {
352 for (i = 0; i < acl_type_list.num_entries; i++) {
353 if (acl_type_list.entries[i].u64 == aclType) {
354 memcpy(pacl_type_info, acl_type_list.entries + i, sizeof(acl_type_t));
361 static bacl_exit_code aix_parse_acl_streams(JCR *jcr,
364 uint32_t content_length)
369 bacl_exit_code retval = bacl_exit_error;
370 POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
373 case STREAM_ACL_AIX_TEXT:
375 * Handle the old stream using the old system call for now.
377 if (acl_put(jcr->last_fname, content, 0) != 0) {
378 retval = bacl_exit_error;
381 retval = bacl_exit_ok;
383 case STREAM_ACL_AIX_AIXC:
384 if (!aix_query_acl_support(jcr, ACL_AIXC, &type)) {
386 _("Trying to restore POSIX acl on file \"%s\" on filesystem without AIXC acl support\n"),
391 case STREAM_ACL_AIX_NFS4:
392 if (!aix_query_acl_support(jcr, ACL_NFS4, &type)) {
394 _("Trying to restore NFSv4 acl on file \"%s\" on filesystem without NFS4 acl support\n"),
401 } /* end switch (stream) */
404 * Set the acl buffer to an initial size. For now we set it
405 * to the same size as the ASCII representation.
407 aclbuf = check_pool_memory_size(aclbuf, content_length);
408 aclsize = content_length;
409 if (aclx_scanStr(content, aclbuf, &aclsize, type) < 0) {
415 * The buffer isn't big enough. The man page doesn't say that aclsize
416 * is updated to the needed size as what is done with aclx_printStr.
417 * So for now we try to increase the buffer a maximum of 3 times
418 * and retry the conversion.
420 for (cnt = 0; cnt < 3; cnt++) {
421 aclsize = 2 * aclsize;
422 aclbuf = check_pool_memory_size(aclbuf, aclsize);
424 if (aclx_scanStr(content, aclbuf, &aclsize, type) == 0) {
429 * See why we failed this time, ENOSPC retry if max retries not met,
442 _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
443 jcr->last_fname, be.bstrerror(errno));
444 Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
445 jcr->last_fname, be.bstrerror());
452 _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
453 jcr->last_fname, be.bstrerror());
454 Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
455 jcr->last_fname, be.bstrerror());
459 if (aclx_put(jcr->last_fname, SET_ACL, type, aclbuf, aclsize, 0) < 0) {
464 retval = bacl_exit_ok;
468 * If the filesystem reports it doesn't support ACLs we clear the
469 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
470 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
471 * when we change from one filesystem to an other.
473 jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
474 retval = bacl_exit_ok;
478 _("aclx_put error on file \"%s\": ERR=%s\n"),
479 jcr->last_fname, be.bstrerror());
480 Dmsg2(100, "aclx_put error file=%s ERR=%s\n",
481 jcr->last_fname, be.bstrerror());
486 retval = bacl_exit_ok;
489 free_pool_memory(aclbuf);
494 #else /* HAVE_EXTENDED_ACL */
496 #include <sys/access.h>
499 * Define the supported ACL streams for this OS
501 static int os_access_acl_streams[1] = {
504 static int os_default_acl_streams[1] = {
508 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
512 if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
513 jcr->acl_data->u.build->content_length =
514 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
515 actuallyfree(acl_text);
516 return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT);
518 return bacl_exit_error;
521 static bacl_exit_code aix_parse_acl_streams(JCR *jcr,
524 uint32_t content_length)
526 if (acl_put(jcr->last_fname, content, 0) != 0) {
527 return bacl_exit_error;
531 #endif /* HAVE_EXTENDED_ACL */
534 * For this OS setup the build and parse function pointer to the OS specific functions.
536 static bacl_exit_code (*os_build_acl_streams)
537 (JCR *jcr, FF_PKT *ff_pkt) =
538 aix_build_acl_streams;
539 static bacl_exit_code (*os_parse_acl_streams)
540 (JCR *jcr, int stream, char *content, uint32_t content_length) =
541 aix_parse_acl_streams;
543 #elif defined(HAVE_DARWIN_OS) || \
544 defined(HAVE_FREEBSD_OS) || \
545 defined(HAVE_IRIX_OS) || \
546 defined(HAVE_OSF1_OS) || \
547 defined(HAVE_LINUX_OS) || \
548 defined(HAVE_HURD_OS)
550 #include <sys/types.h>
552 #ifdef HAVE_SYS_ACL_H
555 #error "configure failed to detect availability of sys/acl.h"
559 * On IRIX we can get shortened ACLs
561 #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
562 #define acl_to_text(acl,len) acl_to_short_text((acl), (len))
566 * On Linux we can get numeric and/or shorted ACLs
568 #if defined(HAVE_LINUX_OS)
569 #if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
570 #define BACL_ALTERNATE_TEXT (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
571 #elif defined(BACL_WANT_SHORT_ACLS)
572 #define BACL_ALTERNATE_TEXT TEXT_ABBREVIATE
573 #elif defined(BACL_WANT_NUMERIC_IDS)
574 #define BACL_ALTERNATE_TEXT TEXT_NUMERIC_IDS
576 #ifdef BACL_ALTERNATE_TEXT
577 #include <acl/libacl.h>
578 #define acl_to_text(acl,len) (acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
583 * On FreeBSD we can get numeric ACLs
585 #if defined(HAVE_FREEBSD_OS)
586 #if defined(BACL_WANT_NUMERIC_IDS)
587 #define BACL_ALTERNATE_TEXT ACL_TEXT_NUMERIC_IDS
589 #ifdef BACL_ALTERNATE_TEXT
590 #define acl_to_text(acl,len) (acl_to_text_np((acl), (len), BACL_ALTERNATE_TEXT))
595 * Some generic functions used by multiple OSes.
597 static acl_type_t bac_to_os_acltype(bacl_type acltype)
602 case BACL_TYPE_ACCESS:
603 ostype = ACL_TYPE_ACCESS;
605 case BACL_TYPE_DEFAULT:
606 ostype = ACL_TYPE_DEFAULT;
608 #ifdef HAVE_ACL_TYPE_NFS4
610 * FreeBSD has an additional acl type named ACL_TYPE_NFS4.
613 ostype = ACL_TYPE_NFS4;
616 #ifdef HAVE_ACL_TYPE_DEFAULT_DIR
617 case BACL_TYPE_DEFAULT_DIR:
619 * TRU64 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
621 ostype = ACL_TYPE_DEFAULT_DIR;
624 #ifdef HAVE_ACL_TYPE_EXTENDED
625 case BACL_TYPE_EXTENDED:
627 * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
629 ostype = ACL_TYPE_EXTENDED;
634 * This should never happen, as the per OS version function only tries acl
635 * types supported on a certain platform.
637 ostype = (acl_type_t)ACL_TYPE_NONE;
643 static int acl_count_entries(acl_t acl)
646 #if defined(HAVE_FREEBSD_OS) || \
647 defined(HAVE_LINUX_OS) || \
648 defined(HAVE_HURD_OS)
652 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
653 while (entry_available == 1) {
655 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
657 #elif defined(HAVE_IRIX_OS)
658 count = acl->acl_cnt;
659 #elif defined(HAVE_OSF1_OS)
660 count = acl->acl_num;
661 #elif defined(HAVE_DARWIN_OS)
665 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
666 while (entry_available == 0) {
668 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
674 #if !defined(HAVE_DARWIN_OS)
676 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
677 * There is no need to store those acls as we already store the stat bits too.
679 static bool acl_is_trivial(acl_t acl)
682 * acl is trivial if it has only the following entries:
689 #if defined(HAVE_FREEBSD_OS) || \
690 defined(HAVE_LINUX_OS) || \
691 defined(HAVE_HURD_OS)
694 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
695 while (entry_available == 1) {
697 * Get the tag type of this acl entry.
698 * If we fail to get the tagtype we call the acl non-trivial.
700 if (acl_get_tag_type(ace, &tag) < 0)
703 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
705 if (tag != ACL_USER_OBJ &&
706 tag != ACL_GROUP_OBJ &&
709 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
712 #elif defined(HAVE_IRIX_OS)
715 for (n = 0; n < acl->acl_cnt; n++) {
716 ace = &acl->acl_entry[n];
720 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
722 if (tag != ACL_USER_OBJ &&
723 tag != ACL_GROUP_OBJ &&
724 tag != ACL_OTHER_OBJ)
728 #elif defined(HAVE_OSF1_OS)
731 ace = acl->acl_first;
732 count = acl->acl_num;
735 tag = ace->entry->acl_type;
737 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
739 if (tag != ACL_USER_OBJ &&
740 tag != ACL_GROUP_OBJ &&
744 * On Tru64, perm can also contain non-standard bits such as
745 * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
747 if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
758 * Generic wrapper around acl_get_file call.
760 static bacl_exit_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
765 bacl_exit_code retval = bacl_exit_ok;
767 ostype = bac_to_os_acltype(acltype);
768 acl = acl_get_file(jcr->last_fname, ostype);
771 * From observation, IRIX's acl_get_file() seems to return a
772 * non-NULL acl with a count field of -1 when a file has no ACL
773 * defined, while IRIX's acl_to_text() returns NULL when presented
776 * For all other implmentations we check if there are more then
777 * zero entries in the acl returned.
779 if (acl_count_entries(acl) <= 0) {
784 * Make sure this is not just a trivial ACL.
786 #if !defined(HAVE_DARWIN_OS)
787 if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
789 * The ACLs simply reflect the (already known) standard permissions
790 * So we don't send an ACL stream to the SD.
795 #if defined(HAVE_FREEBSD_OS) && defined(_PC_ACL_NFS4)
796 if (acltype == BACL_TYPE_NFS4) {
798 if (acl_is_trivial_np(acl, &trivial) == 0) {
801 * The ACLs simply reflect the (already known) standard permissions
802 * So we don't send an ACL stream to the SD.
811 * Convert the internal acl representation into a text representation.
813 if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
814 jcr->acl_data->u.build->content_length =
815 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
823 _("acl_to_text error on file \"%s\": ERR=%s\n"),
824 jcr->last_fname, be.bstrerror());
825 Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",
826 jcr->last_fname, be.bstrerror());
828 retval = bacl_exit_error;
834 * Handle errors gracefully.
837 #if defined(BACL_ENOTSUP)
840 * If the filesystem reports it doesn't support ACLs we clear the
841 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
842 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
843 * when we change from one filesystem to an other.
845 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
851 /* Some real error */
853 _("acl_get_file error on file \"%s\": ERR=%s\n"),
854 jcr->last_fname, be.bstrerror());
855 Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",
856 jcr->last_fname, be.bstrerror());
858 retval = bacl_exit_error;
867 pm_strcpy(jcr->acl_data->u.build->content, "");
868 jcr->acl_data->u.build->content_length = 0;
873 * Generic wrapper around acl_set_file call.
875 static bacl_exit_code generic_set_acl_on_os(JCR *jcr,
878 uint32_t content_length)
884 * If we get empty default ACLs, clear ACLs now
886 ostype = bac_to_os_acltype(acltype);
887 if (ostype == ACL_TYPE_DEFAULT && strlen(content) == 0) {
888 if (acl_delete_def_file(jcr->last_fname) == 0) {
896 #if defined(BACL_ENOTSUP)
899 * If the filesystem reports it doesn't support ACLs we clear the
900 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
901 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
902 * when we change from one filesystem to an other.
904 jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
906 _("acl_delete_def_file error on file \"%s\": filesystem doesn't support ACLs\n"),
908 return bacl_exit_error;
912 _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
913 jcr->last_fname, be.bstrerror());
914 return bacl_exit_error;
918 acl = acl_from_text(content);
923 _("acl_from_text error on file \"%s\": ERR=%s\n"),
924 jcr->last_fname, be.bstrerror());
925 Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",
926 content, jcr->last_fname, be.bstrerror());
927 return bacl_exit_error;
930 #ifndef HAVE_FREEBSD_OS
932 * FreeBSD always fails acl_valid() - at least on valid input...
933 * As it does the right thing, given valid input, just ignore acl_valid().
935 if (acl_valid(acl) != 0) {
939 _("acl_valid error on file \"%s\": ERR=%s\n"),
940 jcr->last_fname, be.bstrerror());
941 Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",
942 content, jcr->last_fname, be.bstrerror());
944 return bacl_exit_error;
949 * Restore the ACLs, but don't complain about links which really should
950 * not have attributes, and the file it is linked to may not yet be restored.
951 * This is only true for the old acl streams as in the new implementation we
952 * don't save acls of symlinks (which cannot have acls anyhow)
954 if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
961 #if defined(BACL_ENOTSUP)
964 * If the filesystem reports it doesn't support ACLs we clear the
965 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
966 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
967 * when we change from one filesystem to an other.
969 jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
971 _("acl_set_file error on file \"%s\": filesystem doesn't support ACLs\n"),
973 Dmsg2(100, "acl_set_file error acl=%s file=%s filesystem doesn't support ACLs\n",
974 content, jcr->last_fname);
976 return bacl_exit_error;
980 _("acl_set_file error on file \"%s\": ERR=%s\n"),
981 jcr->last_fname, be.bstrerror());
982 Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
983 content, jcr->last_fname, be.bstrerror());
985 return bacl_exit_error;
993 * OS specific functions for handling different types of acl streams.
995 #if defined(HAVE_DARWIN_OS)
997 * Define the supported ACL streams for this OS
999 static int os_access_acl_streams[1] = {
1000 STREAM_ACL_DARWIN_ACCESS_ACL
1002 static int os_default_acl_streams[1] = {
1006 static bacl_exit_code darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1008 #if defined(HAVE_ACL_TYPE_EXTENDED)
1010 * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
1011 * and acl_get_file (name, ACL_TYPE_DEFAULT)
1012 * always return NULL / EINVAL. There is no point in making
1013 * these two useless calls. The real ACL is retrieved through
1014 * acl_get_file (name, ACL_TYPE_EXTENDED).
1016 * Read access ACLs for files, dirs and links
1018 if (generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED) == bacl_exit_fatal)
1019 return bacl_exit_fatal;
1022 * Read access ACLs for files, dirs and links
1024 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1025 return bacl_exit_fatal;
1028 if (jcr->acl_data->u.build->content_length > 0) {
1029 return send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL);
1031 return bacl_exit_ok;
1034 static bacl_exit_code darwin_parse_acl_streams(JCR *jcr,
1037 uint32_t content_length)
1039 #if defined(HAVE_ACL_TYPE_EXTENDED)
1040 return generic_set_acl_on_os(jcr, BACL_TYPE_EXTENDED, content, content_length);
1042 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1047 * For this OS setup the build and parse function pointer to the OS specific functions.
1049 static bacl_exit_code (*os_build_acl_streams)
1050 (JCR *jcr, FF_PKT *ff_pkt) =
1051 darwin_build_acl_streams;
1052 static bacl_exit_code (*os_parse_acl_streams)
1053 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1054 darwin_parse_acl_streams;
1056 #elif defined(HAVE_FREEBSD_OS)
1058 * Define the supported ACL streams for these OSes
1060 static int os_access_acl_streams[2] = {
1061 STREAM_ACL_FREEBSD_ACCESS_ACL,
1062 STREAM_ACL_FREEBSD_NFS4_ACL
1064 static int os_default_acl_streams[1] = {
1065 STREAM_ACL_FREEBSD_DEFAULT_ACL
1068 static bacl_exit_code freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1070 int acl_enabled = 0;
1071 bacl_type acltype = BACL_TYPE_NONE;
1073 #if defined(_PC_ACL_NFS4)
1075 * See if filesystem supports NFS4 acls.
1077 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
1078 switch (acl_enabled) {
1084 return bacl_exit_ok;
1087 _("pathconf error on file \"%s\": ERR=%s\n"),
1088 jcr->last_fname, be.bstrerror());
1089 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
1090 jcr->last_fname, be.bstrerror());
1091 return bacl_exit_error;
1097 acltype = BACL_TYPE_NFS4;
1102 if (acl_enabled == 0) {
1104 * See if filesystem supports POSIX acls.
1106 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
1107 switch (acl_enabled) {
1113 return bacl_exit_ok;
1116 _("pathconf error on file \"%s\": ERR=%s\n"),
1117 jcr->last_fname, be.bstrerror());
1118 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
1119 jcr->last_fname, be.bstrerror());
1120 return bacl_exit_error;
1126 acltype = BACL_TYPE_ACCESS;
1132 * If the filesystem reports it doesn't support ACLs we clear the
1133 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1134 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1135 * when we change from one filesystem to an other.
1137 if (acl_enabled == 0) {
1138 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1139 pm_strcpy(jcr->acl_data->u.build->content, "");
1140 jcr->acl_data->u.build->content_length = 0;
1141 return bacl_exit_ok;
1145 * Based on the supported ACLs retrieve and store them.
1148 case BACL_TYPE_NFS4:
1150 * Read NFS4 ACLs for files, dirs and links
1152 if (generic_get_acl_from_os(jcr, BACL_TYPE_NFS4) == bacl_exit_fatal)
1153 return bacl_exit_fatal;
1155 if (jcr->acl_data->u.build->content_length > 0) {
1156 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_NFS4_ACL) == bacl_exit_fatal)
1157 return bacl_exit_fatal;
1160 case BACL_TYPE_ACCESS:
1162 * Read access ACLs for files, dirs and links
1164 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1165 return bacl_exit_fatal;
1167 if (jcr->acl_data->u.build->content_length > 0) {
1168 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_ACCESS_ACL) == bacl_exit_fatal)
1169 return bacl_exit_fatal;
1173 * Directories can have default ACLs too
1175 if (ff_pkt->type == FT_DIREND) {
1176 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
1177 return bacl_exit_fatal;
1178 if (jcr->acl_data->u.build->content_length > 0) {
1179 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_DEFAULT_ACL) == bacl_exit_fatal)
1180 return bacl_exit_fatal;
1188 return bacl_exit_ok;
1191 static bacl_exit_code freebsd_parse_acl_streams(JCR *jcr,
1194 uint32_t content_length)
1196 int acl_enabled = 0;
1197 const char *acl_type_name;
1200 * First make sure the filesystem supports acls.
1203 case STREAM_UNIX_ACCESS_ACL:
1204 case STREAM_ACL_FREEBSD_ACCESS_ACL:
1205 case STREAM_UNIX_DEFAULT_ACL:
1206 case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1207 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
1208 acl_type_name = "POSIX";
1210 case STREAM_ACL_FREEBSD_NFS4_ACL:
1211 #if defined(_PC_ACL_NFS4)
1212 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
1214 acl_type_name = "NFS4";
1217 acl_type_name = "unknown";
1221 switch (acl_enabled) {
1227 return bacl_exit_ok;
1230 _("pathconf error on file \"%s\": ERR=%s\n"),
1231 jcr->last_fname, be.bstrerror());
1232 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1233 content, jcr->last_fname, be.bstrerror());
1234 return bacl_exit_error;
1239 * If the filesystem reports it doesn't support ACLs we clear the
1240 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
1241 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
1242 * when we change from one filesystem to an other.
1244 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1246 _("Trying to restore acl on file \"%s\" on filesystem without %s acl support\n"),
1247 jcr->last_fname, acl_type_name);
1248 return bacl_exit_error;
1257 case STREAM_UNIX_ACCESS_ACL:
1258 case STREAM_ACL_FREEBSD_ACCESS_ACL:
1259 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1260 case STREAM_UNIX_DEFAULT_ACL:
1261 case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1262 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1263 case STREAM_ACL_FREEBSD_NFS4_ACL:
1264 return generic_set_acl_on_os(jcr, BACL_TYPE_NFS4, content, content_length);
1268 return bacl_exit_error;
1272 * For this OSes setup the build and parse function pointer to the OS specific functions.
1274 static bacl_exit_code (*os_build_acl_streams)
1275 (JCR *jcr, FF_PKT *ff_pkt) =
1276 freebsd_build_acl_streams;
1277 static bacl_exit_code (*os_parse_acl_streams)
1278 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1279 freebsd_parse_acl_streams;
1281 #elif defined(HAVE_IRIX_OS) || \
1282 defined(HAVE_LINUX_OS) || \
1283 defined(HAVE_HURD_OS)
1285 * Define the supported ACL streams for these OSes
1287 #if defined(HAVE_IRIX_OS)
1288 static int os_access_acl_streams[1] = {
1289 STREAM_ACL_IRIX_ACCESS_ACL
1291 static int os_default_acl_streams[1] = {
1292 STREAM_ACL_IRIX_DEFAULT_ACL
1294 #elif defined(HAVE_LINUX_OS)
1295 static int os_access_acl_streams[1] = {
1296 STREAM_ACL_LINUX_ACCESS_ACL
1298 static int os_default_acl_streams[1] = {
1299 STREAM_ACL_LINUX_DEFAULT_ACL
1301 #elif defined(HAVE_HURD_OS)
1302 static int os_access_acl_streams[1] = {
1303 STREAM_ACL_HURD_ACCESS_ACL
1305 static int os_default_acl_streams[1] = {
1306 STREAM_ACL_HURD_DEFAULT_ACL
1310 static bacl_exit_code generic_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1313 * Read access ACLs for files, dirs and links
1315 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1316 return bacl_exit_fatal;
1318 if (jcr->acl_data->u.build->content_length > 0) {
1319 if (send_acl_stream(jcr, os_access_acl_streams[0]) == bacl_exit_fatal)
1320 return bacl_exit_fatal;
1324 * Directories can have default ACLs too
1326 if (ff_pkt->type == FT_DIREND) {
1327 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
1328 return bacl_exit_fatal;
1329 if (jcr->acl_data->u.build->content_length > 0) {
1330 if (send_acl_stream(jcr, os_default_acl_streams[0]) == bacl_exit_fatal)
1331 return bacl_exit_fatal;
1334 return bacl_exit_ok;
1337 static bacl_exit_code generic_parse_acl_streams(JCR *jcr,
1340 uint32_t content_length)
1345 case STREAM_UNIX_ACCESS_ACL:
1346 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1347 case STREAM_UNIX_DEFAULT_ACL:
1348 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1351 * See what type of acl it is.
1353 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1354 if (os_access_acl_streams[cnt] == stream) {
1355 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1358 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1359 if (os_default_acl_streams[cnt] == stream) {
1360 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1365 return bacl_exit_error;
1369 * For this OSes setup the build and parse function pointer to the OS specific functions.
1371 static bacl_exit_code (*os_build_acl_streams)
1372 (JCR *jcr, FF_PKT *ff_pkt) =
1373 generic_build_acl_streams;
1374 static bacl_exit_code (*os_parse_acl_streams)
1375 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1376 generic_parse_acl_streams;
1378 #elif defined(HAVE_OSF1_OS)
1381 * Define the supported ACL streams for this OS
1383 static int os_access_acl_streams[1] = {
1384 STREAM_ACL_TRU64_ACCESS_ACL
1386 static int os_default_acl_streams[2] = {
1387 STREAM_ACL_TRU64_DEFAULT_ACL,
1388 STREAM_ACL_TRU64_DEFAULT_DIR_ACL
1391 static bacl_exit_code tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1394 * Read access ACLs for files, dirs and links
1396 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == 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_ACCESS_ACL))
1400 return bacl_exit_error;
1403 * Directories can have default ACLs too
1405 if (ff_pkt->type == FT_DIREND) {
1406 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == 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_ACL))
1410 return bacl_exit_error;
1413 * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
1414 * This is an inherited acl for all subdirs.
1415 * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
1416 * Section 21.5 Default ACLs
1418 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR) == bacl_exit_fatal) {
1419 return bacl_exit_error;
1420 if (jcr->acl_data->u.build->content_length > 0) {
1421 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL))
1422 return bacl_exit_error;
1425 return bacl_exit_ok;
1428 static bacl_exit_code tru64_parse_acl_streams(JCR *jcr,
1431 uint32_t content_length)
1434 case STREAM_UNIX_ACCESS_ACL:
1435 case STREAM_ACL_TRU64_ACCESS_ACL:
1436 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1437 case STREAM_UNIX_DEFAULT_ACL:
1438 case STREAM_ACL_TRU64_DEFAULT_ACL:
1439 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1440 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
1441 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR, content, content_length);
1445 * For this OS setup the build and parse function pointer to the OS specific functions.
1447 static bacl_exit_code (*os_build_acl_streams)
1448 (JCR *jcr, FF_PKT *ff_pkt) =
1449 tru64_build_acl_streams;
1450 static bacl_exit_code (*os_parse_acl_streams)
1451 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1452 tru64_parse_acl_streams;
1456 #elif defined(HAVE_HPUX_OS)
1457 #ifdef HAVE_SYS_ACL_H
1458 #include <sys/acl.h>
1460 #error "configure failed to detect availability of sys/acl.h"
1466 * Define the supported ACL streams for this OS
1468 static int os_access_acl_streams[1] = {
1469 STREAM_ACL_HPUX_ACL_ENTRY
1471 static int os_default_acl_streams[1] = {
1476 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1477 * There is no need to store those acls as we already store the stat bits too.
1479 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
1482 struct acl_entry ace
1484 for (n = 0; n < count; n++) {
1487 * See if this acl just is the stat mode in acl form.
1489 if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
1490 (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
1491 (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
1498 * OS specific functions for handling different types of acl streams.
1500 static bacl_exit_code hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1503 struct acl_entry acls[NACLENTRIES];
1506 if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
1510 #if defined(BACL_ENOTSUP)
1513 * Not supported, just pretend there is nothing to see
1515 * If the filesystem reports it doesn't support ACLs we clear the
1516 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1517 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1518 * when we change from one filesystem to an other.
1520 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1521 pm_strcpy(jcr->acl_data->u.build->content, "");
1522 jcr->acl_data->u.build->content_length = 0;
1523 return bacl_exit_ok;
1526 pm_strcpy(jcr->acl_data->u.build->content, "");
1527 jcr->acl_data->u.build->content_length = 0;
1528 return bacl_exit_ok;
1531 _("getacl error on file \"%s\": ERR=%s\n"),
1532 jcr->last_fname, be.bstrerror());
1533 Dmsg2(100, "getacl error file=%s ERR=%s\n",
1534 jcr->last_fname, be.bstrerror());
1536 pm_strcpy(jcr->acl_data->u.build->content, "");
1537 jcr->acl_data->u.build->content_length = 0;
1538 return bacl_exit_error;
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 ((n = getacl(jcr->last_fname, n, acls)) > 0) {
1547 if (acl_is_trivial(n, acls, ff_pkt->statp)) {
1549 * The ACLs simply reflect the (already known) standard permissions
1550 * So we don't send an ACL stream to the SD.
1552 pm_strcpy(jcr->acl_data->u.build->content, "");
1553 jcr->acl_data->u.build->content_length = 0;
1554 return bacl_exit_ok;
1556 if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
1557 jcr->acl_data->u.build->content_length =
1558 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
1559 actuallyfree(acl_text);
1561 return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
1566 _("acltostr error on file \"%s\": ERR=%s\n"),
1567 jcr->last_fname, be.bstrerror());
1568 Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",
1569 jcr->acl_data->u.build->content, jcr->last_fname, be.bstrerror());
1570 return bacl_exit_error;
1572 return bacl_exit_error;
1575 static bacl_exit_code hpux_parse_acl_streams(JCR *jcr,
1578 uint32_t content_length)
1581 struct acl_entry acls[NACLENTRIES];
1583 n = strtoacl(content, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
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());
1592 return bacl_exit_error;
1594 if (strtoacl(content, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
1598 _("strtoacl error on file \"%s\": ERR=%s\n"),
1599 jcr->last_fname, be.bstrerror());
1600 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
1601 content, jcr->last_fname, be.bstrerror());
1603 return bacl_exit_error;
1606 * Restore the ACLs, but don't complain about links which really should
1607 * not have attributes, and the file it is linked to may not yet be restored.
1608 * This is only true for the old acl streams as in the new implementation we
1609 * don't save acls of symlinks (which cannot have acls anyhow)
1611 if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
1616 return bacl_exit_ok;
1617 #if defined(BACL_ENOTSUP)
1620 * If the filesystem reports it doesn't support ACLs we clear the
1621 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
1622 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
1623 * when we change from one filesystem to an other.
1625 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1627 _("setacl error on file \"%s\": filesystem doesn't support ACLs\n"),
1629 Dmsg2(100, "setacl error acl=%s file=%s filesystem doesn't support ACLs\n",
1630 content, jcr->last_fname);
1631 return bacl_exit_error;
1635 _("setacl error on file \"%s\": ERR=%s\n"),
1636 jcr->last_fname, be.bstrerror());
1637 Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
1638 content, jcr->last_fname, be.bstrerror());
1639 return bacl_exit_error;
1642 return bacl_exit_ok;
1646 * For this OS setup the build and parse function pointer to the OS specific functions.
1648 static bacl_exit_code (*os_build_acl_streams)
1649 (JCR *jcr, FF_PKT *ff_pkt) =
1650 hpux_build_acl_streams;
1651 static bacl_exit_code (*os_parse_acl_streams)
1652 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1653 hpux_parse_acl_streams;
1655 #elif defined(HAVE_SUN_OS)
1656 #ifdef HAVE_SYS_ACL_H
1657 #include <sys/acl.h>
1659 #error "configure failed to detect availability of sys/acl.h"
1662 #if defined(HAVE_EXTENDED_ACL)
1664 * We define some internals of the Solaris acl libs here as those
1665 * are not exposed yet. Probably because they want us to see the
1666 * acls as opague data. But as we need to support different platforms
1667 * and versions of Solaris we need to expose some data to be able
1668 * to determine the type of acl used to stuff it into the correct
1669 * data stream. I know this is far from portable, but maybe the
1670 * proper interface is exposed later on and we can get ride of
1671 * this kludge. Newer versions of Solaris include sys/acl_impl.h
1672 * which has implementation details of acls, if thats included we
1673 * don't have to define it ourself.
1675 #if !defined(_SYS_ACL_IMPL_H)
1676 typedef enum acl_type {
1683 * Two external references to functions in the libsec library function not in current include files.
1686 int acl_type(acl_t *);
1687 char *acl_strerror(int);
1691 * Define the supported ACL streams for this OS
1693 static int os_access_acl_streams[2] = {
1694 STREAM_ACL_SOLARIS_ACLENT,
1695 STREAM_ACL_SOLARIS_ACE
1697 static int os_default_acl_streams[1] = {
1702 * As the new libsec interface with acl_totext and acl_fromtext also handles
1703 * the old format from acltotext we can use the new functions even
1704 * for acls retrieved and stored in the database with older fd versions. If the
1705 * new interface is not defined (Solaris 9 and older we fall back to the old code)
1707 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1709 int acl_enabled, flags;
1712 bacl_exit_code stream_status = bacl_exit_error;
1715 * See if filesystem supports acls.
1717 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1718 switch (acl_enabled) {
1721 * If the filesystem reports it doesn't support ACLs we clear the
1722 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1723 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1724 * when we change from one filesystem to an other.
1726 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1727 pm_strcpy(jcr->acl_data->u.build->content, "");
1728 jcr->acl_data->u.build->content_length = 0;
1729 return bacl_exit_ok;
1735 return bacl_exit_ok;
1738 _("pathconf error on file \"%s\": ERR=%s\n"),
1739 jcr->last_fname, be.bstrerror());
1740 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
1741 jcr->last_fname, be.bstrerror());
1742 return bacl_exit_error;
1750 * Get ACL info: don't bother allocating space if there is only a trivial ACL.
1752 if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
1757 return bacl_exit_ok;
1760 _("acl_get error on file \"%s\": ERR=%s\n"),
1761 jcr->last_fname, acl_strerror(errno));
1762 Dmsg2(100, "acl_get error file=%s ERR=%s\n",
1763 jcr->last_fname, acl_strerror(errno));
1764 return bacl_exit_error;
1770 * The ACLs simply reflect the (already known) standard permissions
1771 * So we don't send an ACL stream to the SD.
1773 pm_strcpy(jcr->acl_data->u.build->content, "");
1774 jcr->acl_data->u.build->content_length = 0;
1775 return bacl_exit_ok;
1778 #if defined(ACL_SID_FMT)
1780 * New format flag added in newer Solaris versions.
1782 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
1784 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
1785 #endif /* ACL_SID_FMT */
1787 if ((acl_text = acl_totext(aclp, flags)) != NULL) {
1788 jcr->acl_data->u.build->content_length =
1789 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
1790 actuallyfree(acl_text);
1792 switch (acl_type(aclp)) {
1794 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1797 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE);
1805 return stream_status;
1808 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr,
1811 uint32_t content_length)
1814 int acl_enabled, error;
1817 case STREAM_UNIX_ACCESS_ACL:
1818 case STREAM_ACL_SOLARIS_ACLENT:
1819 case STREAM_ACL_SOLARIS_ACE:
1821 * First make sure the filesystem supports acls.
1823 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1824 switch (acl_enabled) {
1827 * If the filesystem reports it doesn't support ACLs we clear the
1828 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
1829 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
1830 * when we change from one filesystem to an other.
1832 jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
1834 _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
1836 return bacl_exit_error;
1842 return bacl_exit_ok;
1845 _("pathconf error on file \"%s\": ERR=%s\n"),
1846 jcr->last_fname, be.bstrerror());
1847 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1848 content, jcr->last_fname, be.bstrerror());
1849 return bacl_exit_error;
1854 * On a filesystem with ACL support make sure this particular ACL type can be restored.
1857 case STREAM_ACL_SOLARIS_ACLENT:
1859 * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
1861 if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
1863 _("Trying to restore POSIX acl on file \"%s\" on filesystem without aclent acl support\n"),
1865 return bacl_exit_error;
1868 case STREAM_ACL_SOLARIS_ACE:
1870 * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
1872 if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
1874 _("Trying to restore NFSv4 acl on file \"%s\" on filesystem without ace acl support\n"),
1876 return bacl_exit_error;
1881 * Stream id which doesn't describe the type of acl which is encoded.
1888 if ((error = acl_fromtext(content, &aclp)) != 0) {
1890 _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1891 jcr->last_fname, acl_strerror(error));
1892 Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",
1893 content, jcr->last_fname, acl_strerror(error));
1894 return bacl_exit_error;
1898 * Validate that the conversion gave us the correct acl type.
1901 case STREAM_ACL_SOLARIS_ACLENT:
1902 if (acl_type(aclp) != ACLENT_T) {
1904 _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1906 return bacl_exit_error;
1909 case STREAM_ACL_SOLARIS_ACE:
1910 if (acl_type(aclp) != ACE_T) {
1912 _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1914 return bacl_exit_error;
1919 * Stream id which doesn't describe the type of acl which is encoded.
1925 * Restore the ACLs, but don't complain about links which really should
1926 * not have attributes, and the file it is linked to may not yet be restored.
1927 * This is only true for the old acl streams as in the new implementation we
1928 * don't save acls of symlinks (which cannot have acls anyhow)
1930 if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1934 return bacl_exit_ok;
1937 _("acl_set error on file \"%s\": ERR=%s\n"),
1938 jcr->last_fname, acl_strerror(error));
1939 Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",
1940 content, jcr->last_fname, acl_strerror(error));
1942 return bacl_exit_error;
1947 return bacl_exit_ok;
1949 return bacl_exit_error;
1950 } /* end switch (stream) */
1953 #else /* HAVE_EXTENDED_ACL */
1956 * Define the supported ACL streams for this OS
1958 static int os_access_acl_streams[1] = {
1959 STREAM_ACL_SOLARIS_ACLENT
1961 static int os_default_acl_streams[1] = {
1966 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1967 * There is no need to store those acls as we already store the stat bits too.
1969 static bool acl_is_trivial(int count, aclent_t *entries)
1974 for (n = 0; n < count; n++) {
1977 if (!(ace->a_type == USER_OBJ ||
1978 ace->a_type == GROUP_OBJ ||
1979 ace->a_type == OTHER_OBJ ||
1980 ace->a_type == CLASS_OBJ))
1987 * OS specific functions for handling different types of acl streams.
1989 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1995 n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1996 if (n < MIN_ACL_ENTRIES) {
1997 return bacl_exit_error;
2000 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
2001 if (acl(jcr->last_fname, GETACL, n, acls) == n) {
2002 if (acl_is_trivial(n, acls)) {
2004 * The ACLs simply reflect the (already known) standard permissions
2005 * So we don't send an ACL stream to the SD.
2008 pm_strcpy(jcr->acl_data->u.build->content, "");
2009 jcr->acl_data->u.build->content_length = 0;
2010 return bacl_exit_ok;
2013 if ((acl_text = acltotext(acls, n)) != NULL) {
2014 jcr->acl_data->u.build->content_length =
2015 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
2016 actuallyfree(acl_text);
2018 return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
2023 _("acltotext error on file \"%s\": ERR=%s\n"),
2024 jcr->last_fname, be.bstrerror());
2025 Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",
2026 jcr->acl_data->u.build->content, jcr->last_fname, be.bstrerror());
2030 return bacl_exit_error;
2033 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr,
2036 uint32_t content_length)
2041 acls = aclfromtext(content, &n);
2046 _("aclfromtext error on file \"%s\": ERR=%s\n"),
2047 jcr->last_fname, be.bstrerror());
2048 Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",
2049 content, jcr->last_fname, be.bstrerror());
2050 return bacl_exit_error;
2054 * Restore the ACLs, but don't complain about links which really should
2055 * not have attributes, and the file it is linked to may not yet be restored.
2057 if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
2063 return bacl_exit_ok;
2066 _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
2067 jcr->last_fname, be.bstrerror());
2068 Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
2069 content, jcr->last_fname, be.bstrerror());
2071 return bacl_exit_error;
2075 return bacl_exit_ok;
2077 #endif /* HAVE_EXTENDED_ACL */
2080 * For this OS setup the build and parse function pointer to the OS specific functions.
2082 static bacl_exit_code (*os_build_acl_streams)
2083 (JCR *jcr, FF_PKT *ff_pkt) =
2084 solaris_build_acl_streams;
2085 static bacl_exit_code (*os_parse_acl_streams)
2086 (JCR *jcr, int stream, char *content, uint32_t content_length) =
2087 solaris_parse_acl_streams;
2089 #endif /* HAVE_SUN_OS */
2090 #endif /* HAVE_ACL */
2092 #if defined(HAVE_AFS_ACL)
2094 #if defined(HAVE_AFS_AFSINT_H) && defined(HAVE_AFS_VENUS_H)
2095 #include <afs/afsint.h>
2096 #include <afs/venus.h>
2098 #error "configure failed to detect availability of afs/afsint.h and/or afs/venus.h"
2102 * External references to functions in the libsys library function not in current include files.
2105 long pioctl(char *pathp, long opcode, struct ViceIoctl *blobp, int follow);
2108 static bacl_exit_code afs_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
2111 struct ViceIoctl vip;
2112 char acl_text[BUFSIZ];
2115 * AFS ACLs can only be set on a directory, so no need to try to
2116 * request them for anything other then that.
2118 if (ff_pkt->type != FT_DIREND) {
2119 return bacl_exit_ok;
2125 vip.out_size = sizeof(acl_text);
2126 memset((caddr_t)acl_text, 0, sizeof(acl_text));
2128 if ((error = pioctl(jcr->last_fname, VIOCGETAL, &vip, 0)) < 0) {
2132 _("pioctl VIOCGETAL error on file \"%s\": ERR=%s\n"),
2133 jcr->last_fname, be.bstrerror());
2134 Dmsg2(100, "pioctl VIOCGETAL error file=%s ERR=%s\n",
2135 jcr->last_fname, be.bstrerror());
2136 return bacl_exit_error;
2138 jcr->acl_data->u.build->content_length =
2139 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
2140 return send_acl_stream(jcr, STREAM_ACL_AFS_TEXT);
2143 static bacl_exit_code afs_parse_acl_stream(JCR *jcr,
2146 uint32_t content_length)
2149 struct ViceIoctl vip;
2152 vip.in_size = content_length;
2156 if ((error = pioctl(jcr->last_fname, VIOCSETAL, &vip, 0)) < 0) {
2160 _("pioctl VIOCSETAL error on file \"%s\": ERR=%s\n"),
2161 jcr->last_fname, be.bstrerror());
2162 Dmsg2(100, "pioctl VIOCSETAL error file=%s ERR=%s\n",
2163 jcr->last_fname, be.bstrerror());
2165 return bacl_exit_error;
2167 return bacl_exit_ok;
2169 #endif /* HAVE_AFS_ACL */
2172 * Entry points when compiled with support for ACLs on a supported platform.
2176 * Read and send an ACL for the last encountered file.
2178 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
2181 * See if we are changing from one device to an other.
2182 * We save the current device we are scanning and compare
2183 * it with the current st_dev in the last stat performed on
2184 * the file we are currently storing.
2186 if (jcr->acl_data->current_dev != ff_pkt->statp.st_dev) {
2188 * Reset the acl save flags.
2190 jcr->acl_data->flags = 0;
2192 #if defined(HAVE_AFS_ACL)
2194 * AFS is a non OS specific filesystem so see if this path is on an AFS filesystem
2195 * Set the BACL_FLAG_SAVE_AFS flag if it is. If not set the BACL_FLAG_SAVE_NATIVE flag.
2197 if (fstype_equals(jcr->last_fname, "afs")) {
2198 jcr->acl_data->flags |= BACL_FLAG_SAVE_AFS;
2200 jcr->acl_data->flags |= BACL_FLAG_SAVE_NATIVE;
2203 jcr->acl_data->flags |= BACL_FLAG_SAVE_NATIVE;
2207 * Save that we started scanning a new filesystem.
2209 jcr->acl_data->current_dev = ff_pkt->statp.st_dev;
2212 #if defined(HAVE_AFS_ACL)
2214 * See if the BACL_FLAG_SAVE_AFS flag is set which lets us know if we should
2217 if (jcr->acl_data->flags & BACL_FLAG_SAVE_AFS) {
2218 return afs_build_acl_streams(jcr, ff_pkt);
2221 #if defined(HAVE_ACL)
2223 * See if the BACL_FLAG_SAVE_NATIVE flag is set which lets us know if we should
2226 if (jcr->acl_data->flags & BACL_FLAG_SAVE_NATIVE) {
2228 * Call the appropriate function.
2230 if (os_build_acl_streams) {
2231 return os_build_acl_streams(jcr, ff_pkt);
2234 return bacl_exit_ok;
2237 return bacl_exit_error;
2240 bacl_exit_code parse_acl_streams(JCR *jcr,
2243 uint32_t content_length)
2250 * See if we are changing from one device to an other.
2251 * We save the current device we are restoring to and compare
2252 * it with the current st_dev in the last stat performed on
2253 * the file we are currently restoring.
2255 ret = lstat(jcr->last_fname, &st);
2262 return bacl_exit_ok;
2265 _("Unable to stat file \"%s\": ERR=%s\n"),
2266 jcr->last_fname, be.bstrerror());
2267 Dmsg2(100, "Unable to stat file \"%s\": ERR=%s\n",
2268 jcr->last_fname, be.bstrerror());
2269 return bacl_exit_error;
2276 if (jcr->acl_data->current_dev != st.st_dev) {
2278 * Reset the acl save flags.
2280 jcr->acl_data->flags = 0;
2282 #if defined(HAVE_AFS_ACL)
2284 * AFS is a non OS specific filesystem so see if this path is on an AFS filesystem
2285 * Set the BACL_FLAG_RESTORE_AFS flag if it is. If not set the BACL_FLAG_RETORE_NATIVE flag.
2287 if (fstype_equals(jcr->last_fname, "afs")) {
2288 jcr->acl_data->flags |= BACL_FLAG_RESTORE_AFS;
2290 jcr->acl_data->flags |= BACL_FLAG_RESTORE_NATIVE;
2293 jcr->acl_data->flags |= BACL_FLAG_RESTORE_NATIVE;
2297 * Save that we started restoring to a new filesystem.
2299 jcr->acl_data->current_dev = st.st_dev;
2303 #if defined(HAVE_AFS_ACL)
2304 case STREAM_ACL_AFS_TEXT:
2305 if (jcr->acl_data->flags & BACL_FLAG_RESTORE_AFS) {
2306 return afs_parse_acl_stream(jcr, stream, content, content_length);
2309 * Increment error count but don't log an error again for the same filesystem.
2311 jcr->acl_data->u.parse->nr_errors++;
2312 return bacl_exit_ok;
2315 #if defined(HAVE_ACL)
2316 case STREAM_UNIX_ACCESS_ACL:
2317 case STREAM_UNIX_DEFAULT_ACL:
2319 * Handle legacy ACL streams.
2321 if ((jcr->acl_data->flags & BACL_FLAG_RESTORE_NATIVE) && os_parse_acl_streams) {
2322 return os_parse_acl_streams(jcr, stream, content, content_length);
2325 * Increment error count but don't log an error again for the same filesystem.
2327 jcr->acl_data->u.parse->nr_errors++;
2328 return bacl_exit_ok;
2332 if ((jcr->acl_data->flags & BACL_FLAG_RESTORE_NATIVE) && os_parse_acl_streams) {
2334 * Walk the os_access_acl_streams array with the supported Access ACL streams for this OS.
2336 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
2337 if (os_access_acl_streams[cnt] == stream) {
2338 return os_parse_acl_streams(jcr, stream, content, content_length);
2342 * Walk the os_default_acl_streams array with the supported Default ACL streams for this OS.
2344 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
2345 if (os_default_acl_streams[cnt] == stream) {
2346 return os_parse_acl_streams(jcr, stream, content, content_length);
2351 * Increment error count but don't log an error again for the same filesystem.
2353 jcr->acl_data->u.parse->nr_errors++;
2354 return bacl_exit_ok;
2362 Qmsg2(jcr, M_WARNING, 0,
2363 _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
2364 jcr->last_fname, stream);
2365 return bacl_exit_error;