2 Bacula® - The Network Backup Solution
4 Copyright (C) 2004-2012 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Functions to handle ACLs for bacula.
31 * Currently we support the following OSes:
32 * - AIX (pre-5.3 and post 5.3 acls, acl_get and aclx_get interface)
34 * - FreeBSD (POSIX and NFSv4/ZFS acls)
38 * - Solaris (POSIX and NFSv4/ZFS acls)
41 * We handle two different types of ACLs: access and default ACLS.
42 * On most systems that support default ACLs they only apply to directories.
44 * On some systems (eg. linux and FreeBSD) we must obtain the two ACLs
45 * independently, while others (eg. Solaris) provide both in one call.
47 * The Filed saves ACLs in their native format and uses different streams
48 * for all different platforms. Currently we only allow ACLs to be restored
49 * which were saved in the native format of the platform they are extracted
50 * on. Later on we might add conversion functions for mapping from one
51 * platform to an other or allow restores of systems that use the same
54 * Its also interesting to see what the exact format of acl text is on
55 * certain platforms and if they use they same encoding we might allow
56 * different platform streams to be decoded on an other similar platform.
58 * Original written by Preben 'Peppe' Guldberg, December 2004
59 * Major rewrite by Marco van Wieringen, November 2008
60 * Major overhaul by Marco van Wieringen, January 2012
66 #if !defined(HAVE_ACL)
68 * Entry points when compiled without support for ACLs or on an unsupported platform.
70 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
72 return bacl_exit_fatal;
75 bacl_exit_code parse_acl_streams(JCR *jcr,
78 uint32_t content_length)
80 return bacl_exit_fatal;
84 * Send an ACL stream to the SD.
86 static bacl_exit_code send_acl_stream(JCR *jcr, int stream)
88 BSOCK *sd = jcr->store_bsock;
90 #ifdef FD_NO_SEND_TEST
97 if (jcr->acl_data->u.build->content_length <= 0) {
104 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
105 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
107 return bacl_exit_fatal;
111 * Send the buffer to the storage deamon
113 Dmsg1(400, "Backing up ACL <%s>\n", jcr->acl_data->u.build->content);
115 sd->msg = jcr->acl_data->u.build->content;
116 sd->msglen = jcr->acl_data->u.build->content_length + 1;
120 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
122 return bacl_exit_fatal;
125 jcr->JobBytes += sd->msglen;
127 if (!sd->signal(BNET_EOD)) {
128 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
130 return bacl_exit_fatal;
133 Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
138 * First the native ACLs.
140 #if defined(HAVE_ACL)
141 #if defined(HAVE_AIX_OS)
143 #if defined(HAVE_EXTENDED_ACL)
145 #include <sys/access.h>
148 static bool acl_is_trivial(struct acl *acl)
150 return (acl_last(acl) != acl->acl_ext ? false : true);
153 static bool acl_nfs4_is_trivial(nfs4_acl_int_t *acl)
156 return (acl->aclEntryN > 0 ? false : true);
159 int count = acl->aclEntryN;
162 for (i = 0; i < count; i++) {
163 ace = &acl->aclEntry[i];
164 if (!((ace->flags & ACE4_ID_SPECIAL) != 0 &&
165 (ace->aceWho.special_whoid == ACE4_WHO_OWNER ||
166 ace->aceWho.special_whoid == ACE4_WHO_GROUP ||
167 ace->aceWho.special_whoid == ACE4_WHO_EVERYONE) &&
168 ace->aceType == ACE4_ACCESS_ALLOWED_ACE_TYPE &&
169 ace->aceFlags == 0 &&
170 (ace->aceMask & ~(ACE4_READ_DATA |
171 ACE4_LIST_DIRECTORY |
174 ACE4_EXECUTE)) == 0)) {
183 * Define the supported ACL streams for this OS
185 static int os_access_acl_streams[3] = {
190 static int os_default_acl_streams[1] = {
194 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
198 size_t aclsize, acltxtsize;
199 bacl_exit_code retval = bacl_exit_error;
200 POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
203 * First see how big the buffers should be.
205 memset(&type, 0, sizeof(acl_type_t));
207 if (aclx_get(jcr->last_fname, GET_ACLINFO_ONLY, &type, NULL, &aclsize, &mode) < 0) {
212 retval = bacl_exit_ok;
216 * If the filesystem reports it doesn't support ACLs we clear the
217 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
218 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
219 * when we change from one filesystem to an other.
221 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
222 retval = bacl_exit_ok;
226 _("aclx_get error on file \"%s\": ERR=%s\n"),
227 jcr->last_fname, be.bstrerror());
228 Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
229 jcr->last_fname, be.bstrerror());
235 * Make sure the buffers are big enough.
237 aclbuf = check_pool_memory_size(aclbuf, aclsize + 1);
240 * Retrieve the ACL info.
242 if (aclx_get(jcr->last_fname, 0, &type, aclbuf, &aclsize, &mode) < 0) {
247 retval = bacl_exit_ok;
251 _("aclx_get error on file \"%s\": ERR=%s\n"),
252 jcr->last_fname, be.bstrerror());
253 Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
254 jcr->last_fname, be.bstrerror());
260 * See if the acl is non trivial.
264 if (acl_is_trivial((struct acl *)aclbuf)) {
265 retval = bacl_exit_ok;
270 if (acl_nfs4_is_trivial((nfs4_acl_int_t *)aclbuf)) {
271 retval = bacl_exit_ok;
277 _("Unknown acl type encountered on file \"%s\": %ld\n"),
278 jcr->last_fname, type.u64);
279 Dmsg2(100, "Unknown acl type encountered on file \"%s\": %ld\n",
280 jcr->last_fname, type.u64);
285 * We have a non-trivial acl lets convert it into some ASCII form.
287 acltxtsize = sizeof_pool_memory(jcr->acl_data->u.build->content);
288 if (aclx_printStr(jcr->acl_data->u.build->content, &acltxtsize, aclbuf,
289 aclsize, type, jcr->last_fname, 0) < 0) {
293 * Our buffer is not big enough, acltxtsize should be updated with the value
294 * the aclx_printStr really need. So we increase the buffer and try again.
296 jcr->acl_data->u.build->content =
297 check_pool_memory_size(jcr->acl_data->u.build->content, acltxtsize + 1);
298 if (aclx_printStr(jcr->acl_data->u.build->content, &acltxtsize, aclbuf,
299 aclsize, type, jcr->last_fname, 0) < 0) {
301 _("Failed to convert acl into text on file \"%s\"\n"),
303 Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
304 jcr->last_fname, type.u64);
310 _("Failed to convert acl into text on file \"%s\"\n"),
312 Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
313 jcr->last_fname, type.u64);
318 jcr->acl_data->u.build->content_length = strlen(jcr->acl_data->u.build->content) + 1;
321 retval = send_acl_stream(jcr, STREAM_ACL_AIX_AIXC);
323 retval = send_acl_stream(jcr, STREAM_ACL_AIX_NFS4);
327 free_pool_memory(aclbuf);
333 * See if a specific type of ACLs are supported on the filesystem
334 * the file is located on.
336 static inline bool aix_query_acl_support(JCR *jcr,
338 acl_type_t *pacl_type_info)
341 acl_types_list_t acl_type_list;
342 size_t acl_type_list_len = sizeof(acl_types_list_t);
344 memset(&acl_type_list, 0, sizeof(acl_type_list));
345 if (aclx_gettypes(jcr->last_fname, &acl_type_list, &acl_type_list_len)) {
349 for (i = 0; i < acl_type_list.num_entries; i++) {
350 if (acl_type_list.entries[i].u64 == aclType) {
351 memcpy(pacl_type_info, acl_type_list.entries + i, sizeof(acl_type_t));
358 static bacl_exit_code aix_parse_acl_streams(JCR *jcr,
361 uint32_t content_length)
366 bacl_exit_code retval = bacl_exit_error;
367 POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
370 case STREAM_ACL_AIX_TEXT:
372 * Handle the old stream using the old system call for now.
374 if (acl_put(jcr->last_fname, content, 0) != 0) {
375 retval = bacl_exit_error;
378 retval = bacl_exit_ok;
380 case STREAM_ACL_AIX_AIXC:
381 if (!aix_query_acl_support(jcr, ACL_AIXC, &type)) {
383 _("Trying to restore POSIX acl on file \"%s\" on filesystem without AIXC acl support\n"),
388 case STREAM_ACL_AIX_NFS4:
389 if (!aix_query_acl_support(jcr, ACL_NFS4, &type)) {
391 _("Trying to restore NFSv4 acl on file \"%s\" on filesystem without NFS4 acl support\n"),
398 } /* end switch (stream) */
401 * Set the acl buffer to an initial size. For now we set it
402 * to the same size as the ASCII representation.
404 aclbuf = check_pool_memory_size(aclbuf, content_length);
405 aclsize = content_length;
406 if (aclx_scanStr(content, aclbuf, &aclsize, type) < 0) {
412 * The buffer isn't big enough. The man page doesn't say that aclsize
413 * is updated to the needed size as what is done with aclx_printStr.
414 * So for now we try to increase the buffer a maximum of 3 times
415 * and retry the conversion.
417 for (cnt = 0; cnt < 3; cnt++) {
418 aclsize = 2 * aclsize;
419 aclbuf = check_pool_memory_size(aclbuf, aclsize);
421 if (aclx_scanStr(content, aclbuf, &aclsize, type) == 0) {
426 * See why we failed this time, ENOSPC retry if max retries not met,
437 _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
438 jcr->last_fname, be.bstrerror(errno));
439 Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
440 jcr->last_fname, be.bstrerror());
447 _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
448 jcr->last_fname, be.bstrerror());
449 Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
450 jcr->last_fname, be.bstrerror());
454 if (aclx_put(jcr->last_fname, SET_ACL, type, aclbuf, aclsize, 0) < 0) {
459 retval = bacl_exit_ok;
463 * If the filesystem reports it doesn't support ACLs we clear the
464 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
465 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
466 * when we change from one filesystem to an other.
468 jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
469 retval = bacl_exit_ok;
473 _("aclx_put error on file \"%s\": ERR=%s\n"),
474 jcr->last_fname, be.bstrerror());
475 Dmsg2(100, "aclx_put error file=%s ERR=%s\n",
476 jcr->last_fname, be.bstrerror());
481 retval = bacl_exit_ok;
484 free_pool_memory(aclbuf);
489 #else /* HAVE_EXTENDED_ACL */
491 #include <sys/access.h>
494 * Define the supported ACL streams for this OS
496 static int os_access_acl_streams[1] = {
499 static int os_default_acl_streams[1] = {
503 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
507 if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
508 jcr->acl_data->u.build->content_length =
509 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
510 actuallyfree(acl_text);
511 return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT);
513 return bacl_exit_error;
516 static bacl_exit_code aix_parse_acl_streams(JCR *jcr,
519 uint32_t content_length)
521 if (acl_put(jcr->last_fname, content, 0) != 0) {
522 return bacl_exit_error;
526 #endif /* HAVE_EXTENDED_ACL */
529 * For this OS setup the build and parse function pointer to the OS specific functions.
531 static bacl_exit_code (*os_build_acl_streams)
532 (JCR *jcr, FF_PKT *ff_pkt) =
533 aix_build_acl_streams;
534 static bacl_exit_code (*os_parse_acl_streams)
535 (JCR *jcr, int stream, char *content, uint32_t content_length) =
536 aix_parse_acl_streams;
538 #elif defined(HAVE_DARWIN_OS) || \
539 defined(HAVE_FREEBSD_OS) || \
540 defined(HAVE_IRIX_OS) || \
541 defined(HAVE_OSF1_OS) || \
542 defined(HAVE_LINUX_OS)
544 #include <sys/types.h>
546 #ifdef HAVE_SYS_ACL_H
549 #error "configure failed to detect availability of sys/acl.h"
553 * On IRIX we can get shortened ACLs
555 #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
556 #define acl_to_text(acl,len) acl_to_short_text((acl), (len))
560 * On Linux we can get numeric and/or shorted ACLs
562 #if defined(HAVE_LINUX_OS)
563 #if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
564 #define BACL_ALTERNATE_TEXT (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
565 #elif defined(BACL_WANT_SHORT_ACLS)
566 #define BACL_ALTERNATE_TEXT TEXT_ABBREVIATE
567 #elif defined(BACL_WANT_NUMERIC_IDS)
568 #define BACL_ALTERNATE_TEXT TEXT_NUMERIC_IDS
570 #ifdef BACL_ALTERNATE_TEXT
571 #include <acl/libacl.h>
572 #define acl_to_text(acl,len) (acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
577 * On FreeBSD we can get numeric ACLs
579 #if defined(HAVE_FREEBSD_OS)
580 #if defined(BACL_WANT_NUMERIC_IDS)
581 #define BACL_ALTERNATE_TEXT ACL_TEXT_NUMERIC_IDS
583 #ifdef BACL_ALTERNATE_TEXT
584 #define acl_to_text(acl,len) (acl_to_text_np((acl), (len), BACL_ALTERNATE_TEXT))
589 * Some generic functions used by multiple OSes.
591 static acl_type_t bac_to_os_acltype(bacl_type acltype)
596 case BACL_TYPE_ACCESS:
597 ostype = ACL_TYPE_ACCESS;
599 case BACL_TYPE_DEFAULT:
600 ostype = ACL_TYPE_DEFAULT;
602 #ifdef HAVE_ACL_TYPE_NFS4
604 * FreeBSD has an additional acl type named ACL_TYPE_NFS4.
607 ostype = ACL_TYPE_NFS4;
610 #ifdef HAVE_ACL_TYPE_DEFAULT_DIR
611 case BACL_TYPE_DEFAULT_DIR:
613 * TRU64 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
615 ostype = ACL_TYPE_DEFAULT_DIR;
618 #ifdef HAVE_ACL_TYPE_EXTENDED
619 case BACL_TYPE_EXTENDED:
621 * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
623 ostype = ACL_TYPE_EXTENDED;
628 * This should never happen, as the per OS version function only tries acl
629 * types supported on a certain platform.
631 ostype = (acl_type_t)ACL_TYPE_NONE;
637 static int acl_count_entries(acl_t acl)
640 #if defined(HAVE_FREEBSD_OS) || \
641 defined(HAVE_LINUX_OS)
645 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
646 while (entry_available == 1) {
648 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
650 #elif defined(HAVE_IRIX_OS)
651 count = acl->acl_cnt;
652 #elif defined(HAVE_OSF1_OS)
653 count = acl->acl_num;
654 #elif defined(HAVE_DARWIN_OS)
658 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
659 while (entry_available == 0) {
661 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
667 #if !defined(HAVE_DARWIN_OS)
669 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
670 * There is no need to store those acls as we already store the stat bits too.
672 static bool acl_is_trivial(acl_t acl)
675 * acl is trivial if it has only the following entries:
682 #if defined(HAVE_FREEBSD_OS) || \
683 defined(HAVE_LINUX_OS)
686 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
687 while (entry_available == 1) {
689 * Get the tag type of this acl entry.
690 * If we fail to get the tagtype we call the acl non-trivial.
692 if (acl_get_tag_type(ace, &tag) < 0)
695 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
697 if (tag != ACL_USER_OBJ &&
698 tag != ACL_GROUP_OBJ &&
701 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
704 #elif defined(HAVE_IRIX_OS)
707 for (n = 0; n < acl->acl_cnt; n++) {
708 ace = &acl->acl_entry[n];
712 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
714 if (tag != ACL_USER_OBJ &&
715 tag != ACL_GROUP_OBJ &&
716 tag != ACL_OTHER_OBJ)
720 #elif defined(HAVE_OSF1_OS)
723 ace = acl->acl_first;
724 count = acl->acl_num;
727 tag = ace->entry->acl_type;
729 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
731 if (tag != ACL_USER_OBJ &&
732 tag != ACL_GROUP_OBJ &&
736 * On Tru64, perm can also contain non-standard bits such as
737 * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
739 if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
750 * Generic wrapper around acl_get_file call.
752 static bacl_exit_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
757 bacl_exit_code retval = bacl_exit_ok;
759 ostype = bac_to_os_acltype(acltype);
760 acl = acl_get_file(jcr->last_fname, ostype);
763 * From observation, IRIX's acl_get_file() seems to return a
764 * non-NULL acl with a count field of -1 when a file has no ACL
765 * defined, while IRIX's acl_to_text() returns NULL when presented
768 * For all other implmentations we check if there are more then
769 * zero entries in the acl returned.
771 if (acl_count_entries(acl) <= 0) {
776 * Make sure this is not just a trivial ACL.
778 #if !defined(HAVE_DARWIN_OS)
779 if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
781 * The ACLs simply reflect the (already known) standard permissions
782 * So we don't send an ACL stream to the SD.
787 #if defined(HAVE_FREEBSD_OS) && defined(_PC_ACL_NFS4)
788 if (acltype == BACL_TYPE_NFS4) {
790 if (acl_is_trivial_np(acl, &trivial) == 0) {
793 * The ACLs simply reflect the (already known) standard permissions
794 * So we don't send an ACL stream to the SD.
803 * Convert the internal acl representation into a text representation.
805 if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
806 jcr->acl_data->u.build->content_length =
807 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
815 _("acl_to_text error on file \"%s\": ERR=%s\n"),
816 jcr->last_fname, be.bstrerror());
817 Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",
818 jcr->last_fname, be.bstrerror());
820 retval = bacl_exit_error;
826 * Handle errors gracefully.
829 #if defined(BACL_ENOTSUP)
832 * If the filesystem reports it doesn't support ACLs we clear the
833 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
834 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
835 * when we change from one filesystem to an other.
837 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
843 /* Some real error */
845 _("acl_get_file error on file \"%s\": ERR=%s\n"),
846 jcr->last_fname, be.bstrerror());
847 Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",
848 jcr->last_fname, be.bstrerror());
850 retval = bacl_exit_error;
859 pm_strcpy(jcr->acl_data->u.build->content, "");
860 jcr->acl_data->u.build->content_length = 0;
865 * Generic wrapper around acl_set_file call.
867 static bacl_exit_code generic_set_acl_on_os(JCR *jcr,
870 uint32_t content_length)
876 * If we get empty default ACLs, clear ACLs now
878 ostype = bac_to_os_acltype(acltype);
879 if (ostype == ACL_TYPE_DEFAULT && strlen(content) == 0) {
880 if (acl_delete_def_file(jcr->last_fname) == 0) {
888 #if defined(BACL_ENOTSUP)
891 * If the filesystem reports it doesn't support ACLs we clear the
892 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
893 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
894 * when we change from one filesystem to an other.
896 jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
898 _("acl_delete_def_file error on file \"%s\": filesystem doesn't support ACLs\n"),
900 return bacl_exit_error;
904 _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
905 jcr->last_fname, be.bstrerror());
906 return bacl_exit_error;
910 acl = acl_from_text(content);
915 _("acl_from_text error on file \"%s\": ERR=%s\n"),
916 jcr->last_fname, be.bstrerror());
917 Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",
918 content, jcr->last_fname, be.bstrerror());
919 return bacl_exit_error;
922 #ifndef HAVE_FREEBSD_OS
924 * FreeBSD always fails acl_valid() - at least on valid input...
925 * As it does the right thing, given valid input, just ignore acl_valid().
927 if (acl_valid(acl) != 0) {
931 _("acl_valid error on file \"%s\": ERR=%s\n"),
932 jcr->last_fname, be.bstrerror());
933 Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",
934 content, jcr->last_fname, be.bstrerror());
936 return bacl_exit_error;
941 * Restore the ACLs, but don't complain about links which really should
942 * not have attributes, and the file it is linked to may not yet be restored.
943 * This is only true for the old acl streams as in the new implementation we
944 * don't save acls of symlinks (which cannot have acls anyhow)
946 if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
953 #if defined(BACL_ENOTSUP)
956 * If the filesystem reports it doesn't support ACLs we clear the
957 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
958 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
959 * when we change from one filesystem to an other.
961 jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
963 _("acl_set_file error on file \"%s\": filesystem doesn't support ACLs\n"),
965 Dmsg2(100, "acl_set_file error acl=%s file=%s filesystem doesn't support ACLs\n",
966 content, jcr->last_fname);
968 return bacl_exit_error;
972 _("acl_set_file error on file \"%s\": ERR=%s\n"),
973 jcr->last_fname, be.bstrerror());
974 Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
975 content, jcr->last_fname, be.bstrerror());
977 return bacl_exit_error;
985 * OS specific functions for handling different types of acl streams.
987 #if defined(HAVE_DARWIN_OS)
989 * Define the supported ACL streams for this OS
991 static int os_access_acl_streams[1] = {
992 STREAM_ACL_DARWIN_ACCESS_ACL
994 static int os_default_acl_streams[1] = {
998 static bacl_exit_code darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1000 #if defined(HAVE_ACL_TYPE_EXTENDED)
1002 * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
1003 * and acl_get_file (name, ACL_TYPE_DEFAULT)
1004 * always return NULL / EINVAL. There is no point in making
1005 * these two useless calls. The real ACL is retrieved through
1006 * acl_get_file (name, ACL_TYPE_EXTENDED).
1008 * Read access ACLs for files, dirs and links
1010 if (generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED) == bacl_exit_fatal)
1011 return bacl_exit_fatal;
1014 * Read access ACLs for files, dirs and links
1016 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1017 return bacl_exit_fatal;
1020 if (jcr->acl_data->u.build->content_length > 0) {
1021 return send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL);
1023 return bacl_exit_ok;
1026 static bacl_exit_code darwin_parse_acl_streams(JCR *jcr,
1029 uint32_t content_length)
1031 #if defined(HAVE_ACL_TYPE_EXTENDED)
1032 return generic_set_acl_on_os(jcr, BACL_TYPE_EXTENDED, content, content_length);
1034 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1039 * For this OS setup the build and parse function pointer to the OS specific functions.
1041 static bacl_exit_code (*os_build_acl_streams)
1042 (JCR *jcr, FF_PKT *ff_pkt) =
1043 darwin_build_acl_streams;
1044 static bacl_exit_code (*os_parse_acl_streams)
1045 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1046 darwin_parse_acl_streams;
1048 #elif defined(HAVE_FREEBSD_OS)
1050 * Define the supported ACL streams for these OSes
1052 static int os_access_acl_streams[2] = {
1053 STREAM_ACL_FREEBSD_ACCESS_ACL,
1054 STREAM_ACL_FREEBSD_NFS4_ACL
1056 static int os_default_acl_streams[1] = {
1057 STREAM_ACL_FREEBSD_DEFAULT_ACL
1060 static bacl_exit_code freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1062 int acl_enabled = 0;
1063 bacl_type acltype = BACL_TYPE_NONE;
1065 #if defined(_PC_ACL_NFS4)
1067 * See if filesystem supports NFS4 acls.
1069 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
1070 switch (acl_enabled) {
1076 return bacl_exit_ok;
1079 _("pathconf error on file \"%s\": ERR=%s\n"),
1080 jcr->last_fname, be.bstrerror());
1081 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
1082 jcr->last_fname, be.bstrerror());
1083 return bacl_exit_error;
1089 acltype = BACL_TYPE_NFS4;
1094 if (acl_enabled == 0) {
1096 * See if filesystem supports POSIX acls.
1098 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
1099 switch (acl_enabled) {
1105 return bacl_exit_ok;
1108 _("pathconf error on file \"%s\": ERR=%s\n"),
1109 jcr->last_fname, be.bstrerror());
1110 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
1111 jcr->last_fname, be.bstrerror());
1112 return bacl_exit_error;
1118 acltype = BACL_TYPE_ACCESS;
1124 * If the filesystem reports it doesn't support ACLs we clear the
1125 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1126 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1127 * when we change from one filesystem to an other.
1129 if (acl_enabled == 0) {
1130 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1131 pm_strcpy(jcr->acl_data->u.build->content, "");
1132 jcr->acl_data->u.build->content_length = 0;
1133 return bacl_exit_ok;
1137 * Based on the supported ACLs retrieve and store them.
1140 case BACL_TYPE_NFS4:
1142 * Read NFS4 ACLs for files, dirs and links
1144 if (generic_get_acl_from_os(jcr, BACL_TYPE_NFS4) == bacl_exit_fatal)
1145 return bacl_exit_fatal;
1147 if (jcr->acl_data->u.build->content_length > 0) {
1148 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_NFS4_ACL) == bacl_exit_fatal)
1149 return bacl_exit_fatal;
1152 case BACL_TYPE_ACCESS:
1154 * Read access ACLs for files, dirs and links
1156 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1157 return bacl_exit_fatal;
1159 if (jcr->acl_data->u.build->content_length > 0) {
1160 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_ACCESS_ACL) == bacl_exit_fatal)
1161 return bacl_exit_fatal;
1165 * Directories can have default ACLs too
1167 if (ff_pkt->type == FT_DIREND) {
1168 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
1169 return bacl_exit_fatal;
1170 if (jcr->acl_data->u.build->content_length > 0) {
1171 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_DEFAULT_ACL) == bacl_exit_fatal)
1172 return bacl_exit_fatal;
1180 return bacl_exit_ok;
1183 static bacl_exit_code freebsd_parse_acl_streams(JCR *jcr,
1186 uint32_t content_length)
1188 int acl_enabled = 0;
1189 const char *acl_type_name;
1192 * First make sure the filesystem supports acls.
1195 case STREAM_UNIX_ACCESS_ACL:
1196 case STREAM_ACL_FREEBSD_ACCESS_ACL:
1197 case STREAM_UNIX_DEFAULT_ACL:
1198 case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1199 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
1200 acl_type_name = "POSIX";
1202 case STREAM_ACL_FREEBSD_NFS4_ACL:
1203 #if defined(_PC_ACL_NFS4)
1204 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
1206 acl_type_name = "NFS4";
1209 acl_type_name = "unknown";
1213 switch (acl_enabled) {
1219 return bacl_exit_ok;
1222 _("pathconf error on file \"%s\": ERR=%s\n"),
1223 jcr->last_fname, be.bstrerror());
1224 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1225 content, jcr->last_fname, be.bstrerror());
1226 return bacl_exit_error;
1231 * If the filesystem reports it doesn't support ACLs we clear the
1232 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
1233 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
1234 * when we change from one filesystem to an other.
1236 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1238 _("Trying to restore acl on file \"%s\" on filesystem without %s acl support\n"),
1239 jcr->last_fname, acl_type_name);
1240 return bacl_exit_error;
1249 case STREAM_UNIX_ACCESS_ACL:
1250 case STREAM_ACL_FREEBSD_ACCESS_ACL:
1251 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1252 case STREAM_UNIX_DEFAULT_ACL:
1253 case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1254 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1255 case STREAM_ACL_FREEBSD_NFS4_ACL:
1256 return generic_set_acl_on_os(jcr, BACL_TYPE_NFS4, content, content_length);
1260 return bacl_exit_error;
1264 * For this OSes setup the build and parse function pointer to the OS specific functions.
1266 static bacl_exit_code (*os_build_acl_streams)
1267 (JCR *jcr, FF_PKT *ff_pkt) =
1268 freebsd_build_acl_streams;
1269 static bacl_exit_code (*os_parse_acl_streams)
1270 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1271 freebsd_parse_acl_streams;
1273 #elif defined(HAVE_IRIX_OS) || \
1274 defined(HAVE_LINUX_OS)
1276 * Define the supported ACL streams for these OSes
1278 #if defined(HAVE_IRIX_OS)
1279 static int os_access_acl_streams[1] = {
1280 STREAM_ACL_IRIX_ACCESS_ACL
1282 static int os_default_acl_streams[1] = {
1283 STREAM_ACL_IRIX_DEFAULT_ACL
1285 #elif defined(HAVE_LINUX_OS)
1286 static int os_access_acl_streams[1] = {
1287 STREAM_ACL_LINUX_ACCESS_ACL
1289 static int os_default_acl_streams[1] = {
1290 STREAM_ACL_LINUX_DEFAULT_ACL
1294 static bacl_exit_code generic_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1297 * Read access ACLs for files, dirs and links
1299 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1300 return bacl_exit_fatal;
1302 if (jcr->acl_data->u.build->content_length > 0) {
1303 if (send_acl_stream(jcr, os_access_acl_streams[0]) == bacl_exit_fatal)
1304 return bacl_exit_fatal;
1308 * Directories can have default ACLs too
1310 if (ff_pkt->type == FT_DIREND) {
1311 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
1312 return bacl_exit_fatal;
1313 if (jcr->acl_data->u.build->content_length > 0) {
1314 if (send_acl_stream(jcr, os_default_acl_streams[0]) == bacl_exit_fatal)
1315 return bacl_exit_fatal;
1318 return bacl_exit_ok;
1321 static bacl_exit_code generic_parse_acl_streams(JCR *jcr,
1324 uint32_t content_length)
1329 case STREAM_UNIX_ACCESS_ACL:
1330 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1331 case STREAM_UNIX_DEFAULT_ACL:
1332 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1335 * See what type of acl it is.
1337 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1338 if (os_access_acl_streams[cnt] == stream) {
1339 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1342 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1343 if (os_default_acl_streams[cnt] == stream) {
1344 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1349 return bacl_exit_error;
1353 * For this OSes setup the build and parse function pointer to the OS specific functions.
1355 static bacl_exit_code (*os_build_acl_streams)
1356 (JCR *jcr, FF_PKT *ff_pkt) =
1357 generic_build_acl_streams;
1358 static bacl_exit_code (*os_parse_acl_streams)
1359 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1360 generic_parse_acl_streams;
1362 #elif defined(HAVE_OSF1_OS)
1365 * Define the supported ACL streams for this OS
1367 static int os_access_acl_streams[1] = {
1368 STREAM_ACL_TRU64_ACCESS_ACL
1370 static int os_default_acl_streams[2] = {
1371 STREAM_ACL_TRU64_DEFAULT_ACL,
1372 STREAM_ACL_TRU64_DEFAULT_DIR_ACL
1375 static bacl_exit_code tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1378 * Read access ACLs for files, dirs and links
1380 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal) {
1381 return bacl_exit_error;
1382 if (jcr->acl_data->u.build->content_length > 0) {
1383 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL))
1384 return bacl_exit_error;
1387 * Directories can have default ACLs too
1389 if (ff_pkt->type == FT_DIREND) {
1390 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal) {
1391 return bacl_exit_error;
1392 if (jcr->acl_data->u.build->content_length > 0) {
1393 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL))
1394 return bacl_exit_error;
1397 * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
1398 * This is an inherited acl for all subdirs.
1399 * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
1400 * Section 21.5 Default ACLs
1402 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR) == bacl_exit_fatal) {
1403 return bacl_exit_error;
1404 if (jcr->acl_data->u.build->content_length > 0) {
1405 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL))
1406 return bacl_exit_error;
1409 return bacl_exit_ok;
1412 static bacl_exit_code tru64_parse_acl_streams(JCR *jcr,
1415 uint32_t content_length)
1418 case STREAM_UNIX_ACCESS_ACL:
1419 case STREAM_ACL_TRU64_ACCESS_ACL:
1420 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1421 case STREAM_UNIX_DEFAULT_ACL:
1422 case STREAM_ACL_TRU64_DEFAULT_ACL:
1423 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1424 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
1425 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR, content, content_length);
1429 * For this OS setup the build and parse function pointer to the OS specific functions.
1431 static bacl_exit_code (*os_build_acl_streams)
1432 (JCR *jcr, FF_PKT *ff_pkt) =
1433 tru64_build_acl_streams;
1434 static bacl_exit_code (*os_parse_acl_streams)
1435 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1436 tru64_parse_acl_streams;
1440 #elif defined(HAVE_HPUX_OS)
1441 #ifdef HAVE_SYS_ACL_H
1442 #include <sys/acl.h>
1444 #error "configure failed to detect availability of sys/acl.h"
1450 * Define the supported ACL streams for this OS
1452 static int os_access_acl_streams[1] = {
1453 STREAM_ACL_HPUX_ACL_ENTRY
1455 static int os_default_acl_streams[1] = {
1460 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1461 * There is no need to store those acls as we already store the stat bits too.
1463 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
1466 struct acl_entry ace
1468 for (n = 0; n < count; n++) {
1471 * See if this acl just is the stat mode in acl form.
1473 if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
1474 (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
1475 (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
1482 * OS specific functions for handling different types of acl streams.
1484 static bacl_exit_code hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1487 struct acl_entry acls[NACLENTRIES];
1490 if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
1494 #if defined(BACL_ENOTSUP)
1497 * Not supported, just pretend there is nothing to see
1499 * If the filesystem reports it doesn't support ACLs we clear the
1500 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1501 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1502 * when we change from one filesystem to an other.
1504 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1505 pm_strcpy(jcr->acl_data->u.build->content, "");
1506 jcr->acl_data->u.build->content_length = 0;
1507 return bacl_exit_ok;
1510 pm_strcpy(jcr->acl_data->u.build->content, "");
1511 jcr->acl_data->u.build->content_length = 0;
1512 return bacl_exit_ok;
1515 _("getacl error on file \"%s\": ERR=%s\n"),
1516 jcr->last_fname, be.bstrerror());
1517 Dmsg2(100, "getacl error file=%s ERR=%s\n",
1518 jcr->last_fname, be.bstrerror());
1520 pm_strcpy(jcr->acl_data->u.build->content, "");
1521 jcr->acl_data->u.build->content_length = 0;
1522 return bacl_exit_error;
1526 pm_strcpy(jcr->acl_data->u.build->content, "");
1527 jcr->acl_data->u.build->content_length = 0;
1528 return bacl_exit_ok;
1530 if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
1531 if (acl_is_trivial(n, acls, ff_pkt->statp)) {
1533 * The ACLs simply reflect the (already known) standard permissions
1534 * So we don't send an ACL stream to the SD.
1536 pm_strcpy(jcr->acl_data->u.build->content, "");
1537 jcr->acl_data->u.build->content_length = 0;
1538 return bacl_exit_ok;
1540 if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
1541 jcr->acl_data->u.build->content_length =
1542 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
1543 actuallyfree(acl_text);
1545 return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
1550 _("acltostr error on file \"%s\": ERR=%s\n"),
1551 jcr->last_fname, be.bstrerror());
1552 Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",
1553 jcr->acl_data->u.build->content, jcr->last_fname, be.bstrerror());
1554 return bacl_exit_error;
1556 return bacl_exit_error;
1559 static bacl_exit_code hpux_parse_acl_streams(JCR *jcr,
1562 uint32_t content_length)
1565 struct acl_entry acls[NACLENTRIES];
1567 n = strtoacl(content, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
1572 _("strtoacl error on file \"%s\": ERR=%s\n"),
1573 jcr->last_fname, be.bstrerror());
1574 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
1575 content, jcr->last_fname, be.bstrerror());
1576 return bacl_exit_error;
1578 if (strtoacl(content, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
1582 _("strtoacl error on file \"%s\": ERR=%s\n"),
1583 jcr->last_fname, be.bstrerror());
1584 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
1585 content, jcr->last_fname, be.bstrerror());
1587 return bacl_exit_error;
1590 * Restore the ACLs, but don't complain about links which really should
1591 * not have attributes, and the file it is linked to may not yet be restored.
1592 * This is only true for the old acl streams as in the new implementation we
1593 * don't save acls of symlinks (which cannot have acls anyhow)
1595 if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
1600 return bacl_exit_ok;
1601 #if defined(BACL_ENOTSUP)
1604 * If the filesystem reports it doesn't support ACLs we clear the
1605 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
1606 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
1607 * when we change from one filesystem to an other.
1609 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1611 _("setacl error on file \"%s\": filesystem doesn't support ACLs\n"),
1613 Dmsg2(100, "setacl error acl=%s file=%s filesystem doesn't support ACLs\n",
1614 content, jcr->last_fname);
1615 return bacl_exit_error;
1619 _("setacl error on file \"%s\": ERR=%s\n"),
1620 jcr->last_fname, be.bstrerror());
1621 Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
1622 content, jcr->last_fname, be.bstrerror());
1623 return bacl_exit_error;
1626 return bacl_exit_ok;
1630 * For this OS setup the build and parse function pointer to the OS specific functions.
1632 static bacl_exit_code (*os_build_acl_streams)
1633 (JCR *jcr, FF_PKT *ff_pkt) =
1634 hpux_build_acl_streams;
1635 static bacl_exit_code (*os_parse_acl_streams)
1636 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1637 hpux_parse_acl_streams;
1639 #elif defined(HAVE_SUN_OS)
1640 #ifdef HAVE_SYS_ACL_H
1641 #include <sys/acl.h>
1643 #error "configure failed to detect availability of sys/acl.h"
1646 #if defined(HAVE_EXTENDED_ACL)
1648 * We define some internals of the Solaris acl libs here as those
1649 * are not exposed yet. Probably because they want us to see the
1650 * acls as opague data. But as we need to support different platforms
1651 * and versions of Solaris we need to expose some data to be able
1652 * to determine the type of acl used to stuff it into the correct
1653 * data stream. I know this is far from portable, but maybe the
1654 * proper interface is exposed later on and we can get ride of
1655 * this kludge. Newer versions of Solaris include sys/acl_impl.h
1656 * which has implementation details of acls, if thats included we
1657 * don't have to define it ourself.
1659 #if !defined(_SYS_ACL_IMPL_H)
1660 typedef enum acl_type {
1667 * Two external references to functions in the libsec library function not in current include files.
1670 int acl_type(acl_t *);
1671 char *acl_strerror(int);
1675 * Define the supported ACL streams for this OS
1677 static int os_access_acl_streams[2] = {
1678 STREAM_ACL_SOLARIS_ACLENT,
1679 STREAM_ACL_SOLARIS_ACE
1681 static int os_default_acl_streams[1] = {
1686 * As the new libsec interface with acl_totext and acl_fromtext also handles
1687 * the old format from acltotext we can use the new functions even
1688 * for acls retrieved and stored in the database with older fd versions. If the
1689 * new interface is not defined (Solaris 9 and older we fall back to the old code)
1691 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1693 int acl_enabled, flags;
1696 bacl_exit_code stream_status = bacl_exit_error;
1699 * See if filesystem supports acls.
1701 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1702 switch (acl_enabled) {
1705 * If the filesystem reports it doesn't support ACLs we clear the
1706 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1707 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1708 * when we change from one filesystem to an other.
1710 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1711 pm_strcpy(jcr->acl_data->u.build->content, "");
1712 jcr->acl_data->u.build->content_length = 0;
1713 return bacl_exit_ok;
1719 return bacl_exit_ok;
1722 _("pathconf error on file \"%s\": ERR=%s\n"),
1723 jcr->last_fname, be.bstrerror());
1724 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
1725 jcr->last_fname, be.bstrerror());
1726 return bacl_exit_error;
1734 * Get ACL info: don't bother allocating space if there is only a trivial ACL.
1736 if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
1741 return bacl_exit_ok;
1744 _("acl_get error on file \"%s\": ERR=%s\n"),
1745 jcr->last_fname, acl_strerror(errno));
1746 Dmsg2(100, "acl_get error file=%s ERR=%s\n",
1747 jcr->last_fname, acl_strerror(errno));
1748 return bacl_exit_error;
1754 * The ACLs simply reflect the (already known) standard permissions
1755 * So we don't send an ACL stream to the SD.
1757 pm_strcpy(jcr->acl_data->u.build->content, "");
1758 jcr->acl_data->u.build->content_length = 0;
1759 return bacl_exit_ok;
1762 #if defined(ACL_SID_FMT)
1764 * New format flag added in newer Solaris versions.
1766 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
1768 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
1769 #endif /* ACL_SID_FMT */
1771 if ((acl_text = acl_totext(aclp, flags)) != NULL) {
1772 jcr->acl_data->u.build->content_length =
1773 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
1774 actuallyfree(acl_text);
1776 switch (acl_type(aclp)) {
1778 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1781 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE);
1789 return stream_status;
1792 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr,
1795 uint32_t content_length)
1798 int acl_enabled, error;
1801 case STREAM_UNIX_ACCESS_ACL:
1802 case STREAM_ACL_SOLARIS_ACLENT:
1803 case STREAM_ACL_SOLARIS_ACE:
1805 * First make sure the filesystem supports acls.
1807 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1808 switch (acl_enabled) {
1811 * If the filesystem reports it doesn't support ACLs we clear the
1812 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
1813 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
1814 * when we change from one filesystem to an other.
1816 jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
1818 _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
1820 return bacl_exit_error;
1826 return bacl_exit_ok;
1829 _("pathconf error on file \"%s\": ERR=%s\n"),
1830 jcr->last_fname, be.bstrerror());
1831 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1832 content, jcr->last_fname, be.bstrerror());
1833 return bacl_exit_error;
1838 * On a filesystem with ACL support make sure this particular ACL type can be restored.
1841 case STREAM_ACL_SOLARIS_ACLENT:
1843 * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
1845 if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
1847 _("Trying to restore POSIX acl on file \"%s\" on filesystem without aclent acl support\n"),
1849 return bacl_exit_error;
1852 case STREAM_ACL_SOLARIS_ACE:
1854 * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
1856 if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
1858 _("Trying to restore NFSv4 acl on file \"%s\" on filesystem without ace acl support\n"),
1860 return bacl_exit_error;
1865 * Stream id which doesn't describe the type of acl which is encoded.
1872 if ((error = acl_fromtext(content, &aclp)) != 0) {
1874 _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1875 jcr->last_fname, acl_strerror(error));
1876 Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",
1877 content, jcr->last_fname, acl_strerror(error));
1878 return bacl_exit_error;
1882 * Validate that the conversion gave us the correct acl type.
1885 case STREAM_ACL_SOLARIS_ACLENT:
1886 if (acl_type(aclp) != ACLENT_T) {
1888 _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1890 return bacl_exit_error;
1893 case STREAM_ACL_SOLARIS_ACE:
1894 if (acl_type(aclp) != ACE_T) {
1896 _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1898 return bacl_exit_error;
1903 * Stream id which doesn't describe the type of acl which is encoded.
1909 * Restore the ACLs, but don't complain about links which really should
1910 * not have attributes, and the file it is linked to may not yet be restored.
1911 * This is only true for the old acl streams as in the new implementation we
1912 * don't save acls of symlinks (which cannot have acls anyhow)
1914 if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1918 return bacl_exit_ok;
1921 _("acl_set error on file \"%s\": ERR=%s\n"),
1922 jcr->last_fname, acl_strerror(error));
1923 Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",
1924 content, jcr->last_fname, acl_strerror(error));
1926 return bacl_exit_error;
1931 return bacl_exit_ok;
1933 return bacl_exit_error;
1934 } /* end switch (stream) */
1937 #else /* HAVE_EXTENDED_ACL */
1940 * Define the supported ACL streams for this OS
1942 static int os_access_acl_streams[1] = {
1943 STREAM_ACL_SOLARIS_ACLENT
1945 static int os_default_acl_streams[1] = {
1950 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1951 * There is no need to store those acls as we already store the stat bits too.
1953 static bool acl_is_trivial(int count, aclent_t *entries)
1958 for (n = 0; n < count; n++) {
1961 if (!(ace->a_type == USER_OBJ ||
1962 ace->a_type == GROUP_OBJ ||
1963 ace->a_type == OTHER_OBJ ||
1964 ace->a_type == CLASS_OBJ))
1971 * OS specific functions for handling different types of acl streams.
1973 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1979 n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1980 if (n < MIN_ACL_ENTRIES)
1981 return bacl_exit_error;
1983 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1984 if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1985 if (acl_is_trivial(n, acls)) {
1987 * The ACLs simply reflect the (already known) standard permissions
1988 * So we don't send an ACL stream to the SD.
1991 pm_strcpy(jcr->acl_data->u.build->content, "");
1992 jcr->acl_data->u.build->content_length = 0;
1993 return bacl_exit_ok;
1996 if ((acl_text = acltotext(acls, n)) != NULL) {
1997 jcr->acl_data->u.build->content_length =
1998 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
1999 actuallyfree(acl_text);
2001 return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
2006 _("acltotext error on file \"%s\": ERR=%s\n"),
2007 jcr->last_fname, be.bstrerror());
2008 Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",
2009 jcr->acl_data->u.build->content, jcr->last_fname, be.bstrerror());
2013 return bacl_exit_error;
2016 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr,
2019 uint32_t content_length)
2024 acls = aclfromtext(content, &n);
2029 _("aclfromtext error on file \"%s\": ERR=%s\n"),
2030 jcr->last_fname, be.bstrerror());
2031 Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",
2032 content, jcr->last_fname, be.bstrerror());
2033 return bacl_exit_error;
2037 * Restore the ACLs, but don't complain about links which really should
2038 * not have attributes, and the file it is linked to may not yet be restored.
2040 if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
2046 return bacl_exit_ok;
2049 _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
2050 jcr->last_fname, be.bstrerror());
2051 Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
2052 content, jcr->last_fname, be.bstrerror());
2054 return bacl_exit_error;
2058 return bacl_exit_ok;
2060 #endif /* HAVE_EXTENDED_ACL */
2063 * For this OS setup the build and parse function pointer to the OS specific functions.
2065 static bacl_exit_code (*os_build_acl_streams)
2066 (JCR *jcr, FF_PKT *ff_pkt) =
2067 solaris_build_acl_streams;
2068 static bacl_exit_code (*os_parse_acl_streams)
2069 (JCR *jcr, int stream, char *content, uint32_t content_length) =
2070 solaris_parse_acl_streams;
2072 #endif /* HAVE_SUN_OS */
2073 #endif /* HAVE_ACL */
2076 * Entry points when compiled with support for ACLs on a supported platform.
2080 * Read and send an ACL for the last encountered file.
2082 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
2085 * See if we are changing from one device to an other.
2086 * We save the current device we are restoring to and compare
2087 * it with the current st_dev in the last stat performed on
2088 * the file we are currently storing.
2090 if (jcr->acl_data->current_dev != ff_pkt->statp.st_dev) {
2092 * Reset the acl save flags.
2094 jcr->acl_data->flags = 0;
2096 jcr->acl_data->flags |= BACL_FLAG_SAVE_NATIVE;
2099 * Save that we started scanning a new filesystem.
2101 jcr->acl_data->current_dev = ff_pkt->statp.st_dev;
2104 #if defined(HAVE_ACL)
2106 * See if the BACL_FLAG_SAVE_NATIVE flag is set which lets us know if we should
2109 if (jcr->acl_data->flags & BACL_FLAG_SAVE_NATIVE) {
2111 * Call the appropriate function.
2113 if (os_build_acl_streams) {
2114 return os_build_acl_streams(jcr, ff_pkt);
2117 return bacl_exit_ok;
2120 return bacl_exit_error;
2123 bacl_exit_code parse_acl_streams(JCR *jcr,
2126 uint32_t content_length)
2133 * See if we are changing from one device to an other.
2134 * We save the current device we are restoring to and compare
2135 * it with the current st_dev in the last stat performed on
2136 * the file we are currently restoring.
2138 ret = lstat(jcr->last_fname, &st);
2145 return bacl_exit_ok;
2148 _("Unable to stat file \"%s\": ERR=%s\n"),
2149 jcr->last_fname, be.bstrerror());
2150 Dmsg2(100, "Unable to stat file \"%s\": ERR=%s\n",
2151 jcr->last_fname, be.bstrerror());
2152 return bacl_exit_error;
2159 if (jcr->acl_data->current_dev != st.st_dev) {
2161 * Reset the acl save flags.
2163 jcr->acl_data->flags = 0;
2164 jcr->acl_data->flags |= BACL_FLAG_RESTORE_NATIVE;
2167 * Save that we started restoring to a new filesystem.
2169 jcr->acl_data->current_dev = st.st_dev;
2173 #if defined(HAVE_ACL)
2174 case STREAM_UNIX_ACCESS_ACL:
2175 case STREAM_UNIX_DEFAULT_ACL:
2177 * Handle legacy ACL streams.
2179 if ((jcr->acl_data->flags & BACL_FLAG_RESTORE_NATIVE) && os_parse_acl_streams) {
2180 return os_parse_acl_streams(jcr, stream, content, content_length);
2183 * Increment error count but don't log an error again for the same filesystem.
2185 jcr->acl_data->u.parse->nr_errors++;
2186 return bacl_exit_ok;
2190 if ((jcr->acl_data->flags & BACL_FLAG_RESTORE_NATIVE) && os_parse_acl_streams) {
2192 * Walk the os_access_acl_streams array with the supported Access ACL streams for this OS.
2194 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
2195 if (os_access_acl_streams[cnt] == stream) {
2196 return os_parse_acl_streams(jcr, stream, content, content_length);
2200 * Walk the os_default_acl_streams array with the supported Default ACL streams for this OS.
2202 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
2203 if (os_default_acl_streams[cnt] == stream) {
2204 return os_parse_acl_streams(jcr, stream, content, content_length);
2209 * Increment error count but don't log an error again for the same filesystem.
2211 jcr->acl_data->u.parse->nr_errors++;
2212 return bacl_exit_ok;
2220 Qmsg2(jcr, M_WARNING, 0,
2221 _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
2222 jcr->last_fname, stream);
2223 return bacl_exit_error;