2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
5 Copyright (C) 2004-2015 Free Software Foundation Europe e.V.
7 The original author of Bacula is Kern Sibbald, with contributions
8 from many others, a complete list can be found in the file AUTHORS.
10 You may use this file and others of this release according to the
11 license defined in the LICENSE file, which includes the Affero General
12 Public License, v3.0 ("AGPLv3") and some additional permissions and
13 terms pursuant to its AGPLv3 Section 7.
15 This notice must be preserved when any source code is
16 conveyed and/or propagated.
18 Bacula(R) is a registered trademark of Kern Sibbald.
21 * Functions to handle ACLs for bacula.
23 * Currently we support the following OSes:
24 * - AIX (pre-5.3 and post 5.3 acls, acl_get and aclx_get interface)
26 * - FreeBSD (POSIX and NFSv4/ZFS acls)
31 * - Solaris (POSIX and NFSv4/ZFS acls)
34 * Next to OS specific acls we support AFS acls using the pioctl interface.
36 * We handle two different types of ACLs: access and default ACLS.
37 * On most systems that support default ACLs they only apply to directories.
39 * On some systems (eg. linux and FreeBSD) we must obtain the two ACLs
40 * independently, while others (eg. Solaris) provide both in one call.
42 * The Filed saves ACLs in their native format and uses different streams
43 * for all different platforms. Currently we only allow ACLs to be restored
44 * which were saved in the native format of the platform they are extracted
45 * on. Later on we might add conversion functions for mapping from one
46 * platform to an other or allow restores of systems that use the same
49 * Its also interesting to see what the exact format of acl text is on
50 * certain platforms and if they use they same encoding we might allow
51 * different platform streams to be decoded on an other similar platform.
53 * Original written by Preben 'Peppe' Guldberg, December 2004
60 #if !defined(HAVE_ACL) && !defined(HAVE_AFS_ACL)
62 * Entry points when compiled without support for ACLs or on an unsupported platform.
64 bool backup_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
66 Jmsg(jcr, M_FATAL, 0, "ACL backup requested but not configured in Bacula.\n");
70 bacl_rtn_code restore_acl_streams(JCR *jcr,
73 uint32_t content_length)
75 Jmsg(jcr, M_FATAL, 0, "ACL backup requested but not configured in Bacula.\n");
76 return bacl_rtn_fatal;
80 * Send an ACL stream to the SD.
82 static bacl_rtn_code send_acl_stream(JCR *jcr, int stream)
84 BSOCK *sd = jcr->store_bsock;
86 #ifdef FD_NO_SEND_TEST
93 if (jcr->acl_ctx->content_length <= 0) {
100 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
101 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
103 return bacl_rtn_fatal;
107 * Send the buffer to the storage deamon
109 Dmsg1(400, "Backing up ACL <%s>\n", jcr->acl_ctx->content);
111 sd->msg = jcr->acl_ctx->content;
112 sd->msglen = jcr->acl_ctx->content_length + 1;
116 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
118 return bacl_rtn_fatal;
121 jcr->JobBytes += sd->msglen;
123 if (!sd->signal(BNET_EOD)) {
124 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
126 return bacl_rtn_fatal;
129 Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
134 * First the native ACLs.
136 #if defined(HAVE_ACL)
137 #if defined(HAVE_AIX_OS)
139 #if defined(HAVE_EXTENDED_ACL)
141 #include <sys/access.h>
144 static bool acl_is_trivial(struct acl *acl)
146 return (acl_last(acl) != acl->acl_ext ? false : true);
149 static bool acl_nfs4_is_trivial(nfs4_acl_int_t *acl)
152 int count = acl->aclEntryN;
155 for (i = 0; i < count; i++) {
156 ace = &acl->aclEntry[i];
157 if (!((ace->flags & ACE4_ID_SPECIAL) != 0 &&
158 (ace->aceWho.special_whoid == ACE4_WHO_OWNER ||
159 ace->aceWho.special_whoid == ACE4_WHO_GROUP ||
160 ace->aceWho.special_whoid == ACE4_WHO_EVERYONE) &&
161 ace->aceType == ACE4_ACCESS_ALLOWED_ACE_TYPE &&
162 ace->aceFlags == 0 &&
163 (ace->aceMask & ~(ACE4_READ_DATA |
164 ACE4_LIST_DIRECTORY |
167 ACE4_EXECUTE)) == 0)) {
175 * Define the supported ACL streams for this OS
177 static int os_access_acl_streams[3] = {
182 static int os_default_acl_streams[1] = {
186 static bacl_rtn_code aix_backup_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
190 size_t aclsize, acltxtsize;
191 bacl_rtn_code retval = bacl_rtn_error;
192 POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
195 * First see how big the buffers should be.
197 memset(&type, 0, sizeof(acl_type_t));
199 if (aclx_get(jcr->last_fname, GET_ACLINFO_ONLY, &type, NULL, &aclsize, &mode) < 0) {
201 if (errno == ENOENT) {
202 retval = bacl_rtn_ok;
203 } else if (errno == ENOSYS) {
205 * If the filesystem reports it doesn't support ACLs we clear the
206 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
207 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
208 * when we change from one filesystem to an other.
210 jcr->acl_ctx->flags &= ~BACL_FLAG_SAVE_NATIVE;
211 retval = bacl_rtn_ok;
213 Mmsg2(jcr->errmsg, _("aclx_get error on file \"%s\": ERR=%s\n"),
214 jcr->last_fname, be.bstrerror());
215 Dmsg1(100, "%s", jcr->errmsg);
221 * Make sure the buffers are big enough.
223 aclbuf = check_pool_memory_size(aclbuf, aclsize + 1);
226 * Retrieve the ACL info.
228 if (aclx_get(jcr->last_fname, 0, &type, aclbuf, &aclsize, &mode) < 0) {
230 if (errno == ENOENT) {
231 retval = bacl_rtn_ok;
233 Mmsg2(jcr->errmsg, _("aclx_get error on file \"%s\": ERR=%s\n"),
234 jcr->last_fname, be.bstrerror());
235 Dmsg1(100, "%s", jcr->errmsg);
241 * See if the acl is non trivial.
245 if (acl_is_trivial((struct acl *)aclbuf)) {
246 retval = bacl_rtn_ok;
251 if (acl_nfs4_is_trivial((nfs4_acl_int_t *)aclbuf)) {
252 retval = bacl_rtn_ok;
257 Mmsg2(jcr->errmsg, _("Unknown acl type encountered on file \"%s\": %ld\n"),
258 jcr->last_fname, type.u64);
259 Dmsg1(100, "%s", jcr->errmsg);
264 * We have a non-trivial acl lets convert it into some ASCII form.
266 acltxtsize = sizeof_pool_memory(jcr->acl_ctx->content);
267 if (aclx_printStr(jcr->acl_ctx->content, &acltxtsize, aclbuf,
268 aclsize, type, jcr->last_fname, 0) < 0) {
269 if ((errno == ENOSPC) {
271 * Our buffer is not big enough, acltxtsize should be updated with the value
272 * the aclx_printStr really need. So we increase the buffer and try again.
274 jcr->acl_ctx->content = check_pool_memory_size(jcr->acl_ctx->content, acltxtsize + 1);
275 if (aclx_printStr(jcr->acl_ctx->content, &acltxtsize, aclbuf,
276 aclsize, type, jcr->last_fname, 0) < 0) {
277 Mmsg1(jcr->errmsg, _("Failed to convert acl into text on file \"%s\"\n"),
279 Dmsg1(100, "%s", jcr->errmsg);
283 Mmsg1(jcr->errmsg, _("Failed to convert acl into text on file \"%s\"\n"),
285 Dmsg1(100, "%s", jcr->errmsg);
290 jcr->acl_ctx->content_length = strlen(jcr->acl_ctx->content) + 1;
293 retval = send_acl_stream(jcr, STREAM_ACL_AIX_AIXC);
296 retval = send_acl_stream(jcr, STREAM_ACL_AIX_NFS4);
301 free_pool_memory(aclbuf);
307 * See if a specific type of ACLs are supported on the filesystem
308 * the file is located on.
310 static inline bool aix_query_acl_support(JCR *jcr,
312 acl_type_t *pacl_type_info)
315 acl_types_list_t acl_type_list;
316 size_t acl_type_list_len = sizeof(acl_types_list_t);
318 memset(&acl_type_list, 0, sizeof(acl_type_list));
319 if (aclx_gettypes(jcr->last_fname, &acl_type_list, &acl_type_list_len)) {
323 for (i = 0; i < acl_type_list.num_entries; i++) {
324 if (acl_type_list.entries[i].u64 == aclType) {
325 memcpy(pacl_type_info, acl_type_list.entries + i, sizeof(acl_type_t));
332 static bacl_rtn_code aix_restore_acl_streams(JCR *jcr,
335 uint32_t content_length)
340 bacl_rtn_code retval = bacl_rtn_error;
341 POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
344 case STREAM_ACL_AIX_TEXT:
346 * Handle the old stream using the old system call for now.
348 if (acl_put(jcr->last_fname, content, 0) != 0) {
349 retval = bacl_rtn_error;
352 retval = bacl_rtn_ok;
354 case STREAM_ACL_AIX_AIXC:
355 if (!aix_query_acl_support(jcr, ACL_AIXC, &type)) {
357 _("Trying to restore POSIX acl on file \"%s\" on filesystem without AIXC acl support\n"),
362 case STREAM_ACL_AIX_NFS4:
363 if (!aix_query_acl_support(jcr, ACL_NFS4, &type)) {
365 _("Trying to restore NFSv4 acl on file \"%s\" on filesystem without NFS4 acl support\n"),
375 * Set the acl buffer to an initial size. For now we set it
376 * to the same size as the ASCII representation.
378 aclbuf = check_pool_memory_size(aclbuf, content_length);
379 aclsize = content_length;
380 if (aclx_scanStr(content, aclbuf, &aclsize, type) < 0) {
382 if (errno == ENOSPC) {
384 * The buffer isn't big enough. The man page doesn't say that aclsize
385 * is updated to the needed size as what is done with aclx_printStr.
386 * So for now we try to increase the buffer a maximum of 3 times
387 * and retry the conversion.
389 for (cnt = 0; cnt < 3; cnt++) {
390 aclsize = 2 * aclsize;
391 aclbuf = check_pool_memory_size(aclbuf, aclsize);
393 if (aclx_scanStr(content, aclbuf, &aclsize, type) == 0) {
398 * See why we failed this time, ENOSPC retry if max retries not met,
401 if (errno == ENOSPC && cnt < 3) {
404 Mmsg2(jcr->errmsg, _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
405 jcr->last_fname, be.bstrerror(errno));
406 Dmsg1(100, "%s", jcr->errmsg);
410 Mmsg2(jcr->errmsg, _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
411 jcr->last_fname, be.bstrerror());
412 Dmsg1(100, "%s", jcr->errmsg);
417 if (aclx_put(jcr->last_fname, SET_ACL, type, aclbuf, aclsize, 0) < 0) {
419 if (errno == ENOENT) {
420 retval = bacl_rtn_ok;
423 * If the filesystem reports it doesn't support ACLs we clear the
424 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
425 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
426 * when we change from one filesystem to an other.
428 jcr->acl_ctx->flags &= ~BACL_FLAG_RESTORE_NATIVE;
430 Mmsg2(jcr->errmsg, _("aclx_put error on file \"%s\": ERR=%s\n"),
431 jcr->last_fname, be.bstrerror());
432 Dmsg1(100, "%s", jcr->errmsg);
437 retval = bacl_rtn_ok;
440 free_pool_memory(aclbuf);
444 #else /* HAVE_EXTENDED_ACL */
446 #include <sys/access.h>
449 * Define the supported ACL streams for this OS
451 static int os_access_acl_streams[1] = {
454 static int os_default_acl_streams[1] = {
458 static bacl_rtn_code aix_backup_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
462 if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
463 jcr->acl_ctx->content_length =
464 pm_strcpy(jcr->acl_ctx->content, acl_text);
465 actuallyfree(acl_text);
466 return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT);
468 return bacl_rtn_error;
471 static bacl_rtn_code aix_restore_acl_streams(JCR *jcr,
474 uint32_t content_length)
476 if (acl_put(jcr->last_fname, content, 0) != 0) {
477 return bacl_rtn_error;
481 #endif /* HAVE_EXTENDED_ACL */
484 * For this OS setup the build and parse function pointer to the OS specific functions.
486 static bacl_rtn_code (*os_backup_acl_streams)
487 (JCR *jcr, FF_PKT *ff_pkt) =
488 aix_backup_acl_streams;
489 static bacl_rtn_code (*os_restore_acl_streams)
490 (JCR *jcr, int stream, char *content, uint32_t content_length) =
491 aix_restore_acl_streams;
493 #elif defined(HAVE_DARWIN_OS) || \
494 defined(HAVE_FREEBSD_OS) || \
495 defined(HAVE_IRIX_OS) || \
496 defined(HAVE_OSF1_OS) || \
497 defined(HAVE_LINUX_OS) || \
498 defined(HAVE_HURD_OS)
500 #include <sys/types.h>
502 #ifdef HAVE_SYS_ACL_H
505 #error "configure failed to detect availability of sys/acl.h"
509 * On IRIX we can get shortened ACLs
511 #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
512 #define acl_to_text(acl,len) acl_to_short_text((acl), (len))
516 * On Linux we can get numeric and/or shorted ACLs
518 #if defined(HAVE_LINUX_OS)
519 #if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
520 #define BACL_ALTERNATE_TEXT (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
521 #elif defined(BACL_WANT_SHORT_ACLS)
522 #define BACL_ALTERNATE_TEXT TEXT_ABBREVIATE
523 #elif defined(BACL_WANT_NUMERIC_IDS)
524 #define BACL_ALTERNATE_TEXT TEXT_NUMERIC_IDS
526 #ifdef BACL_ALTERNATE_TEXT
527 #include <acl/libacl.h>
528 #define acl_to_text(acl,len) (acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
533 * On FreeBSD we can get numeric ACLs
535 #if defined(HAVE_FREEBSD_OS)
536 #if defined(BACL_WANT_NUMERIC_IDS)
537 #define BACL_ALTERNATE_TEXT ACL_TEXT_NUMERIC_IDS
539 #ifdef BACL_ALTERNATE_TEXT
540 #define acl_to_text(acl,len) (acl_to_text_np((acl), (len), BACL_ALTERNATE_TEXT))
545 * Some generic functions used by multiple OSes.
547 static acl_type_t bac_to_os_acltype(bacl_type acltype)
552 case BACL_TYPE_ACCESS:
553 ostype = ACL_TYPE_ACCESS;
555 case BACL_TYPE_DEFAULT:
556 ostype = ACL_TYPE_DEFAULT;
558 #ifdef HAVE_ACL_TYPE_NFS4
560 * FreeBSD has an additional acl type named ACL_TYPE_NFS4.
563 ostype = ACL_TYPE_NFS4;
566 #ifdef HAVE_ACL_TYPE_DEFAULT_DIR
567 case BACL_TYPE_DEFAULT_DIR:
569 * TRU64 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
571 ostype = ACL_TYPE_DEFAULT_DIR;
574 #ifdef HAVE_ACL_TYPE_EXTENDED
575 case BACL_TYPE_EXTENDED:
577 * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
579 ostype = ACL_TYPE_EXTENDED;
584 * This should never happen, as the per OS version function only tries acl
585 * types supported on a certain platform.
587 ostype = (acl_type_t)ACL_TYPE_NONE;
593 static int acl_count_entries(acl_t acl)
596 #if defined(HAVE_FREEBSD_OS) || \
597 defined(HAVE_LINUX_OS) || \
598 defined(HAVE_HURD_OS)
602 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
603 while (entry_available == 1) {
605 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
607 #elif defined(HAVE_IRIX_OS)
608 count = acl->acl_cnt;
609 #elif defined(HAVE_OSF1_OS)
610 count = acl->acl_num;
611 #elif defined(HAVE_DARWIN_OS)
615 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
616 while (entry_available == 0) {
618 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
624 #if !defined(HAVE_DARWIN_OS)
626 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
627 * There is no need to store those acls as we already store the stat bits too.
629 static bool acl_is_trivial(acl_t acl)
632 * acl is trivial if it has only the following entries:
639 #if defined(HAVE_FREEBSD_OS) || \
640 defined(HAVE_LINUX_OS) || \
641 defined(HAVE_HURD_OS)
644 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
645 while (entry_available == 1) {
647 * Get the tag type of this acl entry.
648 * If we fail to get the tagtype we call the acl non-trivial.
650 if (acl_get_tag_type(ace, &tag) < 0)
653 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
655 if (tag != ACL_USER_OBJ &&
656 tag != ACL_GROUP_OBJ &&
659 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
662 #elif defined(HAVE_IRIX_OS)
665 for (n = 0; n < acl->acl_cnt; n++) {
666 ace = &acl->acl_entry[n];
670 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
672 if (tag != ACL_USER_OBJ &&
673 tag != ACL_GROUP_OBJ &&
674 tag != ACL_OTHER_OBJ)
678 #elif defined(HAVE_OSF1_OS)
681 ace = acl->acl_first;
682 count = acl->acl_num;
685 tag = ace->entry->acl_type;
687 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
689 if (tag != ACL_USER_OBJ &&
690 tag != ACL_GROUP_OBJ &&
694 * On Tru64, perm can also contain non-standard bits such as
695 * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
697 if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
708 * Generic wrapper around acl_get_file call.
710 static bacl_rtn_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
715 bacl_rtn_code retval = bacl_rtn_ok;
717 ostype = bac_to_os_acltype(acltype);
718 acl = acl_get_file(jcr->last_fname, ostype);
721 * From observation, IRIX's acl_get_file() seems to return a
722 * non-NULL acl with a count field of -1 when a file has no ACL
723 * defined, while IRIX's acl_to_text() returns NULL when presented
726 * For all other implmentations we check if there are more then
727 * zero entries in the acl returned.
729 if (acl_count_entries(acl) <= 0) {
734 * Make sure this is not just a trivial ACL.
736 #ifndef HAVE_DARWIN_OS
737 if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
739 * The ACLs simply reflect the (already known) standard permissions
740 * So we don't send an ACL stream to the SD.
746 #if defined(HAVE_FREEBSD_OS) && defined(_PC_ACL_NFS4)
747 if (acltype == BACL_TYPE_NFS4) {
749 if (acl_is_trivial_np(acl, &trivial) == 0) {
750 /* Trivial ACLS are standard permissions. Do not send to SD. */
759 * Convert the internal acl representation into a text representation.
761 if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
762 jcr->acl_ctx->content_length =
763 pm_strcpy(jcr->acl_ctx->content, acl_text);
771 _("acl_to_text error on file \"%s\": ERR=%s\n"),
772 jcr->last_fname, be.bstrerror());
773 Dmsg1(100, "%s", jcr->errmsg);
774 retval = bacl_rtn_error;
779 * Handle errors gracefully.
784 * If the filesystem reports it doesn't support ACLs we clear the
785 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
786 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
787 * when we change from one filesystem to an other.
789 jcr->acl_ctx->flags &= ~BACL_FLAG_SAVE_NATIVE;
794 /* Some real error */
795 Mmsg2(jcr->errmsg, _("acl_get_file error on file \"%s\": ERR=%s\n"),
796 jcr->last_fname, be.bstrerror());
797 Dmsg1(100, "%s", jcr->errmsg);
798 retval = bacl_rtn_error;
807 pm_strcpy(jcr->acl_ctx->content, "");
808 jcr->acl_ctx->content_length = 0;
813 * Generic wrapper around acl_set_file call.
815 static bacl_rtn_code generic_set_acl_on_os(JCR *jcr,
818 uint32_t content_length)
824 * If we get empty default ACLs, clear ACLs now
826 ostype = bac_to_os_acltype(acltype);
827 if (ostype == ACL_TYPE_DEFAULT && strlen(content) == 0) {
828 if (acl_delete_def_file(jcr->last_fname) == 0) {
838 * If the filesystem reports it doesn't support ACLs we clear the
839 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
840 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
841 * when we change from one filesystem to an other.
843 jcr->acl_ctx->flags &= ~BACL_FLAG_RESTORE_NATIVE;
845 _("acl_delete_def_file error on file \"%s\": filesystem doesn't support ACLs\n"),
847 return bacl_rtn_error;
850 _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
851 jcr->last_fname, be.bstrerror());
852 return bacl_rtn_error;
856 acl = acl_from_text(content);
861 _("acl_from_text error on file \"%s\": ERR=%s\n"),
862 jcr->last_fname, be.bstrerror());
863 Dmsg1(100, "%s", jcr->errmsg);
864 return bacl_rtn_error;
867 #ifndef HAVE_FREEBSD_OS
869 * FreeBSD always fails acl_valid() - at least on valid input...
870 * As it does the right thing, given valid input, just ignore acl_valid().
872 if (acl_valid(acl) != 0) {
876 _("acl_valid error on file \"%s\": ERR=%s\n"),
877 jcr->last_fname, be.bstrerror());
878 Dmsg1(100, "%s", jcr->errmsg);
880 return bacl_rtn_error;
885 * Restore the ACLs, but don't complain about links which really should
886 * not have attributes, and the file it is linked to may not yet be restored.
887 * This is only true for the old acl streams as in the new implementation we
888 * don't save acls of symlinks (which cannot have acls anyhow)
890 if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
898 * If the filesystem reports it doesn't support ACLs we clear the
899 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
900 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
901 * when we change from one filesystem to an other.
903 jcr->acl_ctx->flags &= ~BACL_FLAG_RESTORE_NATIVE;
905 _("acl_set_file error on file \"%s\": filesystem doesn't support ACLs\n"),
907 Dmsg1(100, "%s", jcr->errmsg);
909 return bacl_rtn_error;
911 Mmsg2(jcr->errmsg, _("acl_set_file error on file \"%s\": ERR=%s\n"),
912 jcr->last_fname, be.bstrerror());
913 Dmsg1(100, "%s", jcr->errmsg);
915 return bacl_rtn_error;
923 * OS specific functions for handling different types of acl streams.
925 #if defined(HAVE_DARWIN_OS)
927 * Define the supported ACL streams for this OS
929 static int os_access_acl_streams[1] = {
930 STREAM_ACL_DARWIN_ACCESS
932 static int os_default_acl_streams[1] = {
936 static bacl_rtn_code darwin_backup_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
938 #if defined(HAVE_ACL_TYPE_EXTENDED)
940 * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
941 * and acl_get_file (name, ACL_TYPE_DEFAULT)
942 * always return NULL / EINVAL. There is no point in making
943 * these two useless calls. The real ACL is retrieved through
944 * acl_get_file (name, ACL_TYPE_EXTENDED).
946 * Read access ACLs for files, dirs and links
948 if (generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED) == bacl_rtn_fatal)
949 return bacl_rtn_fatal;
952 * Read access ACLs for files, dirs and links
954 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_rtn_fatal)
955 return bacl_rtn_fatal;
958 if (jcr->acl_ctx->content_length > 0) {
959 return send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL);
964 static bacl_rtn_code darwin_restore_acl_streams(JCR *jcr,
967 uint32_t content_length)
969 #if defined(HAVE_ACL_TYPE_EXTENDED)
970 return generic_set_acl_on_os(jcr, BACL_TYPE_EXTENDED, content, content_length);
972 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
977 * For this OS setup the build and parse function pointer to the OS specific functions.
979 static bacl_rtn_code (*os_backup_acl_streams)
980 (JCR *jcr, FF_PKT *ff_pkt) =
981 darwin_backup_acl_streams;
982 static bacl_rtn_code (*os_restore_acl_streams)
983 (JCR *jcr, int stream, char *content, uint32_t content_length) =
984 darwin_restore_acl_streams;
986 #elif defined(HAVE_FREEBSD_OS)
988 * Define the supported ACL streams for these OSes
990 static int os_access_acl_streams[2] = {
991 STREAM_ACL_FREEBSD_ACCESS,
992 STREAM_ACL_FREEBSD_NFS4
994 static int os_default_acl_streams[1] = {
995 STREAM_ACL_FREEBSD_DEFAULT
998 static bacl_rtn_code freebsd_backup_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1000 int acl_enabled = 0;
1001 bacl_type acltype = BACL_TYPE_NONE;
1003 #if defined(_PC_ACL_NFS4)
1005 * See if filesystem supports NFS4 acls.
1007 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
1008 if (acl_enabled < 0) {
1010 if (errno == ENOENT) {
1013 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1014 jcr->last_fname, be.bstrerror());
1015 Dmsg1(100, "%s", jcr->errmsg);
1016 return bacl_rtn_error;
1018 } else if (acl_enabled != 0) {
1019 acltype = BACL_TYPE_NFS4;
1023 if (acl_enabled == 0) {
1025 * See if filesystem supports POSIX acls.
1027 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
1028 if (acl_enabled < 0) {
1030 if (errno == ENOENT) {
1033 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1034 jcr->last_fname, be.bstrerror());
1035 Dmsg1(100, "%s", jcr->errmsg);
1036 return bacl_rtn_error;
1038 } else if (acl_enabled != 0) {
1039 acltype = BACL_TYPE_ACCESS;
1044 * If the filesystem reports it doesn't support ACLs we clear the
1045 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1046 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1047 * when we change from one filesystem to an other.
1049 if (acl_enabled == 0) {
1050 jcr->acl_ctx->flags &= ~BACL_FLAG_SAVE_NATIVE;
1051 pm_strcpy(jcr->acl_ctx->content, "");
1052 jcr->acl_ctx->content_length = 0;
1057 * Based on the supported ACLs retrieve and store them.
1060 case BACL_TYPE_NFS4:
1062 * Read NFS4 ACLs for files, dirs and links
1064 if (generic_get_acl_from_os(jcr, BACL_TYPE_NFS4) == bacl_rtn_fatal)
1065 return bacl_rtn_fatal;
1067 if (jcr->acl_ctx->content_length > 0) {
1068 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_NFS4) == bacl_rtn_fatal)
1069 return bacl_rtn_fatal;
1072 case BACL_TYPE_ACCESS:
1074 * Read access ACLs for files, dirs and links
1076 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_rtn_fatal)
1077 return bacl_rtn_fatal;
1079 if (jcr->acl_ctx->content_length > 0) {
1080 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_ACCESS) == bacl_rtn_fatal)
1081 return bacl_rtn_fatal;
1085 * Directories can have default ACLs too
1087 if (ff_pkt->type == FT_DIREND) {
1088 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_rtn_fatal)
1089 return bacl_rtn_fatal;
1090 if (jcr->acl_ctx->content_length > 0) {
1091 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_DEFAULT) == bacl_rtn_fatal)
1092 return bacl_rtn_fatal;
1103 static bacl_rtn_code freebsd_restore_acl_streams(JCR *jcr,
1106 uint32_t content_length)
1108 int acl_enabled = 0;
1109 const char *acl_type_name;
1112 * First make sure the filesystem supports acls.
1115 case STREAM_UNIX_ACCESS_ACL:
1116 case STREAM_ACL_FREEBSD_ACCESS:
1117 case STREAM_UNIX_DEFAULT_ACL:
1118 case STREAM_ACL_FREEBSD_DEFAULT:
1119 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
1120 acl_type_name = "POSIX";
1122 case STREAM_ACL_FREEBSD_NFS4:
1123 #if defined(_PC_ACL_NFS4)
1124 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
1126 acl_type_name = "NFS4";
1129 acl_type_name = "unknown";
1133 if (acl_enabled < 0) {
1135 if (errno == ENOENT) {
1138 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1139 jcr->last_fname, be.bstrerror());
1140 Dmsg1(100, "%s", jcr->errmsg);
1141 return bacl_rtn_error;
1143 } else if (acl_enabled == 0) {
1145 * If the filesystem reports it doesn't support ACLs we clear the
1146 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
1147 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
1148 * when we change from one filesystem to an other.
1150 jcr->acl_ctx->flags &= ~BACL_FLAG_SAVE_NATIVE;
1152 _("Trying to restore acl on file \"%s\" on filesystem without %s acl support\n"),
1153 jcr->last_fname, acl_type_name);
1154 return bacl_rtn_error;
1161 case STREAM_UNIX_ACCESS_ACL:
1162 case STREAM_ACL_FREEBSD_ACCESS:
1163 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1164 case STREAM_UNIX_DEFAULT_ACL:
1165 case STREAM_ACL_FREEBSD_DEFAULT:
1166 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1167 case STREAM_ACL_FREEBSD_NFS4:
1168 return generic_set_acl_on_os(jcr, BACL_TYPE_NFS4, content, content_length);
1172 return bacl_rtn_error;
1176 * For this OSes setup the build and parse function pointer to the OS specific functions.
1178 static bacl_rtn_code (*os_backup_acl_streams)
1179 (JCR *jcr, FF_PKT *ff_pkt) =
1180 freebsd_backup_acl_streams;
1181 static bacl_rtn_code (*os_restore_acl_streams)
1182 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1183 freebsd_restore_acl_streams;
1185 #elif defined(HAVE_IRIX_OS) || \
1186 defined(HAVE_LINUX_OS) || \
1187 defined(HAVE_HURD_OS)
1189 * Define the supported ACL streams for these OSes
1191 #if defined(HAVE_IRIX_OS)
1192 static int os_access_acl_streams[1] = {STREAM_ACL_IRIX_ACCESS_ACL};
1193 static int os_default_acl_streams[1] = {STREAM_ACL_IRIX_DEFAULT_ACL};
1194 #elif defined(HAVE_LINUX_OS)
1195 static int os_access_acl_streams[1] = {STREAM_ACL_LINUX_ACCESS};
1196 static int os_default_acl_streams[1] = {STREAM_ACL_LINUX_DEFAULT};
1197 #elif defined(HAVE_HURD_OS)
1198 static int os_access_acl_streams[1] = {STREAM_ACL_HURD_ACCESS};
1199 static int os_default_acl_streams[1] = {STREAM_ACL_HURD_DEFAULT};
1202 static bacl_rtn_code generic_backup_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1205 * Read access ACLs for files, dirs and links
1207 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_rtn_fatal)
1208 return bacl_rtn_fatal;
1210 if (jcr->acl_ctx->content_length > 0) {
1211 if (send_acl_stream(jcr, os_access_acl_streams[0]) == bacl_rtn_fatal)
1212 return bacl_rtn_fatal;
1216 * Directories can have default ACLs too
1218 if (ff_pkt->type == FT_DIREND) {
1219 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_rtn_fatal)
1220 return bacl_rtn_fatal;
1221 if (jcr->acl_ctx->content_length > 0) {
1222 if (send_acl_stream(jcr, os_default_acl_streams[0]) == bacl_rtn_fatal)
1223 return bacl_rtn_fatal;
1229 static bacl_rtn_code generic_restore_acl_streams(JCR *jcr,
1232 uint32_t content_length)
1237 case STREAM_UNIX_ACCESS_ACL:
1238 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1239 case STREAM_UNIX_DEFAULT_ACL:
1240 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1243 * See what type of acl it is.
1245 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1246 if (os_access_acl_streams[cnt] == stream) {
1247 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1250 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1251 if (os_default_acl_streams[cnt] == stream) {
1252 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1257 return bacl_rtn_error;
1261 * For this OSes setup the build and parse function pointer to the OS specific functions.
1263 static bacl_rtn_code (*os_backup_acl_streams)
1264 (JCR *jcr, FF_PKT *ff_pkt) =
1265 generic_backup_acl_streams;
1266 static bacl_rtn_code (*os_restore_acl_streams)
1267 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1268 generic_restore_acl_streams;
1270 #elif defined(HAVE_OSF1_OS)
1273 * Define the supported ACL streams for this OS
1275 static int os_access_acl_streams[1] = {
1276 STREAM_ACL_TRU64_ACCESS
1278 static int os_default_acl_streams[2] = {
1279 STREAM_ACL_TRU64_DEFAULT,
1280 STREAM_ACL_TRU64_DEFAULT_DIR
1283 static bacl_rtn_code tru64_backup_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1286 * Read access ACLs for files, dirs and links
1288 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_rtn_fatal) {
1289 return bacl_rtn_error;
1290 if (jcr->acl_ctx->content_length > 0) {
1291 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL))
1292 return bacl_rtn_error;
1295 * Directories can have default ACLs too
1297 if (ff_pkt->type == FT_DIREND) {
1298 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_rtn_fatal) {
1299 return bacl_rtn_error;
1300 if (jcr->acl_ctx->content_length > 0) {
1301 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL))
1302 return bacl_rtn_error;
1305 * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
1306 * This is an inherited acl for all subdirs.
1307 * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
1308 * Section 21.5 Default ACLs
1310 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR) == bacl_rtn_fatal) {
1311 return bacl_rtn_error;
1312 if (jcr->acl_ctx->content_length > 0) {
1313 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL))
1314 return bacl_rtn_error;
1320 static bacl_rtn_code tru64_restore_acl_streams(JCR *jcr,
1323 uint32_t content_length)
1326 case STREAM_UNIX_ACCESS_ACL:
1327 case STREAM_ACL_TRU64_ACCESS_ACL:
1328 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1329 case STREAM_UNIX_DEFAULT_ACL:
1330 case STREAM_ACL_TRU64_DEFAULT_ACL:
1331 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1332 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
1333 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR, content, content_length);
1337 * For this OS setup the build and parse function pointer to the OS specific functions.
1339 static bacl_rtn_code (*os_backup_acl_streams)
1340 (JCR *jcr, FF_PKT *ff_pkt) =
1341 tru64_backup_acl_streams;
1342 static bacl_rtn_code (*os_restore_acl_streams)
1343 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1344 tru64_restore_acl_streams;
1348 #elif defined(HAVE_HPUX_OS)
1349 #ifdef HAVE_SYS_ACL_H
1350 #include <sys/acl.h>
1352 #error "configure failed to detect availability of sys/acl.h"
1358 * Define the supported ACL streams for this OS
1360 static int os_access_acl_streams[1] = {
1361 STREAM_ACL_HPUX_ACL_ENTRY
1363 static int os_default_acl_streams[1] = {
1368 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1369 * There is no need to store those acls as we already store the stat bits too.
1371 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
1374 struct acl_entry ace
1376 for (n = 0; n < count; n++) {
1379 * See if this acl just is the stat mode in acl form.
1381 if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
1382 (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
1383 (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
1390 * OS specific functions for handling different types of acl streams.
1392 static bacl_rtn_code hpux_backup_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1395 struct acl_entry acls[NACLENTRIES];
1398 if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
1403 * Not supported, just pretend there is nothing to see
1405 * If the filesystem reports it doesn't support ACLs we clear the
1406 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1407 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1408 * when we change from one filesystem to an other.
1410 jcr->acl_ctx->flags &= ~BACL_FLAG_SAVE_NATIVE;
1411 pm_strcpy(jcr->acl_ctx->content, "");
1412 jcr->acl_ctx->content_length = 0;
1415 pm_strcpy(jcr->acl_ctx->content, "");
1416 jcr->acl_ctx->content_length = 0;
1419 Mmsg2(jcr->errmsg, _("getacl error on file \"%s\": ERR=%s\n"),
1420 jcr->last_fname, be.bstrerror());
1421 Dmsg1(100, "%s", jcr->errmsg);
1422 pm_strcpy(jcr->acl_ctx->content, "");
1423 jcr->acl_ctx->content_length = 0;
1424 return bacl_rtn_error;
1428 pm_strcpy(jcr->acl_ctx->content, "");
1429 jcr->acl_ctx->content_length = 0;
1432 if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
1433 if (acl_is_trivial(n, acls, ff_pkt->statp)) {
1435 * The ACLs simply reflect the (already known) standard permissions
1436 * So we don't send an ACL stream to the SD.
1438 pm_strcpy(jcr->acl_ctx->content, "");
1439 jcr->acl_ctx->content_length = 0;
1442 if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
1443 jcr->acl_ctx->content_length =
1444 pm_strcpy(jcr->acl_ctx->content, acl_text);
1445 actuallyfree(acl_text);
1447 return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
1451 Mmsg2(jcr->errmsg, _("acltostr error on file \"%s\": ERR=%s\n"),
1452 jcr->last_fname, be.bstrerror());
1453 Dmsg1(100, "%s", jcr->errmsg);
1454 return bacl_rtn_error;
1456 return bacl_rtn_error;
1459 static bacl_rtn_code hpux_restore_acl_streams(JCR *jcr,
1462 uint32_t content_length)
1465 struct acl_entry acls[NACLENTRIES];
1467 n = strtoacl(content, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
1470 Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
1471 jcr->last_fname, be.bstrerror());
1472 Dmsg1(100, "%s", jcr->errmsg);
1473 return bacl_rtn_error;
1475 if (strtoacl(content, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
1477 Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
1478 jcr->last_fname, be.bstrerror());
1479 Dmsg1(100, "%s", jcr->errmsg);
1480 return bacl_rtn_error;
1483 * Restore the ACLs, but don't complain about links which really should
1484 * not have attributes, and the file it is linked to may not yet be restored.
1485 * This is only true for the old acl streams as in the new implementation we
1486 * don't save acls of symlinks (which cannot have acls anyhow)
1488 if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
1496 * If the filesystem reports it doesn't support ACLs we clear the
1497 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
1498 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
1499 * when we change from one filesystem to an other.
1501 jcr->acl_ctx->flags &= ~BACL_FLAG_SAVE_NATIVE;
1503 _("setacl error on file \"%s\": filesystem doesn't support ACLs\n"),
1505 Dmsg1(100, "%s", jcr->errmsg);
1506 return bacl_rtn_error;
1508 Mmsg2(jcr->errmsg, _("setacl error on file \"%s\": ERR=%s\n"),
1509 jcr->last_fname, be.bstrerror());
1510 Dmsg1(100, "%s", jcr->errmsg);
1511 return bacl_rtn_error;
1518 * For this OS setup the build and parse function pointer to the OS specific functions.
1520 static bacl_rtn_code (*os_backup_acl_streams)
1521 (JCR *jcr, FF_PKT *ff_pkt) =
1522 hpux_backup_acl_streams;
1524 static bacl_rtn_code (*os_restore_acl_streams)
1525 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1526 hpux_restore_acl_streams;
1528 #elif defined(HAVE_SUN_OS)
1529 #ifdef HAVE_SYS_ACL_H
1530 #include <sys/acl.h>
1532 #error "configure failed to detect availability of sys/acl.h"
1535 #if defined(HAVE_EXTENDED_ACL)
1537 * We define some internals of the Solaris acl libs here as those
1538 * are not exposed yet. Probably because they want us to see the
1539 * acls as opague data. But as we need to support different platforms
1540 * and versions of Solaris we need to expose some data to be able
1541 * to determine the type of acl used to stuff it into the correct
1542 * data stream. I know this is far from portable, but maybe the
1543 * proper interface is exposed later on and we can get ride of
1544 * this kludge. Newer versions of Solaris include sys/acl_impl.h
1545 * which has implementation details of acls, if thats included we
1546 * don't have to define it ourself.
1548 #if !defined(_SYS_ACL_IMPL_H)
1549 typedef enum acl_type {
1556 * Two external references to functions in the libsec library function not in current include files.
1559 int acl_type(acl_t *);
1560 char *acl_strerror(int);
1564 * Define the supported ACL streams for this OS
1566 static int os_access_acl_streams[2] = {
1567 STREAM_ACL_SOLARIS_POSIX,
1568 STREAM_ACL_SOLARIS_NFS4
1570 static int os_default_acl_streams[1] = {
1575 * As the new libsec interface with acl_totext and acl_fromtext also handles
1576 * the old format from acltotext we can use the new functions even
1577 * for acls retrieved and stored in the database with older fd versions. If the
1578 * new interface is not defined (Solaris 9 and older we fall back to the old code)
1580 static bacl_rtn_code solaris_backup_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1582 int acl_enabled, flags;
1585 bacl_rtn_code stream_status = bacl_rtn_error;
1588 * See if filesystem supports acls.
1590 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1591 if (acl_enabled == 0) {
1593 * If the filesystem reports it doesn't support ACLs we clear the
1594 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1595 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1596 * when we change from one filesystem to an other.
1598 jcr->acl_ctx->flags &= ~BACL_FLAG_SAVE_NATIVE;
1599 pm_strcpy(jcr->acl_ctx->content, "");
1600 jcr->acl_ctx->content_length = 0;
1603 if (acl_enabled < 0) {
1605 if (errno == ENOENT) {
1608 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1609 jcr->last_fname, be.bstrerror());
1610 Dmsg1(100, "%s", jcr->errmsg);
1611 return bacl_rtn_error;
1616 * Get ACL info: don't bother allocating space if there is only a trivial ACL.
1618 if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
1620 if (errno == ENOENT) {
1623 Mmsg2(jcr->errmsg, _("acl_get error on file \"%s\": ERR=%s\n"),
1624 jcr->last_fname, acl_strerror(errno));
1625 Dmsg1(100, "%s", jcr->errmsg);
1626 return bacl_rtn_error;
1632 * The ACLs simply reflect the (already known) standard permissions
1633 * So we don't send an ACL stream to the SD.
1635 pm_strcpy(jcr->acl_ctx->content, "");
1636 jcr->acl_ctx->content_length = 0;
1640 #if defined(ACL_SID_FMT)
1642 * New format flag added in newer Solaris versions.
1644 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
1646 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
1647 #endif /* ACL_SID_FMT */
1649 if ((acl_text = acl_totext(aclp, flags)) != NULL) {
1650 jcr->acl_ctx->content_length =
1651 pm_strcpy(jcr->acl_ctx->content, acl_text);
1652 actuallyfree(acl_text);
1654 switch (acl_type(aclp)) {
1656 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_POSIX);
1659 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_NFS4);
1667 return stream_status;
1670 static bacl_rtn_code solaris_restore_acl_streams(JCR *jcr, int stream, char *content,
1671 uint32_t content_length)
1674 int acl_enabled, error;
1676 if (stream != STREAM_UNIX_ACCESS_ACL || stream != STREAM_ACL_SOLARIS_POSIX ||
1677 stream != STREAM_ACL_SOLARIS_NFS4) {
1678 return bacl_rtn_error;
1682 * First make sure the filesystem supports acls.
1684 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1685 if (acl_enabled == 0) {
1687 * If the filesystem reports it doesn't support ACLs we clear the
1688 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
1689 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
1690 * when we change from one filesystem to an other.
1692 jcr->acl_ctx->flags &= ~BACL_FLAG_RESTORE_NATIVE;
1694 _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
1696 return bacl_rtn_error;
1697 } else if (acl_enabled < 0) {
1699 if (errno == ENOENT) {
1702 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1703 jcr->last_fname, be.bstrerror());
1704 Dmsg1(100, "%s", jcr->errmsg);
1705 return bacl_rtn_error;
1709 * On a filesystem with ACL support make sure this particular ACL type can be restored.
1712 case STREAM_ACL_SOLARIS_POSIX:
1714 * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
1716 if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
1718 _("Trying to restore POSIX acl on file \"%s\" on filesystem without aclent acl support\n"),
1720 return bacl_rtn_error;
1723 case STREAM_ACL_SOLARIS_NFS4:
1725 * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
1727 if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
1729 _("Trying to restore NFSv4 acl on file \"%s\" on filesystem without ace acl support\n"),
1731 return bacl_rtn_error;
1736 * Stream id which doesn't describe the type of acl which is encoded.
1741 if ((error = acl_fromtext(content, &aclp)) != 0) {
1743 _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1744 jcr->last_fname, acl_strerror(error));
1745 Dmsg1(100, "%s", jcr->errmsg);
1746 return bacl_rtn_error;
1750 * Validate that the conversion gave us the correct acl type.
1753 case STREAM_ACL_SOLARIS_POSIX:
1754 if (acl_type(aclp) != ACLENT_T) {
1756 _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1758 return bacl_rtn_error;
1761 case STREAM_ACL_SOLARIS_NFS4:
1762 if (acl_type(aclp) != ACE_T) {
1764 _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1766 return bacl_rtn_error;
1771 * Stream id which doesn't describe the type of acl which is encoded.
1777 * Restore the ACLs, but don't complain about links which really should
1778 * not have attributes, and the file it is linked to may not yet be restored.
1779 * This is only true for the old acl streams as in the new implementation we
1780 * don't save acls of symlinks (which cannot have acls anyhow)
1782 if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1783 if (errno == ENOENT) {
1787 Mmsg2(jcr->errmsg, _("acl_set error on file \"%s\": ERR=%s\n"),
1788 jcr->last_fname, acl_strerror(error));
1789 Dmsg1(100, "%s", jcr->errmsg);
1791 return bacl_rtn_error;
1799 #else /* HAVE_EXTENDED_ACL */
1802 * Define the supported ACL streams for this OS
1804 static int os_access_acl_streams[1] = {
1805 STREAM_ACL_SOLARIS_POSIX
1807 static int os_default_acl_streams[1] = {
1812 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1813 * There is no need to store those acls as we already store the stat bits too.
1815 static bool acl_is_trivial(int count, aclent_t *entries)
1820 for (n = 0; n < count; n++) {
1823 if (!(ace->a_type == USER_OBJ ||
1824 ace->a_type == GROUP_OBJ ||
1825 ace->a_type == OTHER_OBJ ||
1826 ace->a_type == CLASS_OBJ))
1833 * OS specific functions for handling different types of acl streams.
1835 static bacl_rtn_code solaris_backup_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1841 n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1842 if (n < MIN_ACL_ENTRIES) {
1843 return bacl_rtn_error;
1846 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1847 if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1848 if (acl_is_trivial(n, acls)) {
1850 * The ACLs simply reflect the (already known) standard permissions
1851 * So we don't send an ACL stream to the SD.
1854 pm_strcpy(jcr->acl_ctx->content, "");
1855 jcr->acl_ctx->content_length = 0;
1859 if ((acl_text = acltotext(acls, n)) != NULL) {
1860 jcr->acl_ctx->content_length =
1861 pm_strcpy(jcr->acl_ctx->content, acl_text);
1862 actuallyfree(acl_text);
1864 return send_acl_stream(jcr, STREAM_ACL_SOLARIS_POSIX);
1868 Mmsg2(jcr->errmsg, _("acltotext error on file \"%s\": ERR=%s\n"),
1869 jcr->last_fname, be.bstrerror());
1870 Dmsg1(100, "%s", jcr->errmsg);
1874 return bacl_rtn_error;
1877 static bacl_rtn_code solaris_restore_acl_streams(JCR *jcr, int stream, char *content,
1878 uint32_t content_length)
1883 acls = aclfromtext(content, &n);
1887 Mmsg2(jcr->errmsg, _("aclfromtext error on file \"%s\": ERR=%s\n"),
1888 jcr->last_fname, be.bstrerror());
1889 Dmsg1(100, "%s", jcr->errmsg);
1890 return bacl_rtn_error;
1894 * Restore the ACLs, but don't complain about links which really should
1895 * not have attributes, and the file it is linked to may not yet be restored.
1897 if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
1899 if (errno == ENOENT) {
1903 Mmsg2(jcr->errmsg, _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
1904 jcr->last_fname, be.bstrerror());
1905 Dmsg1(100, "%s", jcr->errmsg);
1907 return bacl_rtn_error;
1913 #endif /* HAVE_EXTENDED_ACL */
1916 * For this OS setup the build and parse function pointer to the OS specific functions.
1918 static bacl_rtn_code (*os_backup_acl_streams)
1919 (JCR *jcr, FF_PKT *ff_pkt) =
1920 solaris_backup_acl_streams;
1921 static bacl_rtn_code (*os_restore_acl_streams)
1922 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1923 solaris_restore_acl_streams;
1925 #endif /* HAVE_SUN_OS */
1926 #endif /* HAVE_ACL */
1928 #if defined(HAVE_AFS_ACL)
1930 #if defined(HAVE_AFS_AFSINT_H) && defined(HAVE_AFS_VENUS_H)
1931 #include <afs/afsint.h>
1932 #include <afs/venus.h>
1934 #error "configure failed to detect availability of afs/afsint.h and/or afs/venus.h"
1938 * External references to functions in the libsys library function not in current include files.
1941 long pioctl(char *pathp, long opcode, struct ViceIoctl *blobp, int follow);
1944 static bacl_rtn_code afs_backup_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1947 struct ViceIoctl vip;
1948 char acl_text[BUFSIZ];
1951 * AFS ACLs can only be set on a directory, so no need to try to
1952 * request them for anything other then that.
1954 if (ff_pkt->type != FT_DIREND) {
1961 vip.out_size = sizeof(acl_text);
1962 memset((caddr_t)acl_text, 0, sizeof(acl_text));
1964 if ((error = pioctl(jcr->last_fname, VIOCGETAL, &vip, 0)) < 0) {
1966 Mmsg2(jcr->errmsg, _("pioctl VIOCGETAL error on file \"%s\": ERR=%s\n"),
1967 jcr->last_fname, be.bstrerror());
1968 Dmsg1(100, "%s", jcr->errmsg);
1969 return bacl_rtn_error;
1971 jcr->acl_ctx->content_length = pm_strcpy(jcr->acl_ctx->content, acl_text);
1972 return send_acl_stream(jcr, STREAM_ACL_AFS_TEXT);
1975 static bacl_rtn_code afs_restore_acl_stream(JCR *jcr, int stream, char *content,
1976 uint32_t content_length)
1979 struct ViceIoctl vip;
1982 vip.in_size = content_length;
1986 if ((error = pioctl(jcr->last_fname, VIOCSETAL, &vip, 0)) < 0) {
1988 Mmsg2(jcr->errmsg, _("pioctl VIOCSETAL error on file \"%s\": ERR=%s\n"),
1989 jcr->last_fname, be.bstrerror());
1990 Dmsg1(100, "%s", jcr->errmsg);
1991 return bacl_rtn_error;
1995 #endif /* HAVE_AFS_ACL */
1998 * Entry points when compiled with support for ACLs on a supported platform.
2002 * Read and send an ACL for the last encountered file.
2004 bool backup_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
2006 bacl_rtn_code rtn = bacl_rtn_error;
2008 if (!(ff_pkt->flags & FO_ACL && ff_pkt->type != FT_LNK && !ff_pkt->cmd_plugin)) {
2009 return true; /* No acl request */
2014 * See if we are changing from one device to an other.
2015 * We save the current device we are scanning and compare
2016 * it with the current st_dev in the last stat performed on
2017 * the file we are currently storing.
2019 if (jcr->acl_ctx->current_dev != ff_pkt->statp.st_dev) {
2021 * Reset the acl save flags.
2023 jcr->acl_ctx->flags = 0;
2025 #if defined(HAVE_AFS_ACL)
2027 * AFS is a non OS specific filesystem so see if this path is on an AFS filesystem
2028 * Set the BACL_FLAG_SAVE_AFS flag if it is. If not set the BACL_FLAG_SAVE_NATIVE flag.
2030 if (fstype_equals(jcr->last_fname, "afs")) {
2031 jcr->acl_ctx->flags |= BACL_FLAG_SAVE_AFS;
2033 jcr->acl_ctx->flags |= BACL_FLAG_SAVE_NATIVE;
2036 jcr->acl_ctx->flags |= BACL_FLAG_SAVE_NATIVE;
2040 * Save that we started scanning a new filesystem.
2042 jcr->acl_ctx->current_dev = ff_pkt->statp.st_dev;
2047 * See if the BACL_FLAG_SAVE_AFS flag is set which lets us know if we should
2050 if (jcr->acl_ctx->flags & BACL_FLAG_SAVE_AFS) {
2051 rtn = afs_backup_acl_streams(jcr, ff_pkt);
2058 * See if the BACL_FLAG_SAVE_NATIVE flag is set which lets us know if we should
2061 if (jcr->acl_ctx->flags & BACL_FLAG_SAVE_NATIVE) {
2063 * Call the appropriate function.
2065 if (os_backup_acl_streams) {
2066 rtn = os_backup_acl_streams(jcr, ff_pkt);
2076 case bacl_rtn_fatal:
2080 case bacl_rtn_error:
2081 if (jcr->acl_ctx->nr_errors < ACL_MAX_ERROR_PRINT_PER_JOB) {
2082 if (jcr->errmsg[0]) {
2083 Jmsg(jcr, M_WARNING, 0, "Operating system ACLs not configured.\n");
2085 Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
2087 jcr->acl_ctx->nr_errors++;
2091 /* Theoretically we cannot get here */
2095 bacl_rtn_code restore_acl_streams(JCR *jcr, int stream,
2096 char *content, uint32_t content_length)
2103 * See if we are changing from one device to an other.
2104 * We save the current device we are restoring to and compare
2105 * it with the current st_dev in the last stat performed on
2106 * the file we are currently restoring.
2108 ret = lstat(jcr->last_fname, &st);
2111 if (errno == ENOENT) {
2114 Mmsg2(jcr->errmsg, _("Unable to stat file \"%s\": ERR=%s\n"),
2115 jcr->last_fname, be.bstrerror());
2116 Dmsg1(100, "%s", jcr->errmsg);
2117 return bacl_rtn_error;
2120 if (jcr->acl_ctx->current_dev != st.st_dev) {
2122 * Reset the acl save flags.
2124 jcr->acl_ctx->flags = 0;
2126 #if defined(HAVE_AFS_ACL)
2128 * AFS is a non OS specific filesystem so see if this path is on an AFS filesystem
2129 * Set the BACL_FLAG_RESTORE_AFS flag if it is. If not set the BACL_FLAG_RETORE_NATIVE flag.
2131 if (fstype_equals(jcr->last_fname, "afs")) {
2132 jcr->acl_ctx->flags |= BACL_FLAG_RESTORE_AFS;
2134 jcr->acl_ctx->flags |= BACL_FLAG_RESTORE_NATIVE;
2137 jcr->acl_ctx->flags |= BACL_FLAG_RESTORE_NATIVE;
2140 /* Save that we started restoring to a new filesystem. */
2141 jcr->acl_ctx->current_dev = st.st_dev;
2146 case STREAM_ACL_AFS_TEXT:
2147 if (jcr->acl_ctx->flags & BACL_FLAG_RESTORE_AFS) {
2148 return afs_restore_acl_stream(jcr, stream, content, content_length);
2151 * Increment error count but don't log an error again for the same filesystem.
2153 jcr->acl_ctx->nr_errors++;
2159 case STREAM_UNIX_ACCESS_ACL:
2160 case STREAM_UNIX_DEFAULT_ACL:
2162 * Handle legacy ACL streams.
2164 if ((jcr->acl_ctx->flags & BACL_FLAG_RESTORE_NATIVE) && os_restore_acl_streams) {
2165 return os_restore_acl_streams(jcr, stream, content, content_length);
2168 * Increment error count but don't log an error again for the same filesystem.
2170 jcr->acl_ctx->nr_errors++;
2175 if ((jcr->acl_ctx->flags & BACL_FLAG_RESTORE_NATIVE) && os_restore_acl_streams) {
2177 * Walk the os_access_acl_streams array with the supported Access ACL streams for this OS.
2179 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
2180 if (os_access_acl_streams[cnt] == stream) {
2181 return os_restore_acl_streams(jcr, stream, content, content_length);
2185 * Walk the os_default_acl_streams array with the supported Default ACL streams for this OS.
2187 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
2188 if (os_default_acl_streams[cnt] == stream) {
2189 return os_restore_acl_streams(jcr, stream, content, content_length);
2194 * Increment error count but don't log an error again for the same filesystem.
2196 jcr->acl_ctx->nr_errors++;
2205 Qmsg2(jcr, M_WARNING, 0, _("Cannot restore ACLs of %s - incompatible acl stream encountered - %d\n"),
2206 jcr->last_fname, stream);
2207 return bacl_rtn_error;