2 Bacula® - The Network Backup Solution
4 Copyright (C) 2004-2012 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Functions to handle ACLs for bacula.
31 * Currently we support the following OSes:
32 * - AIX (pre-5.3 and post 5.3 acls, acl_get and aclx_get interface)
34 * - FreeBSD (POSIX and NFSv4/ZFS acls)
38 * - Solaris (POSIX and NFSv4/ZFS acls)
41 * We handle two different types of ACLs: access and default ACLS.
42 * On most systems that support default ACLs they only apply to directories.
44 * On some systems (eg. linux and FreeBSD) we must obtain the two ACLs
45 * independently, while others (eg. Solaris) provide both in one call.
47 * The Filed saves ACLs in their native format and uses different streams
48 * for all different platforms. Currently we only allow ACLs to be restored
49 * which were saved in the native format of the platform they are extracted
50 * on. Later on we might add conversion functions for mapping from one
51 * platform to an other or allow restores of systems that use the same
54 * Its also interesting to see what the exact format of acl text is on
55 * certain platforms and if they use they same encoding we might allow
56 * different platform streams to be decoded on an other similar platform.
58 * Original written by Preben 'Peppe' Guldberg, December 2004
59 * Major rewrite by Marco van Wieringen, November 2008
60 * Major overhaul by Marco van Wieringen, January 2012
66 #if !defined(HAVE_ACL)
68 * Entry points when compiled without support for ACLs or on an unsupported platform.
70 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
72 return bacl_exit_fatal;
75 bacl_exit_code parse_acl_streams(JCR *jcr,
78 uint32_t content_length)
80 return bacl_exit_fatal;
84 * Send an ACL stream to the SD.
86 static bacl_exit_code send_acl_stream(JCR *jcr, int stream)
88 BSOCK *sd = jcr->store_bsock;
90 #ifdef FD_NO_SEND_TEST
97 if (jcr->acl_data->u.build->content_length <= 0) {
104 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
105 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
107 return bacl_exit_fatal;
111 * Send the buffer to the storage deamon
113 Dmsg1(400, "Backing up ACL <%s>\n", jcr->acl_data->u.build->content);
115 sd->msg = jcr->acl_data->u.build->content;
116 sd->msglen = jcr->acl_data->u.build->content_length + 1;
120 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
122 return bacl_exit_fatal;
125 jcr->JobBytes += sd->msglen;
127 if (!sd->signal(BNET_EOD)) {
128 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
130 return bacl_exit_fatal;
133 Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
138 * First the native ACLs.
140 #if defined(HAVE_ACL)
141 #if defined(HAVE_AIX_OS)
143 #if defined(HAVE_EXTENDED_ACL)
145 #include <sys/access.h>
148 static bool acl_is_trivial(struct acl *acl)
150 return (acl_last(acl) != acl->acl_ext ? false : true);
153 static bool acl_nfs4_is_trivial(nfs4_acl_int_t *acl)
155 return (acl->aclEntryN > 0 ? false : true);
159 * Define the supported ACL streams for this OS
161 static int os_access_acl_streams[3] = {
166 static int os_default_acl_streams[1] = {
170 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
175 size_t aclsize, acltxtsize;
176 bacl_exit_code retval = bacl_exit_error;
177 POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
180 * First see how big the buffers should be.
183 if (aclx_get(jcr->last_fname, GET_ACLINFO_ONLY, &type, NULL, &aclsize, NULL) < 0) {
186 retval = bacl_exit_ok;
190 _("aclx_get error on file \"%s\": ERR=%s\n"),
191 jcr->last_fname, be.bstrerror());
192 Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
193 jcr->last_fname, be.bstrerror());
199 * Make sure the buffers are big enough.
201 aclbuf = check_pool_memory_size(aclbuf, aclsize + 1);
204 * Retrieve the ACL info.
206 if (aclx_get(jcr->last_fname, 0, &type, aclbuf, &aclsize, &mode) < 0) {
209 retval = bacl_exit_ok;
213 _("aclx_get error on file \"%s\": ERR=%s\n"),
214 jcr->last_fname, be.bstrerror());
215 Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
216 jcr->last_fname, be.bstrerror());
222 * See if the acl is non trivial.
226 if (acl_is_trivial((struct acl *)aclbuf)) {
227 retval = bacl_exit_ok;
232 if (acl_nfs4_is_trivial((nfs4_acl_int_t *)aclbuf)) {
233 retval = bacl_exit_ok;
239 _("Unknown acl type encountered on file \"%s\": %ld\n"),
240 jcr->last_fname, type.u64);
241 Dmsg2(100, "Unknown acl type encountered on file \"%s\": %ld\n",
242 jcr->last_fname, type.u64);
247 * We have a non-trivial acl lets convert it into some ASCII form.
249 acltxtsize = sizeof_pool_memory(jcr->acl_data->u.build->content);
250 if (aclx_printStr(jcr->acl_data->u.build->content, &acltxtsize, aclbuf,
251 aclsize, type, jcr->last_fname, 0) < 0) {
255 * Our buffer is not big enough, acltxtsize should be updated with the value
256 * the aclx_printStr really need. So we increase the buffer and try again.
258 jcr->acl_data->u.build->content =
259 check_pool_memory_size(jcr->acl_data->u.build->content, acltxtsize + 1);
260 if (aclx_printStr(jcr->acl_data->u.build->content, &acltxtsize, aclbuf,
261 aclsize, type, jcr->last_fname, 0) < 0) {
263 _("Failed to convert acl into text on file \"%s\"\n"),
265 Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
266 jcr->last_fname, type.u64);
272 _("Failed to convert acl into text on file \"%s\"\n"),
274 Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
275 jcr->last_fname, type.u64);
280 jcr->acl_data->u.build->u.build->content_length = strlen(jcr->acl_data->u.build->content) + 1;
283 retval = send_acl_stream(jcr, STREAM_ACL_AIX_AIXC);
285 retval = send_acl_stream(jcr, STREAM_ACL_AIX_NFS4);
289 free_pool_memory(aclbuf);
294 static bacl_exit_code aix_parse_acl_streams(JCR *jcr,
297 uint32_t content_length)
303 bacl_exit_code retval = bacl_exit_error;
304 POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
307 case STREAM_ACL_AIX_TEXT:
309 * Handle the old stream using the old system call for now.
311 if (acl_put(jcr->last_fname, content, 0) != 0) {
312 retval = bacl_exit_error;
315 retval = bacl_exit_ok;
317 case STREAM_ACL_AIX_AIXC:
320 case STREAM_ACL_AIX_NFS4:
325 } /* end switch (stream) */
328 * Set the acl buffer to an initial size. For now we set it
329 * to the same size as the ASCII representation.
331 aclbuf = check_pool_memory_size(aclbuf, content_length);
332 aclsize = content_length;
333 if (aclx_scanStr(content, aclbuf, &aclsize, type) < 0) {
337 * The buffer isn't big enough. The man page doesn't say that aclsize
338 * is updated to the needed size as what is done with aclx_printStr.
339 * So for now we try to increase the buffer a maximum of 3 times
340 * and retry the conversion.
342 for (cnt = 0; cnt < 3; cnt++) {
343 aclsize = 2 * aclsize;
344 aclbuf = check_pool_memory_size(aclbuf, aclsize);
346 if (aclx_scanStr(content, aclbuf, &aclsize, type) == 0) {
351 * See why we failed this time, ENOSPC retry if max retries not met,
362 _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
363 jcr->last_fname, be.bstrerror());
364 Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
365 jcr->last_fname, be.bstrerror());
372 _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
373 jcr->last_fname, be.bstrerror());
374 Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
375 jcr->last_fname, be.bstrerror());
379 if (aclx_put(jcr->last_fname, SET_ACL, type, aclbuf, aclsize, 0) < 0) {
382 retval = bacl_exit_ok;
386 _("aclx_put error on file \"%s\": ERR=%s\n"),
387 jcr->last_fname, be.bstrerror());
388 Dmsg2(100, "aclx_put error file=%s ERR=%s\n",
389 jcr->last_fname, be.bstrerror());
394 retval = bacl_exit_ok;
397 free_pool_memory(aclbuf);
402 #else /* HAVE_EXTENDED_ACL */
404 #include <sys/access.h>
407 * Define the supported ACL streams for this OS
409 static int os_access_acl_streams[1] = {
412 static int os_default_acl_streams[1] = {
416 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
420 if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
421 jcr->acl_data->u.build->content_length =
422 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
423 actuallyfree(acl_text);
424 return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT);
426 return bacl_exit_error;
429 static bacl_exit_code aix_parse_acl_streams(JCR *jcr,
432 uint32_t content_length)
434 if (acl_put(jcr->last_fname, content, 0) != 0) {
435 return bacl_exit_error;
439 #endif /* HAVE_EXTENDED_ACL */
442 * For this OS setup the build and parse function pointer to the OS specific functions.
444 static bacl_exit_code (*os_build_acl_streams)
445 (JCR *jcr, FF_PKT *ff_pkt) =
446 aix_build_acl_streams;
447 static bacl_exit_code (*os_parse_acl_streams)
448 (JCR *jcr, int stream, char *content, uint32_t content_length) =
449 aix_parse_acl_streams;
451 #elif defined(HAVE_DARWIN_OS) || \
452 defined(HAVE_FREEBSD_OS) || \
453 defined(HAVE_IRIX_OS) || \
454 defined(HAVE_OSF1_OS) || \
455 defined(HAVE_LINUX_OS)
457 #include <sys/types.h>
459 #ifdef HAVE_SYS_ACL_H
462 #error "configure failed to detect availability of sys/acl.h"
466 * On IRIX we can get shortened ACLs
468 #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
469 #define acl_to_text(acl,len) acl_to_short_text((acl), (len))
473 * On Linux we can get numeric and/or shorted ACLs
475 #if defined(HAVE_LINUX_OS)
476 #if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
477 #define BACL_ALTERNATE_TEXT (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
478 #elif defined(BACL_WANT_SHORT_ACLS)
479 #define BACL_ALTERNATE_TEXT TEXT_ABBREVIATE
480 #elif defined(BACL_WANT_NUMERIC_IDS)
481 #define BACL_ALTERNATE_TEXT TEXT_NUMERIC_IDS
483 #ifdef BACL_ALTERNATE_TEXT
484 #include <acl/libacl.h>
485 #define acl_to_text(acl,len) (acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
490 * On FreeBSD we can get numeric ACLs
492 #if defined(HAVE_FREEBSD_OS)
493 #if defined(BACL_WANT_NUMERIC_IDS)
494 #define BACL_ALTERNATE_TEXT ACL_TEXT_NUMERIC_IDS
496 #ifdef BACL_ALTERNATE_TEXT
497 #define acl_to_text(acl,len) (acl_to_text_np((acl), (len), BACL_ALTERNATE_TEXT))
502 * Some generic functions used by multiple OSes.
504 static acl_type_t bac_to_os_acltype(bacl_type acltype)
509 case BACL_TYPE_ACCESS:
510 ostype = ACL_TYPE_ACCESS;
512 case BACL_TYPE_DEFAULT:
513 ostype = ACL_TYPE_DEFAULT;
515 #ifdef HAVE_ACL_TYPE_NFS4
517 * FreeBSD has an additional acl type named ACL_TYPE_NFS4.
520 ostype = ACL_TYPE_NFS4;
523 #ifdef HAVE_ACL_TYPE_DEFAULT_DIR
524 case BACL_TYPE_DEFAULT_DIR:
526 * TRU64 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
528 ostype = ACL_TYPE_DEFAULT_DIR;
531 #ifdef HAVE_ACL_TYPE_EXTENDED
532 case BACL_TYPE_EXTENDED:
534 * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
536 ostype = ACL_TYPE_EXTENDED;
541 * This should never happen, as the per OS version function only tries acl
542 * types supported on a certain platform.
544 ostype = (acl_type_t)ACL_TYPE_NONE;
550 static int acl_count_entries(acl_t acl)
553 #if defined(HAVE_FREEBSD_OS) || \
554 defined(HAVE_LINUX_OS)
558 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
559 while (entry_available == 1) {
561 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
563 #elif defined(HAVE_IRIX_OS)
564 count = acl->acl_cnt;
565 #elif defined(HAVE_OSF1_OS)
566 count = acl->acl_num;
567 #elif defined(HAVE_DARWIN_OS)
571 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
572 while (entry_available == 0) {
574 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
580 #if !defined(HAVE_DARWIN_OS)
582 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
583 * There is no need to store those acls as we already store the stat bits too.
585 static bool acl_is_trivial(acl_t acl)
588 * acl is trivial if it has only the following entries:
595 #if defined(HAVE_FREEBSD_OS) || \
596 defined(HAVE_LINUX_OS)
599 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
600 while (entry_available == 1) {
602 * Get the tag type of this acl entry.
603 * If we fail to get the tagtype we call the acl non-trivial.
605 if (acl_get_tag_type(ace, &tag) < 0)
608 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
610 if (tag != ACL_USER_OBJ &&
611 tag != ACL_GROUP_OBJ &&
614 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
617 #elif defined(HAVE_IRIX_OS)
620 for (n = 0; n < acl->acl_cnt; n++) {
621 ace = &acl->acl_entry[n];
625 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
627 if (tag != ACL_USER_OBJ &&
628 tag != ACL_GROUP_OBJ &&
629 tag != ACL_OTHER_OBJ)
633 #elif defined(HAVE_OSF1_OS)
636 ace = acl->acl_first;
637 count = acl->acl_num;
640 tag = ace->entry->acl_type;
642 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
644 if (tag != ACL_USER_OBJ &&
645 tag != ACL_GROUP_OBJ &&
649 * On Tru64, perm can also contain non-standard bits such as
650 * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
652 if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
663 * Generic wrapper around acl_get_file call.
665 static bacl_exit_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
671 bacl_exit_code retval = bacl_exit_ok;
673 ostype = bac_to_os_acltype(acltype);
674 acl = acl_get_file(jcr->last_fname, ostype);
677 * From observation, IRIX's acl_get_file() seems to return a
678 * non-NULL acl with a count field of -1 when a file has no ACL
679 * defined, while IRIX's acl_to_text() returns NULL when presented
682 * For all other implmentations we check if there are more then
683 * zero entries in the acl returned.
685 if (acl_count_entries(acl) <= 0) {
690 * Make sure this is not just a trivial ACL.
692 #if !defined(HAVE_DARWIN_OS)
693 if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
695 * The ACLs simply reflect the (already known) standard permissions
696 * So we don't send an ACL stream to the SD.
701 #if defined(HAVE_FREEBSD_OS) && defined(_PC_ACL_NFS4)
702 if (acltype == BACL_TYPE_NFS4) {
704 if (acl_is_trivial_np(acl, &trivial) == 0) {
707 * The ACLs simply reflect the (already known) standard permissions
708 * So we don't send an ACL stream to the SD.
717 * Convert the internal acl representation into a text representation.
719 if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
720 jcr->acl_data->u.build->content_length =
721 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
728 _("acl_to_text error on file \"%s\": ERR=%s\n"),
729 jcr->last_fname, be.bstrerror());
730 Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",
731 jcr->last_fname, be.bstrerror());
733 retval = bacl_exit_error;
737 * Handle errors gracefully.
740 #if defined(BACL_ENOTSUP)
743 * If the filesystem reports it doesn't support ACLs we clear the
744 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
745 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
746 * when we change from one filesystem to an other.
748 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
754 /* Some real error */
756 _("acl_get_file error on file \"%s\": ERR=%s\n"),
757 jcr->last_fname, be.bstrerror());
758 Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",
759 jcr->last_fname, be.bstrerror());
761 retval = bacl_exit_error;
770 pm_strcpy(jcr->acl_data->u.build->content, "");
771 jcr->acl_data->u.build->content_length = 0;
776 * Generic wrapper around acl_set_file call.
778 static bacl_exit_code generic_set_acl_on_os(JCR *jcr,
781 uint32_t content_length)
788 * If we get empty default ACLs, clear ACLs now
790 ostype = bac_to_os_acltype(acltype);
791 if (ostype == ACL_TYPE_DEFAULT && strlen(content) == 0) {
792 if (acl_delete_def_file(jcr->last_fname) == 0) {
798 #if defined(BACL_ENOTSUP)
801 * If the filesystem reports it doesn't support ACLs we clear the
802 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
803 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
804 * when we change from one filesystem to an other.
806 jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
808 _("acl_delete_def_file error on file \"%s\": filesystem doesn't support ACLs\n"),
810 return bacl_exit_error;
814 _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
815 jcr->last_fname, be.bstrerror());
816 return bacl_exit_error;
820 acl = acl_from_text(content);
823 _("acl_from_text error on file \"%s\": ERR=%s\n"),
824 jcr->last_fname, be.bstrerror());
825 Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",
826 content, jcr->last_fname, be.bstrerror());
827 return bacl_exit_error;
830 #ifndef HAVE_FREEBSD_OS
832 * FreeBSD always fails acl_valid() - at least on valid input...
833 * As it does the right thing, given valid input, just ignore acl_valid().
835 if (acl_valid(acl) != 0) {
837 _("acl_valid error on file \"%s\": ERR=%s\n"),
838 jcr->last_fname, be.bstrerror());
839 Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",
840 content, jcr->last_fname, be.bstrerror());
842 return bacl_exit_error;
847 * Restore the ACLs, but don't complain about links which really should
848 * not have attributes, and the file it is linked to may not yet be restored.
849 * This is only true for the old acl streams as in the new implementation we
850 * don't save acls of symlinks (which cannot have acls anyhow)
852 if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
857 #if defined(BACL_ENOTSUP)
860 * If the filesystem reports it doesn't support ACLs we clear the
861 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
862 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
863 * when we change from one filesystem to an other.
865 jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
867 _("acl_set_file error on file \"%s\": filesystem doesn't support ACLs\n"),
869 Dmsg2(100, "acl_set_file error acl=%s file=%s filesystem doesn't support ACLs\n",
870 content, jcr->last_fname);
872 return bacl_exit_error;
876 _("acl_set_file error on file \"%s\": ERR=%s\n"),
877 jcr->last_fname, be.bstrerror());
878 Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
879 content, jcr->last_fname, be.bstrerror());
881 return bacl_exit_error;
889 * OS specific functions for handling different types of acl streams.
891 #if defined(HAVE_DARWIN_OS)
893 * Define the supported ACL streams for this OS
895 static int os_access_acl_streams[1] = {
896 STREAM_ACL_DARWIN_ACCESS_ACL
898 static int os_default_acl_streams[1] = {
902 static bacl_exit_code darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
904 #if defined(HAVE_ACL_TYPE_EXTENDED)
906 * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
907 * and acl_get_file (name, ACL_TYPE_DEFAULT)
908 * always return NULL / EINVAL. There is no point in making
909 * these two useless calls. The real ACL is retrieved through
910 * acl_get_file (name, ACL_TYPE_EXTENDED).
912 * Read access ACLs for files, dirs and links
914 if (generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED) == bacl_exit_fatal)
915 return bacl_exit_fatal;
918 * Read access ACLs for files, dirs and links
920 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
921 return bacl_exit_fatal;
924 if (jcr->acl_data->u.build->content_length > 0) {
925 return send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL);
930 static bacl_exit_code darwin_parse_acl_streams(JCR *jcr,
933 uint32_t content_length)
935 #if defined(HAVE_ACL_TYPE_EXTENDED)
936 return generic_set_acl_on_os(jcr, BACL_TYPE_EXTENDED, content, content_length);
938 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
943 * For this OS setup the build and parse function pointer to the OS specific functions.
945 static bacl_exit_code (*os_build_acl_streams)
946 (JCR *jcr, FF_PKT *ff_pkt) =
947 darwin_build_acl_streams;
948 static bacl_exit_code (*os_parse_acl_streams)
949 (JCR *jcr, int stream, char *content, uint32_t content_length) =
950 darwin_parse_acl_streams;
952 #elif defined(HAVE_FREEBSD_OS)
954 * Define the supported ACL streams for these OSes
956 static int os_access_acl_streams[2] = {
957 STREAM_ACL_FREEBSD_ACCESS_ACL,
958 STREAM_ACL_FREEBSD_NFS4_ACL
960 static int os_default_acl_streams[1] = {
961 STREAM_ACL_FREEBSD_DEFAULT_ACL
964 static bacl_exit_code freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
967 bacl_type acltype = BACL_TYPE_NONE;
970 #if defined(_PC_ACL_NFS4)
972 * See if filesystem supports NFS4 acls.
974 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
975 switch (acl_enabled) {
982 _("pathconf error on file \"%s\": ERR=%s\n"),
983 jcr->last_fname, be.bstrerror());
984 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
985 jcr->last_fname, be.bstrerror());
986 return bacl_exit_error;
991 acltype = BACL_TYPE_NFS4;
996 if (acl_enabled == 0) {
998 * See if filesystem supports POSIX acls.
1000 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
1001 switch (acl_enabled) {
1005 return bacl_exit_ok;
1008 _("pathconf error on file \"%s\": ERR=%s\n"),
1009 jcr->last_fname, be.bstrerror());
1010 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
1011 jcr->last_fname, be.bstrerror());
1012 return bacl_exit_error;
1017 acltype = BACL_TYPE_ACCESS;
1023 * If the filesystem reports it doesn't support ACLs we clear the
1024 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1025 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1026 * when we change from one filesystem to an other.
1028 if (acl_enabled == 0) {
1029 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1030 pm_strcpy(jcr->acl_data->u.build->content, "");
1031 jcr->acl_data->u.build->content_length = 0;
1032 return bacl_exit_ok;
1036 * Based on the supported ACLs retrieve and store them.
1039 case BACL_TYPE_NFS4:
1041 * Read NFS4 ACLs for files, dirs and links
1043 if (generic_get_acl_from_os(jcr, BACL_TYPE_NFS4) == bacl_exit_fatal)
1044 return bacl_exit_fatal;
1046 if (jcr->acl_data->u.build->content_length > 0) {
1047 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_NFS4_ACL) == bacl_exit_fatal)
1048 return bacl_exit_fatal;
1051 case BACL_TYPE_ACCESS:
1053 * Read access ACLs for files, dirs and links
1055 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1056 return bacl_exit_fatal;
1058 if (jcr->acl_data->u.build->content_length > 0) {
1059 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_ACCESS_ACL) == bacl_exit_fatal)
1060 return bacl_exit_fatal;
1064 * Directories can have default ACLs too
1066 if (ff_pkt->type == FT_DIREND) {
1067 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
1068 return bacl_exit_fatal;
1069 if (jcr->acl_data->u.build->content_length > 0) {
1070 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_DEFAULT_ACL) == bacl_exit_fatal)
1071 return bacl_exit_fatal;
1079 return bacl_exit_ok;
1082 static bacl_exit_code freebsd_parse_acl_streams(JCR *jcr,
1085 uint32_t content_length)
1087 int acl_enabled = 0;
1088 const char *acl_type_name;
1092 * First make sure the filesystem supports acls.
1095 case STREAM_UNIX_ACCESS_ACL:
1096 case STREAM_ACL_FREEBSD_ACCESS_ACL:
1097 case STREAM_UNIX_DEFAULT_ACL:
1098 case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1099 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
1100 acl_type_name = "POSIX";
1102 case STREAM_ACL_FREEBSD_NFS4_ACL:
1103 #if defined(_PC_ACL_NFS4)
1104 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
1106 acl_type_name = "NFS4";
1109 acl_type_name = "unknown";
1113 switch (acl_enabled) {
1117 return bacl_exit_ok;
1120 _("pathconf error on file \"%s\": ERR=%s\n"),
1121 jcr->last_fname, be.bstrerror());
1122 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1123 content, jcr->last_fname, be.bstrerror());
1124 return bacl_exit_error;
1128 * If the filesystem reports it doesn't support ACLs we clear the
1129 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
1130 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
1131 * when we change from one filesystem to an other.
1133 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1135 _("Trying to restore acl on file \"%s\" on filesystem without %s acl support\n"),
1136 jcr->last_fname, acl_type_name);
1137 return bacl_exit_error;
1146 case STREAM_UNIX_ACCESS_ACL:
1147 case STREAM_ACL_FREEBSD_ACCESS_ACL:
1148 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1149 case STREAM_UNIX_DEFAULT_ACL:
1150 case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1151 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1152 case STREAM_ACL_FREEBSD_NFS4_ACL:
1153 return generic_set_acl_on_os(jcr, BACL_TYPE_NFS4, content, content_length);
1157 return bacl_exit_error;
1161 * For this OSes setup the build and parse function pointer to the OS specific functions.
1163 static bacl_exit_code (*os_build_acl_streams)
1164 (JCR *jcr, FF_PKT *ff_pkt) =
1165 freebsd_build_acl_streams;
1166 static bacl_exit_code (*os_parse_acl_streams)
1167 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1168 freebsd_parse_acl_streams;
1170 #elif defined(HAVE_IRIX_OS) || \
1171 defined(HAVE_LINUX_OS)
1173 * Define the supported ACL streams for these OSes
1175 #if defined(HAVE_IRIX_OS)
1176 static int os_access_acl_streams[1] = {
1177 STREAM_ACL_IRIX_ACCESS_ACL
1179 static int os_default_acl_streams[1] = {
1180 STREAM_ACL_IRIX_DEFAULT_ACL
1182 #elif defined(HAVE_LINUX_OS)
1183 static int os_access_acl_streams[1] = {
1184 STREAM_ACL_LINUX_ACCESS_ACL
1186 static int os_default_acl_streams[1] = {
1187 STREAM_ACL_LINUX_DEFAULT_ACL
1191 static bacl_exit_code generic_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1194 * Read access ACLs for files, dirs and links
1196 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1197 return bacl_exit_fatal;
1199 if (jcr->acl_data->u.build->content_length > 0) {
1200 if (send_acl_stream(jcr, os_access_acl_streams[0]) == bacl_exit_fatal)
1201 return bacl_exit_fatal;
1205 * Directories can have default ACLs too
1207 if (ff_pkt->type == FT_DIREND) {
1208 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
1209 return bacl_exit_fatal;
1210 if (jcr->acl_data->u.build->content_length > 0) {
1211 if (send_acl_stream(jcr, os_default_acl_streams[0]) == bacl_exit_fatal)
1212 return bacl_exit_fatal;
1215 return bacl_exit_ok;
1218 static bacl_exit_code generic_parse_acl_streams(JCR *jcr,
1221 uint32_t content_length)
1226 case STREAM_UNIX_ACCESS_ACL:
1227 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1228 case STREAM_UNIX_DEFAULT_ACL:
1229 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1232 * See what type of acl it is.
1234 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1235 if (os_access_acl_streams[cnt] == stream) {
1236 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1239 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1240 if (os_default_acl_streams[cnt] == stream) {
1241 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1246 return bacl_exit_error;
1250 * For this OSes setup the build and parse function pointer to the OS specific functions.
1252 static bacl_exit_code (*os_build_acl_streams)
1253 (JCR *jcr, FF_PKT *ff_pkt) =
1254 generic_build_acl_streams;
1255 static bacl_exit_code (*os_parse_acl_streams)
1256 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1257 generic_parse_acl_streams;
1259 #elif defined(HAVE_OSF1_OS)
1262 * Define the supported ACL streams for this OS
1264 static int os_access_acl_streams[1] = {
1265 STREAM_ACL_TRU64_ACCESS_ACL
1267 static int os_default_acl_streams[2] = {
1268 STREAM_ACL_TRU64_DEFAULT_ACL,
1269 STREAM_ACL_TRU64_DEFAULT_DIR_ACL
1272 static bacl_exit_code tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1275 * Read access ACLs for files, dirs and links
1277 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal) {
1278 return bacl_exit_error;
1279 if (jcr->acl_data->u.build->content_length > 0) {
1280 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL))
1281 return bacl_exit_error;
1284 * Directories can have default ACLs too
1286 if (ff_pkt->type == FT_DIREND) {
1287 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal) {
1288 return bacl_exit_error;
1289 if (jcr->acl_data->u.build->content_length > 0) {
1290 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL))
1291 return bacl_exit_error;
1294 * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
1295 * This is an inherited acl for all subdirs.
1296 * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
1297 * Section 21.5 Default ACLs
1299 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR) == bacl_exit_fatal) {
1300 return bacl_exit_error;
1301 if (jcr->acl_data->u.build->content_length > 0) {
1302 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL))
1303 return bacl_exit_error;
1306 return bacl_exit_ok;
1309 static bacl_exit_code tru64_parse_acl_streams(JCR *jcr,
1312 uint32_t content_length)
1315 case STREAM_UNIX_ACCESS_ACL:
1316 case STREAM_ACL_TRU64_ACCESS_ACL:
1317 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1318 case STREAM_UNIX_DEFAULT_ACL:
1319 case STREAM_ACL_TRU64_DEFAULT_ACL:
1320 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1321 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
1322 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR, content, content_length);
1326 * For this OS setup the build and parse function pointer to the OS specific functions.
1328 static bacl_exit_code (*os_build_acl_streams)
1329 (JCR *jcr, FF_PKT *ff_pkt) =
1330 tru64_build_acl_streams;
1331 static bacl_exit_code (*os_parse_acl_streams)
1332 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1333 tru64_parse_acl_streams;
1337 #elif defined(HAVE_HPUX_OS)
1338 #ifdef HAVE_SYS_ACL_H
1339 #include <sys/acl.h>
1341 #error "configure failed to detect availability of sys/acl.h"
1347 * Define the supported ACL streams for this OS
1349 static int os_access_acl_streams[1] = {
1350 STREAM_ACL_HPUX_ACL_ENTRY
1352 static int os_default_acl_streams[1] = {
1357 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1358 * There is no need to store those acls as we already store the stat bits too.
1360 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
1363 struct acl_entry ace
1365 for (n = 0; n < count; n++) {
1368 * See if this acl just is the stat mode in acl form.
1370 if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
1371 (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
1372 (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
1379 * OS specific functions for handling different types of acl streams.
1381 static bacl_exit_code hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1384 struct acl_entry acls[NACLENTRIES];
1388 if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
1390 #if defined(BACL_ENOTSUP)
1393 * Not supported, just pretend there is nothing to see
1395 * If the filesystem reports it doesn't support ACLs we clear the
1396 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1397 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1398 * when we change from one filesystem to an other.
1400 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1401 pm_strcpy(jcr->acl_data->u.build->content, "");
1402 jcr->acl_data->u.build->content_length = 0;
1403 return bacl_exit_ok;
1406 pm_strcpy(jcr->acl_data->u.build->content, "");
1407 jcr->acl_data->u.build->content_length = 0;
1408 return bacl_exit_ok;
1411 _("getacl error on file \"%s\": ERR=%s\n"),
1412 jcr->last_fname, be.bstrerror());
1413 Dmsg2(100, "getacl error file=%s ERR=%s\n",
1414 jcr->last_fname, be.bstrerror());
1416 pm_strcpy(jcr->acl_data->u.build->content, "");
1417 jcr->acl_data->u.build->content_length = 0;
1418 return bacl_exit_error;
1422 pm_strcpy(jcr->acl_data->u.build->content, "");
1423 jcr->acl_data->u.build->content_length = 0;
1424 return bacl_exit_ok;
1426 if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
1427 if (acl_is_trivial(n, acls, ff_pkt->statp)) {
1429 * The ACLs simply reflect the (already known) standard permissions
1430 * So we don't send an ACL stream to the SD.
1432 pm_strcpy(jcr->acl_data->u.build->content, "");
1433 jcr->acl_data->u.build->content_length = 0;
1434 return bacl_exit_ok;
1436 if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
1437 jcr->acl_data->u.build->content_length =
1438 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
1439 actuallyfree(acl_text);
1441 return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
1444 _("acltostr error on file \"%s\": ERR=%s\n"),
1445 jcr->last_fname, be.bstrerror());
1446 Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",
1447 jcr->acl_data->u.build->content, jcr->last_fname, be.bstrerror());
1448 return bacl_exit_error;
1450 return bacl_exit_error;
1453 static bacl_exit_code hpux_parse_acl_streams(JCR *jcr,
1456 uint32_t content_length)
1459 struct acl_entry acls[NACLENTRIES];
1462 n = strtoacl(content, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
1465 _("strtoacl error on file \"%s\": ERR=%s\n"),
1466 jcr->last_fname, be.bstrerror());
1467 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
1468 content, jcr->last_fname, be.bstrerror());
1469 return bacl_exit_error;
1471 if (strtoacl(content, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
1473 _("strtoacl error on file \"%s\": ERR=%s\n"),
1474 jcr->last_fname, be.bstrerror());
1475 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
1476 content, jcr->last_fname, be.bstrerror());
1478 return bacl_exit_error;
1481 * Restore the ACLs, but don't complain about links which really should
1482 * not have attributes, and the file it is linked to may not yet be restored.
1483 * This is only true for the old acl streams as in the new implementation we
1484 * don't save acls of symlinks (which cannot have acls anyhow)
1486 if (setacl(jcr->last_fname, n, acls) != 0 &&
1487 jcr->last_type != FT_LNK) {
1490 return bacl_exit_ok;
1491 #if defined(BACL_ENOTSUP)
1494 * If the filesystem reports it doesn't support ACLs we clear the
1495 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
1496 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
1497 * when we change from one filesystem to an other.
1499 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1501 _("setacl error on file \"%s\": filesystem doesn't support ACLs\n"),
1503 Dmsg2(100, "setacl error acl=%s file=%s filesystem doesn't support ACLs\n",
1504 content, jcr->last_fname);
1505 return bacl_exit_error;
1509 _("setacl error on file \"%s\": ERR=%s\n"),
1510 jcr->last_fname, be.bstrerror());
1511 Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
1512 content, jcr->last_fname, be.bstrerror());
1513 return bacl_exit_error;
1516 return bacl_exit_ok;
1520 * For this OS setup the build and parse function pointer to the OS specific functions.
1522 static bacl_exit_code (*os_build_acl_streams)
1523 (JCR *jcr, FF_PKT *ff_pkt) =
1524 hpux_build_acl_streams;
1525 static bacl_exit_code (*os_parse_acl_streams)
1526 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1527 hpux_parse_acl_streams;
1529 #elif defined(HAVE_SUN_OS)
1530 #ifdef HAVE_SYS_ACL_H
1531 #include <sys/acl.h>
1533 #error "configure failed to detect availability of sys/acl.h"
1536 #if defined(HAVE_EXTENDED_ACL)
1538 * We define some internals of the Solaris acl libs here as those
1539 * are not exposed yet. Probably because they want us to see the
1540 * acls as opague data. But as we need to support different platforms
1541 * and versions of Solaris we need to expose some data to be able
1542 * to determine the type of acl used to stuff it into the correct
1543 * data stream. I know this is far from portable, but maybe the
1544 * proper interface is exposed later on and we can get ride of
1545 * this kludge. Newer versions of Solaris include sys/acl_impl.h
1546 * which has implementation details of acls, if thats included we
1547 * don't have to define it ourself.
1549 #if !defined(_SYS_ACL_IMPL_H)
1550 typedef enum acl_type {
1557 * Two external references to functions in the libsec library function not in current include files.
1560 int acl_type(acl_t *);
1561 char *acl_strerror(int);
1565 * Define the supported ACL streams for this OS
1567 static int os_access_acl_streams[2] = {
1568 STREAM_ACL_SOLARIS_ACLENT,
1569 STREAM_ACL_SOLARIS_ACE
1571 static int os_default_acl_streams[1] = {
1576 * As the new libsec interface with acl_totext and acl_fromtext also handles
1577 * the old format from acltotext we can use the new functions even
1578 * for acls retrieved and stored in the database with older fd versions. If the
1579 * new interface is not defined (Solaris 9 and older we fall back to the old code)
1581 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1583 int acl_enabled, flags;
1586 bacl_exit_code stream_status = bacl_exit_error;
1590 * See if filesystem supports acls.
1592 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1593 switch (acl_enabled) {
1596 * If the filesystem reports it doesn't support ACLs we clear the
1597 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1598 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1599 * when we change from one filesystem to an other.
1601 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1602 pm_strcpy(jcr->acl_data->u.build->content, "");
1603 jcr->acl_data->u.build->content_length = 0;
1604 return bacl_exit_ok;
1608 return bacl_exit_ok;
1611 _("pathconf error on file \"%s\": ERR=%s\n"),
1612 jcr->last_fname, be.bstrerror());
1613 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
1614 jcr->last_fname, be.bstrerror());
1615 return bacl_exit_error;
1622 * Get ACL info: don't bother allocating space if there is only a trivial ACL.
1624 if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
1627 return bacl_exit_ok;
1630 _("acl_get error on file \"%s\": ERR=%s\n"),
1631 jcr->last_fname, acl_strerror(errno));
1632 Dmsg2(100, "acl_get error file=%s ERR=%s\n",
1633 jcr->last_fname, acl_strerror(errno));
1634 return bacl_exit_error;
1640 * The ACLs simply reflect the (already known) standard permissions
1641 * So we don't send an ACL stream to the SD.
1643 pm_strcpy(jcr->acl_data->u.build->content, "");
1644 jcr->acl_data->u.build->content_length = 0;
1645 return bacl_exit_ok;
1648 #if defined(ACL_SID_FMT)
1650 * New format flag added in newer Solaris versions.
1652 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
1654 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
1655 #endif /* ACL_SID_FMT */
1657 if ((acl_text = acl_totext(aclp, flags)) != NULL) {
1658 jcr->acl_data->u.build->content_length =
1659 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
1660 actuallyfree(acl_text);
1662 switch (acl_type(aclp)) {
1664 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1667 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE);
1675 return stream_status;
1678 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr,
1681 uint32_t content_length)
1684 int acl_enabled, error;
1688 case STREAM_UNIX_ACCESS_ACL:
1689 case STREAM_ACL_SOLARIS_ACLENT:
1690 case STREAM_ACL_SOLARIS_ACE:
1692 * First make sure the filesystem supports acls.
1694 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1695 switch (acl_enabled) {
1698 * If the filesystem reports it doesn't support ACLs we clear the
1699 * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
1700 * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
1701 * when we change from one filesystem to an other.
1703 jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
1705 _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
1707 return bacl_exit_error;
1711 return bacl_exit_ok;
1714 _("pathconf error on file \"%s\": ERR=%s\n"),
1715 jcr->last_fname, be.bstrerror());
1716 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1717 content, jcr->last_fname, be.bstrerror());
1718 return bacl_exit_error;
1722 * On a filesystem with ACL support make sure this particular ACL type can be restored.
1725 case STREAM_ACL_SOLARIS_ACLENT:
1727 * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
1729 if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
1731 _("Trying to restore acl on file \"%s\" on filesystem without aclent acl support\n"),
1733 return bacl_exit_error;
1736 case STREAM_ACL_SOLARIS_ACE:
1738 * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
1740 if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
1742 _("Trying to restore acl on file \"%s\" on filesystem without ace acl support\n"),
1744 return bacl_exit_error;
1749 * Stream id which doesn't describe the type of acl which is encoded.
1756 if ((error = acl_fromtext(content, &aclp)) != 0) {
1758 _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1759 jcr->last_fname, acl_strerror(error));
1760 Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",
1761 content, jcr->last_fname, acl_strerror(error));
1762 return bacl_exit_error;
1766 * Validate that the conversion gave us the correct acl type.
1769 case STREAM_ACL_SOLARIS_ACLENT:
1770 if (acl_type(aclp) != ACLENT_T) {
1772 _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1774 return bacl_exit_error;
1777 case STREAM_ACL_SOLARIS_ACE:
1778 if (acl_type(aclp) != ACE_T) {
1780 _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1782 return bacl_exit_error;
1787 * Stream id which doesn't describe the type of acl which is encoded.
1793 * Restore the ACLs, but don't complain about links which really should
1794 * not have attributes, and the file it is linked to may not yet be restored.
1795 * This is only true for the old acl streams as in the new implementation we
1796 * don't save acls of symlinks (which cannot have acls anyhow)
1798 if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1802 return bacl_exit_ok;
1805 _("acl_set error on file \"%s\": ERR=%s\n"),
1806 jcr->last_fname, acl_strerror(error));
1807 Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",
1808 content, jcr->last_fname, acl_strerror(error));
1810 return bacl_exit_error;
1815 return bacl_exit_ok;
1817 return bacl_exit_error;
1818 } /* end switch (stream) */
1821 #else /* HAVE_EXTENDED_ACL */
1824 * Define the supported ACL streams for this OS
1826 static int os_access_acl_streams[1] = {
1827 STREAM_ACL_SOLARIS_ACLENT
1829 static int os_default_acl_streams[1] = {
1834 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1835 * There is no need to store those acls as we already store the stat bits too.
1837 static bool acl_is_trivial(int count, aclent_t *entries)
1842 for (n = 0; n < count; n++) {
1845 if (!(ace->a_type == USER_OBJ ||
1846 ace->a_type == GROUP_OBJ ||
1847 ace->a_type == OTHER_OBJ ||
1848 ace->a_type == CLASS_OBJ))
1855 * OS specific functions for handling different types of acl streams.
1857 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1864 n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1865 if (n < MIN_ACL_ENTRIES)
1866 return bacl_exit_error;
1868 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1869 if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1870 if (acl_is_trivial(n, acls)) {
1872 * The ACLs simply reflect the (already known) standard permissions
1873 * So we don't send an ACL stream to the SD.
1876 pm_strcpy(jcr->acl_data->u.build->content, "");
1877 jcr->acl_data->u.build->content_length = 0;
1878 return bacl_exit_ok;
1881 if ((acl_text = acltotext(acls, n)) != NULL) {
1882 jcr->acl_data->u.build->content_length =
1883 pm_strcpy(jcr->acl_data->u.build->content, acl_text);
1884 actuallyfree(acl_text);
1886 return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1890 _("acltotext error on file \"%s\": ERR=%s\n"),
1891 jcr->last_fname, be.bstrerror());
1892 Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",
1893 jcr->acl_data->u.build->content, jcr->last_fname, be.bstrerror());
1897 return bacl_exit_error;
1900 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr,
1903 uint32_t content_length)
1909 acls = aclfromtext(content, &n);
1912 _("aclfromtext error on file \"%s\": ERR=%s\n"),
1913 jcr->last_fname, be.bstrerror());
1914 Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",
1915 content, jcr->last_fname, be.bstrerror());
1916 return bacl_exit_error;
1920 * Restore the ACLs, but don't complain about links which really should
1921 * not have attributes, and the file it is linked to may not yet be restored.
1923 if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
1927 return bacl_exit_ok;
1930 _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
1931 jcr->last_fname, be.bstrerror());
1932 Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
1933 content, jcr->last_fname, be.bstrerror());
1935 return bacl_exit_error;
1939 return bacl_exit_ok;
1941 #endif /* HAVE_EXTENDED_ACL */
1944 * For this OS setup the build and parse function pointer to the OS specific functions.
1946 static bacl_exit_code (*os_build_acl_streams)
1947 (JCR *jcr, FF_PKT *ff_pkt) =
1948 solaris_build_acl_streams;
1949 static bacl_exit_code (*os_parse_acl_streams)
1950 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1951 solaris_parse_acl_streams;
1953 #endif /* HAVE_SUN_OS */
1954 #endif /* HAVE_ACL */
1957 * Entry points when compiled with support for ACLs on a supported platform.
1961 * Read and send an ACL for the last encountered file.
1963 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1966 * See if we are changing from one device to an other.
1967 * We save the current device we are restoring to and compare
1968 * it with the current st_dev in the last stat performed on
1969 * the file we are currently storing.
1971 if (jcr->acl_data->current_dev != ff_pkt->statp.st_dev) {
1973 * Reset the acl save flags.
1975 jcr->acl_data->flags = 0;
1977 jcr->acl_data->flags |= BACL_FLAG_SAVE_NATIVE;
1980 * Save that we started scanning a new filesystem.
1982 jcr->acl_data->current_dev = ff_pkt->statp.st_dev;
1985 #if defined(HAVE_ACL)
1987 * See if the BACL_FLAG_SAVE_NATIVE flag is set which lets us know if we should
1990 if (jcr->acl_data->flags & BACL_FLAG_SAVE_NATIVE) {
1992 * Call the appropriate function.
1994 if (os_build_acl_streams) {
1995 return os_build_acl_streams(jcr, ff_pkt);
1998 return bacl_exit_ok;
2001 return bacl_exit_error;
2004 bacl_exit_code parse_acl_streams(JCR *jcr,
2007 uint32_t content_length)
2015 * See if we are changing from one device to an other.
2016 * We save the current device we are restoring to and compare
2017 * it with the current st_dev in the last stat performed on
2018 * the file we are currently restoring.
2020 ret = lstat(jcr->last_fname, &st);
2025 return bacl_exit_ok;
2028 _("Unable to stat file \"%s\": ERR=%s\n"),
2029 jcr->last_fname, be.bstrerror());
2030 Dmsg2(100, "Unable to stat file \"%s\": ERR=%s\n",
2031 jcr->last_fname, be.bstrerror());
2032 return bacl_exit_error;
2038 if (jcr->acl_data->current_dev != st.st_dev) {
2040 * Reset the acl save flags.
2042 jcr->acl_data->flags = 0;
2043 jcr->acl_data->flags |= BACL_FLAG_RESTORE_NATIVE;
2046 * Save that we started restoring to a new filesystem.
2048 jcr->acl_data->current_dev = st.st_dev;
2052 #if defined(HAVE_ACL)
2053 case STREAM_UNIX_ACCESS_ACL:
2054 case STREAM_UNIX_DEFAULT_ACL:
2056 * Handle legacy ACL streams.
2058 if ((jcr->acl_data->flags & BACL_FLAG_RESTORE_NATIVE) && os_parse_acl_streams) {
2059 return os_parse_acl_streams(jcr, stream, content, content_length);
2062 * Increment error count but don't log an error again for the same filesystem.
2064 jcr->acl_data->u.parse->nr_errors++;
2065 return bacl_exit_ok;
2069 if ((jcr->acl_data->flags & BACL_FLAG_RESTORE_NATIVE) && os_parse_acl_streams) {
2071 * Walk the os_access_acl_streams array with the supported Access ACL streams for this OS.
2073 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
2074 if (os_access_acl_streams[cnt] == stream) {
2075 return os_parse_acl_streams(jcr, stream, content, content_length);
2079 * Walk the os_default_acl_streams array with the supported Default ACL streams for this OS.
2081 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
2082 if (os_default_acl_streams[cnt] == stream) {
2083 return os_parse_acl_streams(jcr, stream, content, content_length);
2088 * Increment error count but don't log an error again for the same filesystem.
2090 jcr->acl_data->u.parse->nr_errors++;
2091 return bacl_exit_ok;
2099 Qmsg2(jcr, M_WARNING, 0,
2100 _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
2101 jcr->last_fname, stream);
2102 return bacl_exit_error;