2 Bacula® - The Network Backup Solution
4 Copyright (C) 2004-2010 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Functions to handle ACLs for bacula.
31 * Currently we support the following OSes:
32 * - AIX (pre-5.3 and post 5.3 acls, acl_get and aclx_get interface)
34 * - FreeBSD (POSIX and NFSv4/ZFS acls)
38 * - Solaris (POSIX and NFSv4/ZFS acls)
41 * Next to OS specific acls we support AFS acls using the pioctl interface.
43 * We handle two different types of ACLs: access and default ACLS.
44 * On most systems that support default ACLs they only apply to directories.
46 * On some systems (eg. linux and FreeBSD) we must obtain the two ACLs
47 * independently, while others (eg. Solaris) provide both in one call.
49 * The Filed saves ACLs in their native format and uses different streams
50 * for all different platforms. Currently we only allow ACLs to be restored
51 * which were saved in the native format of the platform they are extracted
52 * on. Later on we might add conversion functions for mapping from one
53 * platform to an other or allow restores of systems that use the same
56 * Its also interesting to see what the exact format of acl text is on
57 * certain platforms and if they use they same encoding we might allow
58 * different platform streams to be decoded on an other similar platform.
60 * Original written by Preben 'Peppe' Guldberg, December MMIV
61 * Major rewrite by Marco van Wieringen, November MMVIII
67 #if !defined(HAVE_ACL) && !defined(HAVE_AFS_ACL)
69 * Entry points when compiled without support for ACLs or on an unsupported platform.
71 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
73 return bacl_exit_fatal;
76 bacl_exit_code parse_acl_streams(JCR *jcr, int stream)
78 return bacl_exit_fatal;
82 * Send an ACL stream to the SD.
84 static bacl_exit_code send_acl_stream(JCR *jcr, int stream)
86 BSOCK *sd = jcr->store_bsock;
88 #ifdef FD_NO_SEND_TEST
95 if (jcr->acl_data->content_length <= 0) {
102 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
103 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
105 return bacl_exit_fatal;
109 * Send the buffer to the storage deamon
111 Dmsg1(400, "Backing up ACL <%s>\n", jcr->acl_data->content);
113 sd->msg = jcr->acl_data->content;
114 sd->msglen = jcr->acl_data->content_length + 1;
118 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
120 return bacl_exit_fatal;
123 jcr->JobBytes += sd->msglen;
125 if (!sd->signal(BNET_EOD)) {
126 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
128 return bacl_exit_fatal;
131 Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
136 * First the native ACLs.
138 #if defined(HAVE_ACL)
139 #if defined(HAVE_AIX_OS)
141 #if defined(HAVE_EXTENDED_ACL)
143 #include <sys/access.h>
146 static bool acl_is_trivial(struct acl *acl)
148 return (acl_last(acl) != acl->acl_ext ? false : true);
151 static bool acl_nfs4_is_trivial(nfs4_acl_int_t *acl)
153 return (acl->aclEntryN > 0 ? false : true);
157 * Define the supported ACL streams for this OS
159 static int os_access_acl_streams[3] = { STREAM_ACL_AIX_TEXT, STREAM_ACL_AIX_AIXC, STREAM_ACL_AIX_NFS4 };
160 static int os_default_acl_streams[1] = { -1 };
162 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
167 size_t aclsize, acltxtsize;
168 bacl_exit_code retval = bacl_exit_error;
169 POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
172 * First see how big the buffers should be.
175 if (aclx_get(jcr->last_fname, GET_ACLINFO_ONLY, &type, NULL, &aclsize, NULL) < 0) {
178 retval = bacl_exit_ok;
181 Mmsg2(jcr->errmsg, _("aclx_get error on file \"%s\": ERR=%s\n"),
182 jcr->last_fname, be.bstrerror());
183 Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
184 jcr->last_fname, be.bstrerror());
190 * Make sure the buffers are big enough.
192 aclbuf = check_pool_memory_size(aclbuf, aclsize + 1);
195 * Retrieve the ACL info.
197 if (aclx_get(jcr->last_fname, 0, &type, aclbuf, &aclsize, &mode) < 0) {
200 retval = bacl_exit_ok;
203 Mmsg2(jcr->errmsg, _("aclx_get error on file \"%s\": ERR=%s\n"),
204 jcr->last_fname, be.bstrerror());
205 Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
206 jcr->last_fname, be.bstrerror());
212 * See if the acl is non trivial.
216 if (acl_is_trivial((struct acl *)aclbuf)) {
217 retval = bacl_exit_ok;
222 if (acl_nfs4_is_trivial((nfs4_acl_int_t *)aclbuf)) {
223 retval = bacl_exit_ok;
228 Mmsg2(jcr->errmsg, _("Unknown acl type encountered on file \"%s\": %ld\n"),
229 jcr->last_fname, type.u64);
230 Dmsg2(100, "Unknown acl type encountered on file \"%s\": %ld\n",
231 jcr->last_fname, type.u64);
236 * We have a non-trivial acl lets convert it into some ASCII form.
238 acltxtsize = sizeof_pool_memory(jcr->acl_data->content);
239 if (aclx_printStr(jcr->acl_data->content, &acltxtsize, aclbuf,
240 aclsize, type, jcr->last_fname, 0) < 0) {
244 * Our buffer is not big enough, acltxtsize should be updated with the value
245 * the aclx_printStr really need. So we increase the buffer and try again.
247 jcr->acl_data->content = check_pool_memory_size(jcr->acl_data->content, acltxtsize + 1);
248 if (aclx_printStr(jcr->acl_data->content, &acltxtsize, aclbuf,
249 aclsize, type, jcr->last_fname, 0) < 0) {
250 Mmsg1(jcr->errmsg, _("Failed to convert acl into text on file \"%s\"\n"),
252 Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
253 jcr->last_fname, type.u64);
258 Mmsg1(jcr->errmsg, _("Failed to convert acl into text on file \"%s\"\n"),
260 Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
261 jcr->last_fname, type.u64);
266 jcr->acl_data->content_length = strlen(jcr->acl_data->content) + 1;
269 retval = send_acl_stream(jcr, STREAM_ACL_AIX_AIXC);
271 retval = send_acl_stream(jcr, STREAM_ACL_AIX_NFS4);
275 free_pool_memory(aclbuf);
280 static bacl_exit_code aix_parse_acl_streams(JCR *jcr, int stream)
286 bacl_exit_code retval = bacl_exit_error;
287 POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
290 case STREAM_ACL_AIX_TEXT:
292 * Handle the old stream using the old system call for now.
294 if (acl_put(jcr->last_fname, jcr->acl_data->content, 0) != 0) {
295 retval = bacl_exit_error;
298 retval = bacl_exit_ok;
300 case STREAM_ACL_AIX_AIXC:
303 case STREAM_ACL_AIX_NFS4:
308 } /* end switch (stream) */
311 * Set the acl buffer to an initial size. For now we set it
312 * to the same size as the ASCII representation.
314 aclbuf = check_pool_memory_size(aclbuf, jcr->acl_data->content_length);
315 aclsize = jcr->acl_data->content_length;
316 if (aclx_scanStr(jcr->acl_data->content, aclbuf, &aclsize, type) < 0) {
320 * The buffer isn't big enough. The man page doesn't say that aclsize
321 * is updated to the needed size as what is done with aclx_printStr.
322 * So for now we try to increase the buffer a maximum of 3 times
323 * and retry the conversion.
325 for (cnt = 0; cnt < 3; cnt++) {
326 aclsize = 2 * aclsize;
327 aclbuf = check_pool_memory_size(aclbuf, aclsize);
329 if (aclx_scanStr(jcr->acl_data->content, aclbuf, &aclsize, type) == 0) {
334 * See why we failed this time, ENOSPC retry if max retries not met,
344 Mmsg2(jcr->errmsg, _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
345 jcr->last_fname, be.bstrerror());
346 Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
347 jcr->last_fname, be.bstrerror());
353 Mmsg2(jcr->errmsg, _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
354 jcr->last_fname, be.bstrerror());
355 Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
356 jcr->last_fname, be.bstrerror());
360 if (aclx_put(jcr->last_fname, SET_ACL, type, aclbuf, aclsize, 0) < 0) {
363 retval = bacl_exit_ok;
366 Mmsg2(jcr->errmsg, _("aclx_put error on file \"%s\": ERR=%s\n"),
367 jcr->last_fname, be.bstrerror());
368 Dmsg2(100, "aclx_put error file=%s ERR=%s\n",
369 jcr->last_fname, be.bstrerror());
374 retval = bacl_exit_ok;
377 free_pool_memory(aclbuf);
382 #else /* HAVE_EXTENDED_ACL */
384 #include <sys/access.h>
387 * Define the supported ACL streams for this OS
389 static int os_access_acl_streams[1] = { STREAM_ACL_AIX_TEXT };
390 static int os_default_acl_streams[1] = { -1 };
392 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
396 if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
397 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
398 actuallyfree(acl_text);
399 return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT);
401 return bacl_exit_error;
404 static bacl_exit_code aix_parse_acl_streams(JCR *jcr, int stream)
406 if (acl_put(jcr->last_fname, jcr->acl_data->content, 0) != 0) {
407 return bacl_exit_error;
411 #endif /* HAVE_EXTENDED_ACL */
414 * For this OS setup the build and parse function pointer to the OS specific functions.
416 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = aix_build_acl_streams;
417 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = aix_parse_acl_streams;
419 #elif defined(HAVE_DARWIN_OS) || \
420 defined(HAVE_FREEBSD_OS) || \
421 defined(HAVE_IRIX_OS) || \
422 defined(HAVE_OSF1_OS) || \
423 defined(HAVE_LINUX_OS)
425 #include <sys/types.h>
427 #ifdef HAVE_SYS_ACL_H
430 #error "configure failed to detect availability of sys/acl.h"
434 * On IRIX we can get shortened ACLs
436 #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
437 #define acl_to_text(acl,len) acl_to_short_text((acl), (len))
441 * On Linux we can get numeric and/or shorted ACLs
443 #if defined(HAVE_LINUX_OS)
444 #if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
445 #define BACL_ALTERNATE_TEXT (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
446 #elif defined(BACL_WANT_SHORT_ACLS)
447 #define BACL_ALTERNATE_TEXT TEXT_ABBREVIATE
448 #elif defined(BACL_WANT_NUMERIC_IDS)
449 #define BACL_ALTERNATE_TEXT TEXT_NUMERIC_IDS
451 #ifdef BACL_ALTERNATE_TEXT
452 #include <acl/libacl.h>
453 #define acl_to_text(acl,len) (acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
458 * On FreeBSD we can get numeric ACLs
460 #if defined(HAVE_FREEBSD_OS)
461 #if defined(BACL_WANT_NUMERIC_IDS)
462 #define BACL_ALTERNATE_TEXT ACL_TEXT_NUMERIC_IDS
464 #ifdef BACL_ALTERNATE_TEXT
465 #define acl_to_text(acl,len) (acl_to_text_np((acl), (len), BACL_ALTERNATE_TEXT))
470 * Some generic functions used by multiple OSes.
472 static acl_type_t bac_to_os_acltype(bacl_type acltype)
477 case BACL_TYPE_ACCESS:
478 ostype = ACL_TYPE_ACCESS;
480 case BACL_TYPE_DEFAULT:
481 ostype = ACL_TYPE_DEFAULT;
483 #ifdef HAVE_ACL_TYPE_NFS4
485 * FreeBSD has an additional acl type named ACL_TYPE_NFS4.
488 ostype = ACL_TYPE_NFS4;
491 #ifdef HAVE_ACL_TYPE_DEFAULT_DIR
492 case BACL_TYPE_DEFAULT_DIR:
494 * TRU64 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
496 ostype = ACL_TYPE_DEFAULT_DIR;
499 #ifdef HAVE_ACL_TYPE_EXTENDED
500 case BACL_TYPE_EXTENDED:
502 * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
504 ostype = ACL_TYPE_EXTENDED;
509 * This should never happen, as the per OS version function only tries acl
510 * types supported on a certain platform.
512 ostype = (acl_type_t)ACL_TYPE_NONE;
518 static int acl_count_entries(acl_t acl)
521 #if defined(HAVE_FREEBSD_OS) || \
522 defined(HAVE_LINUX_OS)
526 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
527 while (entry_available == 1) {
529 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
531 #elif defined(HAVE_IRIX_OS)
532 count = acl->acl_cnt;
533 #elif defined(HAVE_OSF1_OS)
534 count = acl->acl_num;
535 #elif defined(HAVE_DARWIN_OS)
539 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
540 while (entry_available == 0) {
542 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
548 #if !defined(HAVE_DARWIN_OS)
550 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
551 * There is no need to store those acls as we already store the stat bits too.
553 static bool acl_is_trivial(acl_t acl)
556 * acl is trivial if it has only the following entries:
563 #if defined(HAVE_FREEBSD_OS) || \
564 defined(HAVE_LINUX_OS)
567 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
568 while (entry_available == 1) {
570 * Get the tag type of this acl entry.
571 * If we fail to get the tagtype we call the acl non-trivial.
573 if (acl_get_tag_type(ace, &tag) < 0)
576 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
578 if (tag != ACL_USER_OBJ &&
579 tag != ACL_GROUP_OBJ &&
582 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
585 #elif defined(HAVE_IRIX_OS)
588 for (n = 0; n < acl->acl_cnt; n++) {
589 ace = &acl->acl_entry[n];
593 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
595 if (tag != ACL_USER_OBJ &&
596 tag != ACL_GROUP_OBJ &&
597 tag != ACL_OTHER_OBJ)
601 #elif defined(HAVE_OSF1_OS)
604 ace = acl->acl_first;
605 count = acl->acl_num;
608 tag = ace->entry->acl_type;
610 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
612 if (tag != ACL_USER_OBJ &&
613 tag != ACL_GROUP_OBJ &&
617 * On Tru64, perm can also contain non-standard bits such as
618 * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
620 if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
631 * Generic wrapper around acl_get_file call.
633 static bacl_exit_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
639 bacl_exit_code retval = bacl_exit_ok;
641 ostype = bac_to_os_acltype(acltype);
642 acl = acl_get_file(jcr->last_fname, ostype);
645 * From observation, IRIX's acl_get_file() seems to return a
646 * non-NULL acl with a count field of -1 when a file has no ACL
647 * defined, while IRIX's acl_to_text() returns NULL when presented
650 * For all other implmentations we check if there are more then
651 * zero entries in the acl returned.
653 if (acl_count_entries(acl) <= 0) {
658 * Make sure this is not just a trivial ACL.
660 #if !defined(HAVE_DARWIN_OS)
661 if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
663 * The ACLs simply reflect the (already known) standard permissions
664 * So we don't send an ACL stream to the SD.
669 #if defined(HAVE_FREEBSD_OS) && defined(_PC_ACL_NFS4)
670 if (acltype == BACL_TYPE_NFS4) {
672 if (acl_is_trivial_np(acl, &trivial) == 0) {
675 * The ACLs simply reflect the (already known) standard permissions
676 * So we don't send an ACL stream to the SD.
685 * Convert the internal acl representation into a text representation.
687 if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
688 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
694 Mmsg2(jcr->errmsg, _("acl_to_text error on file \"%s\": ERR=%s\n"),
695 jcr->last_fname, be.bstrerror());
696 Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",
697 jcr->last_fname, be.bstrerror());
699 retval = bacl_exit_error;
703 * Handle errors gracefully.
706 #if defined(BACL_ENOTSUP)
709 * If the filesystem reports it doesn't support ACLs we clear the
710 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
711 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
712 * when we change from one filesystem to an other.
714 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
720 /* Some real error */
721 Mmsg2(jcr->errmsg, _("acl_get_file error on file \"%s\": ERR=%s\n"),
722 jcr->last_fname, be.bstrerror());
723 Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",
724 jcr->last_fname, be.bstrerror());
726 retval = bacl_exit_error;
735 pm_strcpy(jcr->acl_data->content, "");
736 jcr->acl_data->content_length = 0;
741 * Generic wrapper around acl_set_file call.
743 static bacl_exit_code generic_set_acl_on_os(JCR *jcr, bacl_type acltype)
750 * If we get empty default ACLs, clear ACLs now
752 ostype = bac_to_os_acltype(acltype);
753 if (ostype == ACL_TYPE_DEFAULT && strlen(jcr->acl_data->content) == 0) {
754 if (acl_delete_def_file(jcr->last_fname) == 0) {
761 Mmsg2(jcr->errmsg, _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
762 jcr->last_fname, be.bstrerror());
763 return bacl_exit_error;
767 acl = acl_from_text(jcr->acl_data->content);
769 Mmsg2(jcr->errmsg, _("acl_from_text error on file \"%s\": ERR=%s\n"),
770 jcr->last_fname, be.bstrerror());
771 Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",
772 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
773 return bacl_exit_error;
776 #ifndef HAVE_FREEBSD_OS
778 * FreeBSD always fails acl_valid() - at least on valid input...
779 * As it does the right thing, given valid input, just ignore acl_valid().
781 if (acl_valid(acl) != 0) {
782 Mmsg2(jcr->errmsg, _("acl_valid error on file \"%s\": ERR=%s\n"),
783 jcr->last_fname, be.bstrerror());
784 Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",
785 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
787 return bacl_exit_error;
792 * Restore the ACLs, but don't complain about links which really should
793 * not have attributes, and the file it is linked to may not yet be restored.
794 * This is only true for the old acl streams as in the new implementation we
795 * don't save acls of symlinks (which cannot have acls anyhow)
797 if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
803 Mmsg2(jcr->errmsg, _("acl_set_file error on file \"%s\": ERR=%s\n"),
804 jcr->last_fname, be.bstrerror());
805 Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
806 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
808 return bacl_exit_error;
816 * OS specific functions for handling different types of acl streams.
818 #if defined(HAVE_DARWIN_OS)
820 * Define the supported ACL streams for this OS
822 static int os_access_acl_streams[1] = { STREAM_ACL_DARWIN_ACCESS_ACL };
823 static int os_default_acl_streams[1] = { -1 };
825 static bacl_exit_code darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
827 #if defined(HAVE_ACL_TYPE_EXTENDED)
829 * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
830 * and acl_get_file (name, ACL_TYPE_DEFAULT)
831 * always return NULL / EINVAL. There is no point in making
832 * these two useless calls. The real ACL is retrieved through
833 * acl_get_file (name, ACL_TYPE_EXTENDED).
835 * Read access ACLs for files, dirs and links
837 if (generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED) == bacl_exit_fatal)
838 return bacl_exit_fatal;
841 * Read access ACLs for files, dirs and links
843 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
844 return bacl_exit_fatal;
847 if (jcr->acl_data->content_length > 0) {
848 return send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL);
853 static bacl_exit_code darwin_parse_acl_streams(JCR *jcr, int stream)
855 #if defined(HAVE_ACL_TYPE_EXTENDED)
856 return generic_set_acl_on_os(jcr, BACL_TYPE_EXTENDED);
858 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
863 * For this OS setup the build and parse function pointer to the OS specific functions.
865 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = darwin_build_acl_streams;
866 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = darwin_parse_acl_streams;
868 #elif defined(HAVE_FREEBSD_OS)
870 * Define the supported ACL streams for these OSes
872 static int os_access_acl_streams[2] = { STREAM_ACL_FREEBSD_ACCESS_ACL, STREAM_ACL_FREEBSD_NFS4_ACL };
873 static int os_default_acl_streams[1] = { STREAM_ACL_FREEBSD_DEFAULT_ACL };
875 static bacl_exit_code freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
878 bacl_type acltype = BACL_TYPE_NONE;
881 #if defined(_PC_ACL_NFS4)
883 * See if filesystem supports NFS4 acls.
885 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
886 switch (acl_enabled) {
892 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
893 jcr->last_fname, be.bstrerror());
894 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
895 jcr->last_fname, be.bstrerror());
896 return bacl_exit_error;
901 acltype = BACL_TYPE_NFS4;
906 if (acl_enabled == 0) {
908 * See if filesystem supports POSIX acls.
910 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
911 switch (acl_enabled) {
917 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
918 jcr->last_fname, be.bstrerror());
919 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
920 jcr->last_fname, be.bstrerror());
921 return bacl_exit_error;
926 acltype = BACL_TYPE_ACCESS;
932 * If the filesystem reports it doesn't support ACLs we clear the
933 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
934 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
935 * when we change from one filesystem to an other.
937 if (acl_enabled == 0) {
938 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
939 pm_strcpy(jcr->acl_data->content, "");
940 jcr->acl_data->content_length = 0;
945 * Based on the supported ACLs retrieve and store them.
950 * Read NFS4 ACLs for files, dirs and links
952 if (generic_get_acl_from_os(jcr, BACL_TYPE_NFS4) == bacl_exit_fatal)
953 return bacl_exit_fatal;
955 if (jcr->acl_data->content_length > 0) {
956 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_NFS4_ACL) == bacl_exit_fatal)
957 return bacl_exit_fatal;
960 case BACL_TYPE_ACCESS:
962 * Read access ACLs for files, dirs and links
964 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
965 return bacl_exit_fatal;
967 if (jcr->acl_data->content_length > 0) {
968 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_ACCESS_ACL) == bacl_exit_fatal)
969 return bacl_exit_fatal;
973 * Directories can have default ACLs too
975 if (ff_pkt->type == FT_DIREND) {
976 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
977 return bacl_exit_fatal;
978 if (jcr->acl_data->content_length > 0) {
979 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_DEFAULT_ACL) == bacl_exit_fatal)
980 return bacl_exit_fatal;
991 static bacl_exit_code freebsd_parse_acl_streams(JCR *jcr, int stream)
994 const char *acl_type_name;
998 * First make sure the filesystem supports acls.
1001 case STREAM_UNIX_ACCESS_ACL:
1002 case STREAM_ACL_FREEBSD_ACCESS_ACL:
1003 case STREAM_UNIX_DEFAULT_ACL:
1004 case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1005 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
1006 acl_type_name = "POSIX";
1008 case STREAM_ACL_FREEBSD_NFS4_ACL:
1009 #if defined(_PC_ACL_NFS4)
1010 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
1012 acl_type_name = "NFS4";
1015 acl_type_name = "unknown";
1019 switch (acl_enabled) {
1023 return bacl_exit_ok;
1025 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1026 jcr->last_fname, be.bstrerror());
1027 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1028 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1029 return bacl_exit_error;
1032 Mmsg2(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without %s acl support\n"),
1033 jcr->last_fname, acl_type_name);
1034 return bacl_exit_error;
1043 case STREAM_UNIX_ACCESS_ACL:
1044 case STREAM_ACL_FREEBSD_ACCESS_ACL:
1045 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
1046 case STREAM_UNIX_DEFAULT_ACL:
1047 case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1048 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
1049 case STREAM_ACL_FREEBSD_NFS4_ACL:
1050 return generic_set_acl_on_os(jcr, BACL_TYPE_NFS4);
1054 return bacl_exit_error;
1058 * For this OSes setup the build and parse function pointer to the OS specific functions.
1060 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = freebsd_build_acl_streams;
1061 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = freebsd_parse_acl_streams;
1063 #elif defined(HAVE_IRIX_OS) || \
1064 defined(HAVE_LINUX_OS)
1066 * Define the supported ACL streams for these OSes
1068 #if defined(HAVE_IRIX_OS)
1069 static int os_access_acl_streams[1] = { STREAM_ACL_IRIX_ACCESS_ACL };
1070 static int os_default_acl_streams[1] = { STREAM_ACL_IRIX_DEFAULT_ACL };
1071 #elif defined(HAVE_LINUX_OS)
1072 static int os_access_acl_streams[1] = { STREAM_ACL_LINUX_ACCESS_ACL };
1073 static int os_default_acl_streams[1] = { STREAM_ACL_LINUX_DEFAULT_ACL };
1076 static bacl_exit_code generic_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1079 * Read access ACLs for files, dirs and links
1081 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1082 return bacl_exit_fatal;
1084 if (jcr->acl_data->content_length > 0) {
1085 if (send_acl_stream(jcr, os_access_acl_streams[0]) == bacl_exit_fatal)
1086 return bacl_exit_fatal;
1090 * Directories can have default ACLs too
1092 if (ff_pkt->type == FT_DIREND) {
1093 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
1094 return bacl_exit_fatal;
1095 if (jcr->acl_data->content_length > 0) {
1096 if (send_acl_stream(jcr, os_default_acl_streams[0]) == bacl_exit_fatal)
1097 return bacl_exit_fatal;
1100 return bacl_exit_ok;
1103 static bacl_exit_code generic_parse_acl_streams(JCR *jcr, int stream)
1108 case STREAM_UNIX_ACCESS_ACL:
1109 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
1110 case STREAM_UNIX_DEFAULT_ACL:
1111 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
1114 * See what type of acl it is.
1116 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1117 if (os_access_acl_streams[cnt] == stream) {
1118 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
1121 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1122 if (os_default_acl_streams[cnt] == stream) {
1123 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
1128 return bacl_exit_error;
1132 * For this OSes setup the build and parse function pointer to the OS specific functions.
1134 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_build_acl_streams;
1135 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = generic_parse_acl_streams;
1137 #elif defined(HAVE_OSF1_OS)
1140 * Define the supported ACL streams for this OS
1142 static int os_access_acl_streams[1] = { STREAM_ACL_TRU64_ACCESS_ACL };
1143 static int os_default_acl_streams[2] = { STREAM_ACL_TRU64_DEFAULT_ACL, STREAM_ACL_TRU64_DEFAULT_DIR_ACL };
1145 static bacl_exit_code tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1148 * Read access ACLs for files, dirs and links
1150 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
1151 return bacl_exit_error;
1152 if (jcr->acl_data->content_length > 0) {
1153 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL))
1154 return bacl_exit_error;
1157 * Directories can have default ACLs too
1159 if (ff_pkt->type == FT_DIREND) {
1160 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
1161 return bacl_exit_error;
1162 if (jcr->acl_data->content_length > 0) {
1163 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL))
1164 return bacl_exit_error;
1167 * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
1168 * This is an inherited acl for all subdirs.
1169 * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
1170 * Section 21.5 Default ACLs
1172 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR)) < 0)
1173 return bacl_exit_error;
1174 if (jcr->acl_data->content_length > 0) {
1175 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL))
1176 return bacl_exit_error;
1179 return bacl_exit_ok;
1182 static bacl_exit_code tru64_parse_acl_streams(JCR *jcr, int stream)
1185 case STREAM_UNIX_ACCESS_ACL:
1186 case STREAM_ACL_TRU64_ACCESS_ACL:
1187 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
1188 case STREAM_UNIX_DEFAULT_ACL:
1189 case STREAM_ACL_TRU64_DEFAULT_ACL:
1190 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
1191 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
1192 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR);
1196 * For this OS setup the build and parse function pointer to the OS specific functions.
1198 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = tru64_build_acl_streams;
1199 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = tru64_parse_acl_streams;
1203 #elif defined(HAVE_HPUX_OS)
1204 #ifdef HAVE_SYS_ACL_H
1205 #include <sys/acl.h>
1207 #error "configure failed to detect availability of sys/acl.h"
1213 * Define the supported ACL streams for this OS
1215 static int os_access_acl_streams[1] = { STREAM_ACL_HPUX_ACL_ENTRY };
1216 static int os_default_acl_streams[1] = { -1 };
1219 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1220 * There is no need to store those acls as we already store the stat bits too.
1222 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
1225 struct acl_entry ace
1227 for (n = 0; n < count; n++) {
1230 * See if this acl just is the stat mode in acl form.
1232 if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
1233 (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
1234 (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
1241 * OS specific functions for handling different types of acl streams.
1243 static bacl_exit_code hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1246 struct acl_entry acls[NACLENTRIES];
1250 if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
1252 #if defined(BACL_ENOTSUP)
1255 * Not supported, just pretend there is nothing to see
1257 * If the filesystem reports it doesn't support ACLs we clear the
1258 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1259 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1260 * when we change from one filesystem to an other.
1262 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1263 pm_strcpy(jcr->acl_data->content, "");
1264 jcr->acl_data->content_length = 0;
1265 return bacl_exit_ok;
1268 pm_strcpy(jcr->acl_data->content, "");
1269 jcr->acl_data->content_length = 0;
1270 return bacl_exit_ok;
1272 Mmsg2(jcr->errmsg, _("getacl error on file \"%s\": ERR=%s\n"),
1273 jcr->last_fname, be.bstrerror());
1274 Dmsg2(100, "getacl error file=%s ERR=%s\n",
1275 jcr->last_fname, be.bstrerror());
1277 pm_strcpy(jcr->acl_data->content, "");
1278 jcr->acl_data->content_length = 0;
1279 return bacl_exit_error;
1283 pm_strcpy(jcr->acl_data->content, "");
1284 jcr->acl_data->content_length = 0;
1285 return bacl_exit_ok;
1287 if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
1288 if (acl_is_trivial(n, acls, ff_pkt->statp)) {
1290 * The ACLs simply reflect the (already known) standard permissions
1291 * So we don't send an ACL stream to the SD.
1293 pm_strcpy(jcr->acl_data->content, "");
1294 jcr->acl_data->content_length = 0;
1295 return bacl_exit_ok;
1297 if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
1298 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1299 actuallyfree(acl_text);
1301 return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
1303 Mmsg2(jcr->errmsg, _("acltostr error on file \"%s\": ERR=%s\n"),
1304 jcr->last_fname, be.bstrerror());
1305 Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",
1306 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1307 return bacl_exit_error;
1309 return bacl_exit_error;
1312 static bacl_exit_code hpux_parse_acl_streams(JCR *jcr, int stream)
1315 struct acl_entry acls[NACLENTRIES];
1318 n = strtoacl(jcr->acl_data->content, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
1320 Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
1321 jcr->last_fname, be.bstrerror());
1322 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
1323 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1324 return bacl_exit_error;
1326 if (strtoacl(jcr->acl_data->content, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
1327 Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
1328 jcr->last_fname, be.bstrerror());
1329 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
1330 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1332 return bacl_exit_error;
1335 * Restore the ACLs, but don't complain about links which really should
1336 * not have attributes, and the file it is linked to may not yet be restored.
1337 * This is only true for the old acl streams as in the new implementation we
1338 * don't save acls of symlinks (which cannot have acls anyhow)
1340 if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
1343 return bacl_exit_ok;
1345 Mmsg2(jcr->errmsg, _("setacl error on file \"%s\": ERR=%s\n"),
1346 jcr->last_fname, be.bstrerror());
1347 Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
1348 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1349 return bacl_exit_error;
1352 return bacl_exit_ok;
1356 * For this OS setup the build and parse function pointer to the OS specific functions.
1358 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = hpux_build_acl_streams;
1359 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = hpux_parse_acl_streams;
1361 #elif defined(HAVE_SUN_OS)
1362 #ifdef HAVE_SYS_ACL_H
1363 #include <sys/acl.h>
1365 #error "configure failed to detect availability of sys/acl.h"
1368 #if defined(HAVE_EXTENDED_ACL)
1370 * We define some internals of the Solaris acl libs here as those
1371 * are not exposed yet. Probably because they want us to see the
1372 * acls as opague data. But as we need to support different platforms
1373 * and versions of Solaris we need to expose some data to be able
1374 * to determine the type of acl used to stuff it into the correct
1375 * data stream. I know this is far from portable, but maybe the
1376 * proper interface is exposed later on and we can get ride of
1377 * this kludge. Newer versions of Solaris include sys/acl_impl.h
1378 * which has implementation details of acls, if thats included we
1379 * don't have to define it ourself.
1381 #if !defined(_SYS_ACL_IMPL_H)
1382 typedef enum acl_type {
1389 * Two external references to functions in the libsec library function not in current include files.
1392 int acl_type(acl_t *);
1393 char *acl_strerror(int);
1397 * Define the supported ACL streams for this OS
1399 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT, STREAM_ACL_SOLARIS_ACE };
1400 static int os_default_acl_streams[1] = { -1 };
1403 * As the new libsec interface with acl_totext and acl_fromtext also handles
1404 * the old format from acltotext we can use the new functions even
1405 * for acls retrieved and stored in the database with older fd versions. If the
1406 * new interface is not defined (Solaris 9 and older we fall back to the old code)
1408 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1410 int acl_enabled, flags;
1413 bacl_exit_code stream_status = bacl_exit_error;
1417 * See if filesystem supports acls.
1419 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1420 switch (acl_enabled) {
1423 * If the filesystem reports it doesn't support ACLs we clear the
1424 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1425 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1426 * when we change from one filesystem to an other.
1428 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1429 pm_strcpy(jcr->acl_data->content, "");
1430 jcr->acl_data->content_length = 0;
1431 return bacl_exit_ok;
1435 return bacl_exit_ok;
1437 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1438 jcr->last_fname, be.bstrerror());
1439 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
1440 jcr->last_fname, be.bstrerror());
1441 return bacl_exit_error;
1448 * Get ACL info: don't bother allocating space if there is only a trivial ACL.
1450 if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
1453 return bacl_exit_ok;
1455 Mmsg2(jcr->errmsg, _("acl_get error on file \"%s\": ERR=%s\n"),
1456 jcr->last_fname, acl_strerror(errno));
1457 Dmsg2(100, "acl_get error file=%s ERR=%s\n",
1458 jcr->last_fname, acl_strerror(errno));
1459 return bacl_exit_error;
1465 * The ACLs simply reflect the (already known) standard permissions
1466 * So we don't send an ACL stream to the SD.
1468 pm_strcpy(jcr->acl_data->content, "");
1469 jcr->acl_data->content_length = 0;
1470 return bacl_exit_ok;
1473 #if defined(ACL_SID_FMT)
1475 * New format flag added in newer Solaris versions.
1477 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
1479 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
1480 #endif /* ACL_SID_FMT */
1482 if ((acl_text = acl_totext(aclp, flags)) != NULL) {
1483 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1484 actuallyfree(acl_text);
1486 switch (acl_type(aclp)) {
1488 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1491 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE);
1499 return stream_status;
1502 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
1505 int acl_enabled, error;
1509 case STREAM_UNIX_ACCESS_ACL:
1510 case STREAM_ACL_SOLARIS_ACLENT:
1511 case STREAM_ACL_SOLARIS_ACE:
1513 * First make sure the filesystem supports acls.
1515 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1516 switch (acl_enabled) {
1518 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
1520 return bacl_exit_error;
1524 return bacl_exit_ok;
1526 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1527 jcr->last_fname, be.bstrerror());
1528 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1529 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1530 return bacl_exit_error;
1534 * On a filesystem with ACL support make sure this particular ACL type can be restored.
1537 case STREAM_ACL_SOLARIS_ACLENT:
1539 * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
1541 if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
1542 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without aclent acl support\n"),
1544 return bacl_exit_error;
1547 case STREAM_ACL_SOLARIS_ACE:
1549 * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
1551 if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
1552 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without ace acl support\n"),
1554 return bacl_exit_error;
1559 * Stream id which doesn't describe the type of acl which is encoded.
1566 if ((error = acl_fromtext(jcr->acl_data->content, &aclp)) != 0) {
1567 Mmsg2(jcr->errmsg, _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1568 jcr->last_fname, acl_strerror(error));
1569 Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",
1570 jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1571 return bacl_exit_error;
1575 * Validate that the conversion gave us the correct acl type.
1578 case STREAM_ACL_SOLARIS_ACLENT:
1579 if (acl_type(aclp) != ACLENT_T) {
1580 Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1582 return bacl_exit_error;
1585 case STREAM_ACL_SOLARIS_ACE:
1586 if (acl_type(aclp) != ACE_T) {
1587 Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1589 return bacl_exit_error;
1594 * Stream id which doesn't describe the type of acl which is encoded.
1600 * Restore the ACLs, but don't complain about links which really should
1601 * not have attributes, and the file it is linked to may not yet be restored.
1602 * This is only true for the old acl streams as in the new implementation we
1603 * don't save acls of symlinks (which cannot have acls anyhow)
1605 if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1609 return bacl_exit_ok;
1611 Mmsg2(jcr->errmsg, _("acl_set error on file \"%s\": ERR=%s\n"),
1612 jcr->last_fname, acl_strerror(error));
1613 Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",
1614 jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1616 return bacl_exit_error;
1621 return bacl_exit_ok;
1623 return bacl_exit_error;
1624 } /* end switch (stream) */
1627 #else /* HAVE_EXTENDED_ACL */
1630 * Define the supported ACL streams for this OS
1632 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT };
1633 static int os_default_acl_streams[1] = { -1 };
1636 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1637 * There is no need to store those acls as we already store the stat bits too.
1639 static bool acl_is_trivial(int count, aclent_t *entries)
1644 for (n = 0; n < count; n++) {
1647 if (!(ace->a_type == USER_OBJ ||
1648 ace->a_type == GROUP_OBJ ||
1649 ace->a_type == OTHER_OBJ ||
1650 ace->a_type == CLASS_OBJ))
1657 * OS specific functions for handling different types of acl streams.
1659 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1666 n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1667 if (n < MIN_ACL_ENTRIES)
1668 return bacl_exit_error;
1670 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1671 if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1672 if (acl_is_trivial(n, acls)) {
1674 * The ACLs simply reflect the (already known) standard permissions
1675 * So we don't send an ACL stream to the SD.
1678 pm_strcpy(jcr->acl_data->content, "");
1679 jcr->acl_data->content_length = 0;
1680 return bacl_exit_ok;
1683 if ((acl_text = acltotext(acls, n)) != NULL) {
1684 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1685 actuallyfree(acl_text);
1687 return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1690 Mmsg2(jcr->errmsg, _("acltotext error on file \"%s\": ERR=%s\n"),
1691 jcr->last_fname, be.bstrerror());
1692 Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",
1693 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1697 return bacl_exit_error;
1700 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
1706 acls = aclfromtext(jcr->acl_data->content, &n);
1708 Mmsg2(jcr->errmsg, _("aclfromtext error on file \"%s\": ERR=%s\n"),
1709 jcr->last_fname, be.bstrerror());
1710 Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",
1711 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1712 return bacl_exit_error;
1716 * Restore the ACLs, but don't complain about links which really should
1717 * not have attributes, and the file it is linked to may not yet be restored.
1719 if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
1723 return bacl_exit_ok;
1725 Mmsg2(jcr->errmsg, _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
1726 jcr->last_fname, be.bstrerror());
1727 Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
1728 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1730 return bacl_exit_error;
1734 return bacl_exit_ok;
1736 #endif /* HAVE_EXTENDED_ACL */
1739 * For this OS setup the build and parse function pointer to the OS specific functions.
1741 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_acl_streams;
1742 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = solaris_parse_acl_streams;
1744 #endif /* HAVE_SUN_OS */
1745 #endif /* HAVE_ACL */
1748 * Entry points when compiled with support for ACLs on a supported platform.
1752 * Read and send an ACL for the last encountered file.
1754 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1757 * See if we are changing from one device to an other.
1758 * We save the current device we are scanning and compare
1759 * it with the current st_dev in the last stat performed on
1760 * the file we are currently storing.
1762 if (jcr->acl_data->current_dev != ff_pkt->statp.st_dev) {
1764 * Reset the acl save flags.
1766 jcr->acl_data->flags = 0;
1768 jcr->acl_data->flags |= BACL_FLAG_SAVE_NATIVE;
1771 * Save that we started scanning a new filesystem.
1773 jcr->acl_data->current_dev = ff_pkt->statp.st_dev;
1776 #if defined(HAVE_ACL)
1778 * See if the BACL_FLAG_SAVE_NATIVE flag is set which lets us know if we should
1781 if (jcr->acl_data->flags & BACL_FLAG_SAVE_NATIVE) {
1783 * Call the appropriate function.
1785 if (os_build_acl_streams) {
1786 return (*os_build_acl_streams)(jcr, ff_pkt);
1789 return bacl_exit_ok;
1792 return bacl_exit_error;
1795 bacl_exit_code parse_acl_streams(JCR *jcr, int stream)
1800 #if defined(HAVE_ACL)
1801 case STREAM_UNIX_ACCESS_ACL:
1802 case STREAM_UNIX_DEFAULT_ACL:
1804 * Handle legacy ACL streams.
1806 if (os_parse_acl_streams) {
1807 return (*os_parse_acl_streams)(jcr, stream);
1811 if (os_parse_acl_streams) {
1813 * Walk the os_access_acl_streams array with the supported Access ACL streams for this OS.
1815 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1816 if (os_access_acl_streams[cnt] == stream) {
1817 return (*os_parse_acl_streams)(jcr, stream);
1821 * Walk the os_default_acl_streams array with the supported Default ACL streams for this OS.
1823 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1824 if (os_default_acl_streams[cnt] == stream) {
1825 return (*os_parse_acl_streams)(jcr, stream);
1835 Qmsg2(jcr, M_WARNING, 0,
1836 _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
1837 jcr->last_fname, stream);
1838 return bacl_exit_error;