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 * 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 MMIV
59 * Major rewrite by Marco van Wieringen, November MMVIII
65 #if !defined(HAVE_ACL)
67 * Entry points when compiled without support for ACLs or on an unsupported platform.
69 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
71 return bacl_exit_fatal;
74 bacl_exit_code parse_acl_streams(JCR *jcr, int stream)
76 return bacl_exit_fatal;
80 * Send an ACL stream to the SD.
82 static bacl_exit_code send_acl_stream(JCR *jcr, int stream)
84 BSOCK *sd = jcr->store_bsock;
86 #ifdef FD_NO_SEND_TEST
93 if (jcr->acl_data->content_length <= 0) {
100 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
101 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
103 return bacl_exit_fatal;
107 * Send the buffer to the storage deamon
109 Dmsg1(400, "Backing up ACL <%s>\n", jcr->acl_data->content);
111 sd->msg = jcr->acl_data->content;
112 sd->msglen = jcr->acl_data->content_length + 1;
116 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
118 return bacl_exit_fatal;
121 jcr->JobBytes += sd->msglen;
123 if (!sd->signal(BNET_EOD)) {
124 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
126 return bacl_exit_fatal;
129 Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
134 * First the native ACLs.
136 #if defined(HAVE_ACL)
137 #if defined(HAVE_AIX_OS)
139 #if defined(HAVE_EXTENDED_ACL)
141 #include <sys/access.h>
144 static bool acl_is_trivial(struct acl *acl)
146 return (acl_last(acl) != acl->acl_ext ? false : true);
149 static bool acl_nfs4_is_trivial(nfs4_acl_int_t *acl)
151 return (acl->aclEntryN > 0 ? false : true);
155 * Define the supported ACL streams for this OS
157 static int os_access_acl_streams[3] = { STREAM_ACL_AIX_TEXT, STREAM_ACL_AIX_AIXC, STREAM_ACL_AIX_NFS4 };
158 static int os_default_acl_streams[1] = { -1 };
160 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
165 size_t aclsize, acltxtsize;
166 bacl_exit_code retval = bacl_exit_error;
167 POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
170 * First see how big the buffers should be.
173 if (aclx_get(jcr->last_fname, GET_ACLINFO_ONLY, &type, NULL, &aclsize, NULL) < 0) {
176 retval = bacl_exit_ok;
179 Mmsg2(jcr->errmsg, _("aclx_get error on file \"%s\": ERR=%s\n"),
180 jcr->last_fname, be.bstrerror());
181 Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
182 jcr->last_fname, be.bstrerror());
188 * Make sure the buffers are big enough.
190 aclbuf = check_pool_memory_size(aclbuf, aclsize + 1);
193 * Retrieve the ACL info.
195 if (aclx_get(jcr->last_fname, 0, &type, aclbuf, &aclsize, &mode) < 0) {
198 retval = bacl_exit_ok;
201 Mmsg2(jcr->errmsg, _("aclx_get error on file \"%s\": ERR=%s\n"),
202 jcr->last_fname, be.bstrerror());
203 Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
204 jcr->last_fname, be.bstrerror());
210 * See if the acl is non trivial.
214 if (acl_is_trivial((struct acl *)aclbuf)) {
215 retval = bacl_exit_ok;
220 if (acl_nfs4_is_trivial((nfs4_acl_int_t *)aclbuf)) {
221 retval = bacl_exit_ok;
226 Mmsg2(jcr->errmsg, _("Unknown acl type encountered on file \"%s\": %ld\n"),
227 jcr->last_fname, type.u64);
228 Dmsg2(100, "Unknown acl type encountered on file \"%s\": %ld\n",
229 jcr->last_fname, type.u64);
234 * We have a non-trivial acl lets convert it into some ASCII form.
236 acltxtsize = sizeof_pool_memory(jcr->acl_data->content);
237 if (aclx_printStr(jcr->acl_data->content, &acltxtsize, aclbuf,
238 aclsize, type, jcr->last_fname, 0) < 0) {
242 * Our buffer is not big enough, acltxtsize should be updated with the value
243 * the aclx_printStr really need. So we increase the buffer and try again.
245 jcr->acl_data->content = check_pool_memory_size(jcr->acl_data->content, acltxtsize + 1);
246 if (aclx_printStr(jcr->acl_data->content, &acltxtsize, aclbuf,
247 aclsize, type, jcr->last_fname, 0) < 0) {
248 Mmsg1(jcr->errmsg, _("Failed to convert acl into text on file \"%s\"\n"),
250 Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
251 jcr->last_fname, type.u64);
256 Mmsg1(jcr->errmsg, _("Failed to convert acl into text on file \"%s\"\n"),
258 Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
259 jcr->last_fname, type.u64);
264 jcr->acl_data->content_length = strlen(jcr->acl_data->content) + 1;
267 retval = send_acl_stream(jcr, STREAM_ACL_AIX_AIXC);
269 retval = send_acl_stream(jcr, STREAM_ACL_AIX_NFS4);
273 free_pool_memory(aclbuf);
278 static bacl_exit_code aix_parse_acl_streams(JCR *jcr, int stream)
284 bacl_exit_code retval = bacl_exit_error;
285 POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
288 case STREAM_ACL_AIX_TEXT:
290 * Handle the old stream using the old system call for now.
292 if (acl_put(jcr->last_fname, jcr->acl_data->content, 0) != 0) {
293 retval = bacl_exit_error;
296 retval = bacl_exit_ok;
298 case STREAM_ACL_AIX_AIXC:
301 case STREAM_ACL_AIX_NFS4:
306 } /* end switch (stream) */
309 * Set the acl buffer to an initial size. For now we set it
310 * to the same size as the ASCII representation.
312 aclbuf = check_pool_memory_size(aclbuf, jcr->acl_data->content_length);
313 aclsize = jcr->acl_data->content_length;
314 if (aclx_scanStr(jcr->acl_data->content, aclbuf, &aclsize, type) < 0) {
318 * The buffer isn't big enough. The man page doesn't say that aclsize
319 * is updated to the needed size as what is done with aclx_printStr.
320 * So for now we try to increase the buffer a maximum of 3 times
321 * and retry the conversion.
323 for (cnt = 0; cnt < 3; cnt++) {
324 aclsize = 2 * aclsize;
325 aclbuf = check_pool_memory_size(aclbuf, aclsize);
327 if (aclx_scanStr(jcr->acl_data->content, aclbuf, &aclsize, type) == 0) {
332 * See why we failed this time, ENOSPC retry if max retries not met,
342 Mmsg2(jcr->errmsg, _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
343 jcr->last_fname, be.bstrerror());
344 Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
345 jcr->last_fname, be.bstrerror());
351 Mmsg2(jcr->errmsg, _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
352 jcr->last_fname, be.bstrerror());
353 Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
354 jcr->last_fname, be.bstrerror());
358 if (aclx_put(jcr->last_fname, SET_ACL, type, aclbuf, aclsize, 0) < 0) {
361 retval = bacl_exit_ok;
364 Mmsg2(jcr->errmsg, _("aclx_put error on file \"%s\": ERR=%s\n"),
365 jcr->last_fname, be.bstrerror());
366 Dmsg2(100, "aclx_put error file=%s ERR=%s\n",
367 jcr->last_fname, be.bstrerror());
372 retval = bacl_exit_ok;
375 free_pool_memory(aclbuf);
380 #else /* HAVE_EXTENDED_ACL */
382 #include <sys/access.h>
385 * Define the supported ACL streams for this OS
387 static int os_access_acl_streams[1] = { STREAM_ACL_AIX_TEXT };
388 static int os_default_acl_streams[1] = { -1 };
390 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
394 if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
395 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
396 actuallyfree(acl_text);
397 return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT);
399 return bacl_exit_error;
402 static bacl_exit_code aix_parse_acl_streams(JCR *jcr, int stream)
404 if (acl_put(jcr->last_fname, jcr->acl_data->content, 0) != 0) {
405 return bacl_exit_error;
409 #endif /* HAVE_EXTENDED_ACL */
412 * For this OS setup the build and parse function pointer to the OS specific functions.
414 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = aix_build_acl_streams;
415 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = aix_parse_acl_streams;
417 #elif defined(HAVE_DARWIN_OS) || \
418 defined(HAVE_FREEBSD_OS) || \
419 defined(HAVE_IRIX_OS) || \
420 defined(HAVE_OSF1_OS) || \
421 defined(HAVE_LINUX_OS)
423 #include <sys/types.h>
425 #ifdef HAVE_SYS_ACL_H
428 #error "configure failed to detect availability of sys/acl.h"
432 * On IRIX we can get shortened ACLs
434 #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
435 #define acl_to_text(acl,len) acl_to_short_text((acl), (len))
439 * On Linux we can get numeric and/or shorted ACLs
441 #if defined(HAVE_LINUX_OS)
442 #if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
443 #define BACL_ALTERNATE_TEXT (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
444 #elif defined(BACL_WANT_SHORT_ACLS)
445 #define BACL_ALTERNATE_TEXT TEXT_ABBREVIATE
446 #elif defined(BACL_WANT_NUMERIC_IDS)
447 #define BACL_ALTERNATE_TEXT TEXT_NUMERIC_IDS
449 #ifdef BACL_ALTERNATE_TEXT
450 #include <acl/libacl.h>
451 #define acl_to_text(acl,len) (acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
456 * On FreeBSD we can get numeric ACLs
458 #if defined(HAVE_FREEBSD_OS)
459 #if defined(BACL_WANT_NUMERIC_IDS)
460 #define BACL_ALTERNATE_TEXT ACL_TEXT_NUMERIC_IDS
462 #ifdef BACL_ALTERNATE_TEXT
463 #define acl_to_text(acl,len) (acl_to_text_np((acl), (len), BACL_ALTERNATE_TEXT))
468 * Some generic functions used by multiple OSes.
470 static acl_type_t bac_to_os_acltype(bacl_type acltype)
475 case BACL_TYPE_ACCESS:
476 ostype = ACL_TYPE_ACCESS;
478 case BACL_TYPE_DEFAULT:
479 ostype = ACL_TYPE_DEFAULT;
481 #ifdef HAVE_ACL_TYPE_NFS4
483 * FreeBSD has an additional acl type named ACL_TYPE_NFS4.
486 ostype = ACL_TYPE_NFS4;
489 #ifdef HAVE_ACL_TYPE_DEFAULT_DIR
490 case BACL_TYPE_DEFAULT_DIR:
492 * TRU64 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
494 ostype = ACL_TYPE_DEFAULT_DIR;
497 #ifdef HAVE_ACL_TYPE_EXTENDED
498 case BACL_TYPE_EXTENDED:
500 * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
502 ostype = ACL_TYPE_EXTENDED;
507 * This should never happen, as the per OS version function only tries acl
508 * types supported on a certain platform.
510 ostype = (acl_type_t)ACL_TYPE_NONE;
516 static int acl_count_entries(acl_t acl)
519 #if defined(HAVE_FREEBSD_OS) || \
520 defined(HAVE_LINUX_OS)
524 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
525 while (entry_available == 1) {
527 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
529 #elif defined(HAVE_IRIX_OS)
530 count = acl->acl_cnt;
531 #elif defined(HAVE_OSF1_OS)
532 count = acl->acl_num;
533 #elif defined(HAVE_DARWIN_OS)
537 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
538 while (entry_available == 0) {
540 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
546 #if !defined(HAVE_DARWIN_OS)
548 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
549 * There is no need to store those acls as we already store the stat bits too.
551 static bool acl_is_trivial(acl_t acl)
554 * acl is trivial if it has only the following entries:
561 #if defined(HAVE_FREEBSD_OS) || \
562 defined(HAVE_LINUX_OS)
565 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
566 while (entry_available == 1) {
568 * Get the tag type of this acl entry.
569 * If we fail to get the tagtype we call the acl non-trivial.
571 if (acl_get_tag_type(ace, &tag) < 0)
574 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
576 if (tag != ACL_USER_OBJ &&
577 tag != ACL_GROUP_OBJ &&
580 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
583 #elif defined(HAVE_IRIX_OS)
586 for (n = 0; n < acl->acl_cnt; n++) {
587 ace = &acl->acl_entry[n];
591 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
593 if (tag != ACL_USER_OBJ &&
594 tag != ACL_GROUP_OBJ &&
595 tag != ACL_OTHER_OBJ)
599 #elif defined(HAVE_OSF1_OS)
602 ace = acl->acl_first;
603 count = acl->acl_num;
606 tag = ace->entry->acl_type;
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 &&
615 * On Tru64, perm can also contain non-standard bits such as
616 * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
618 if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
629 * Generic wrapper around acl_get_file call.
631 static bacl_exit_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
637 bacl_exit_code retval = bacl_exit_ok;
639 ostype = bac_to_os_acltype(acltype);
640 acl = acl_get_file(jcr->last_fname, ostype);
643 * From observation, IRIX's acl_get_file() seems to return a
644 * non-NULL acl with a count field of -1 when a file has no ACL
645 * defined, while IRIX's acl_to_text() returns NULL when presented
648 * For all other implmentations we check if there are more then
649 * zero entries in the acl returned.
651 if (acl_count_entries(acl) <= 0) {
656 * Make sure this is not just a trivial ACL.
658 #if !defined(HAVE_DARWIN_OS)
659 if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
661 * The ACLs simply reflect the (already known) standard permissions
662 * So we don't send an ACL stream to the SD.
667 #if defined(HAVE_FREEBSD_OS) && defined(_PC_ACL_NFS4)
668 if (acltype == BACL_TYPE_NFS4) {
670 if (acl_is_trivial_np(acl, &trivial) == 0) {
673 * The ACLs simply reflect the (already known) standard permissions
674 * So we don't send an ACL stream to the SD.
683 * Convert the internal acl representation into a text representation.
685 if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
686 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
692 Mmsg2(jcr->errmsg, _("acl_to_text error on file \"%s\": ERR=%s\n"),
693 jcr->last_fname, be.bstrerror());
694 Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",
695 jcr->last_fname, be.bstrerror());
697 retval = bacl_exit_error;
701 * Handle errors gracefully.
704 #if defined(BACL_ENOTSUP)
707 * If the filesystem reports it doesn't support ACLs we clear the
708 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
709 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
710 * when we change from one filesystem to an other.
712 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
718 /* Some real error */
719 Mmsg2(jcr->errmsg, _("acl_get_file error on file \"%s\": ERR=%s\n"),
720 jcr->last_fname, be.bstrerror());
721 Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",
722 jcr->last_fname, be.bstrerror());
724 retval = bacl_exit_error;
733 pm_strcpy(jcr->acl_data->content, "");
734 jcr->acl_data->content_length = 0;
739 * Generic wrapper around acl_set_file call.
741 static bacl_exit_code generic_set_acl_on_os(JCR *jcr, bacl_type acltype)
748 * If we get empty default ACLs, clear ACLs now
750 ostype = bac_to_os_acltype(acltype);
751 if (ostype == ACL_TYPE_DEFAULT && strlen(jcr->acl_data->content) == 0) {
752 if (acl_delete_def_file(jcr->last_fname) == 0) {
758 #if defined(BACL_ENOTSUP)
760 Mmsg1(jcr->errmsg, _("acl_delete_def_file error on file \"%s\": filesystem doesn't support ACLs\n"),
765 Mmsg2(jcr->errmsg, _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
766 jcr->last_fname, be.bstrerror());
767 return bacl_exit_error;
771 acl = acl_from_text(jcr->acl_data->content);
773 Mmsg2(jcr->errmsg, _("acl_from_text error on file \"%s\": ERR=%s\n"),
774 jcr->last_fname, be.bstrerror());
775 Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",
776 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
777 return bacl_exit_error;
780 #ifndef HAVE_FREEBSD_OS
782 * FreeBSD always fails acl_valid() - at least on valid input...
783 * As it does the right thing, given valid input, just ignore acl_valid().
785 if (acl_valid(acl) != 0) {
786 Mmsg2(jcr->errmsg, _("acl_valid error on file \"%s\": ERR=%s\n"),
787 jcr->last_fname, be.bstrerror());
788 Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",
789 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
791 return bacl_exit_error;
796 * Restore the ACLs, but don't complain about links which really should
797 * not have attributes, and the file it is linked to may not yet be restored.
798 * This is only true for the old acl streams as in the new implementation we
799 * don't save acls of symlinks (which cannot have acls anyhow)
801 if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
806 #if defined(BACL_ENOTSUP)
808 Mmsg1(jcr->errmsg, _("acl_set_file error on file \"%s\": filesystem doesn't support ACLs\n"),
810 Dmsg2(100, "acl_set_file error acl=%s file=%s filesystem doesn't support ACLs\n",
811 jcr->acl_data->content, jcr->last_fname);
816 Mmsg2(jcr->errmsg, _("acl_set_file error on file \"%s\": ERR=%s\n"),
817 jcr->last_fname, be.bstrerror());
818 Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
819 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
821 return bacl_exit_error;
829 * OS specific functions for handling different types of acl streams.
831 #if defined(HAVE_DARWIN_OS)
833 * Define the supported ACL streams for this OS
835 static int os_access_acl_streams[1] = { STREAM_ACL_DARWIN_ACCESS_ACL };
836 static int os_default_acl_streams[1] = { -1 };
838 static bacl_exit_code darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
840 #if defined(HAVE_ACL_TYPE_EXTENDED)
842 * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
843 * and acl_get_file (name, ACL_TYPE_DEFAULT)
844 * always return NULL / EINVAL. There is no point in making
845 * these two useless calls. The real ACL is retrieved through
846 * acl_get_file (name, ACL_TYPE_EXTENDED).
848 * Read access ACLs for files, dirs and links
850 if (generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED) == bacl_exit_fatal)
851 return bacl_exit_fatal;
854 * Read access ACLs for files, dirs and links
856 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
857 return bacl_exit_fatal;
860 if (jcr->acl_data->content_length > 0) {
861 return send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL);
866 static bacl_exit_code darwin_parse_acl_streams(JCR *jcr, int stream)
868 #if defined(HAVE_ACL_TYPE_EXTENDED)
869 return generic_set_acl_on_os(jcr, BACL_TYPE_EXTENDED);
871 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
876 * For this OS setup the build and parse function pointer to the OS specific functions.
878 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = darwin_build_acl_streams;
879 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = darwin_parse_acl_streams;
881 #elif defined(HAVE_FREEBSD_OS)
883 * Define the supported ACL streams for these OSes
885 static int os_access_acl_streams[2] = { STREAM_ACL_FREEBSD_ACCESS_ACL, STREAM_ACL_FREEBSD_NFS4_ACL };
886 static int os_default_acl_streams[1] = { STREAM_ACL_FREEBSD_DEFAULT_ACL };
888 static bacl_exit_code freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
891 bacl_type acltype = BACL_TYPE_NONE;
894 #if defined(_PC_ACL_NFS4)
896 * See if filesystem supports NFS4 acls.
898 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
899 switch (acl_enabled) {
905 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
906 jcr->last_fname, be.bstrerror());
907 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
908 jcr->last_fname, be.bstrerror());
909 return bacl_exit_error;
914 acltype = BACL_TYPE_NFS4;
919 if (acl_enabled == 0) {
921 * See if filesystem supports POSIX acls.
923 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
924 switch (acl_enabled) {
930 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
931 jcr->last_fname, be.bstrerror());
932 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
933 jcr->last_fname, be.bstrerror());
934 return bacl_exit_error;
939 acltype = BACL_TYPE_ACCESS;
945 * If the filesystem reports it doesn't support ACLs we clear the
946 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
947 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
948 * when we change from one filesystem to an other.
950 if (acl_enabled == 0) {
951 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
952 pm_strcpy(jcr->acl_data->content, "");
953 jcr->acl_data->content_length = 0;
958 * Based on the supported ACLs retrieve and store them.
963 * Read NFS4 ACLs for files, dirs and links
965 if (generic_get_acl_from_os(jcr, BACL_TYPE_NFS4) == bacl_exit_fatal)
966 return bacl_exit_fatal;
968 if (jcr->acl_data->content_length > 0) {
969 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_NFS4_ACL) == bacl_exit_fatal)
970 return bacl_exit_fatal;
973 case BACL_TYPE_ACCESS:
975 * Read access ACLs for files, dirs and links
977 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
978 return bacl_exit_fatal;
980 if (jcr->acl_data->content_length > 0) {
981 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_ACCESS_ACL) == bacl_exit_fatal)
982 return bacl_exit_fatal;
986 * Directories can have default ACLs too
988 if (ff_pkt->type == FT_DIREND) {
989 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
990 return bacl_exit_fatal;
991 if (jcr->acl_data->content_length > 0) {
992 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_DEFAULT_ACL) == bacl_exit_fatal)
993 return bacl_exit_fatal;
1001 return bacl_exit_ok;
1004 static bacl_exit_code freebsd_parse_acl_streams(JCR *jcr, int stream)
1006 int acl_enabled = 0;
1007 const char *acl_type_name;
1011 * First make sure the filesystem supports acls.
1014 case STREAM_UNIX_ACCESS_ACL:
1015 case STREAM_ACL_FREEBSD_ACCESS_ACL:
1016 case STREAM_UNIX_DEFAULT_ACL:
1017 case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1018 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
1019 acl_type_name = "POSIX";
1021 case STREAM_ACL_FREEBSD_NFS4_ACL:
1022 #if defined(_PC_ACL_NFS4)
1023 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
1025 acl_type_name = "NFS4";
1028 acl_type_name = "unknown";
1032 switch (acl_enabled) {
1036 return bacl_exit_ok;
1038 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1039 jcr->last_fname, be.bstrerror());
1040 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1041 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1042 return bacl_exit_error;
1045 Mmsg2(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without %s acl support\n"),
1046 jcr->last_fname, acl_type_name);
1047 return bacl_exit_error;
1056 case STREAM_UNIX_ACCESS_ACL:
1057 case STREAM_ACL_FREEBSD_ACCESS_ACL:
1058 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
1059 case STREAM_UNIX_DEFAULT_ACL:
1060 case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1061 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
1062 case STREAM_ACL_FREEBSD_NFS4_ACL:
1063 return generic_set_acl_on_os(jcr, BACL_TYPE_NFS4);
1067 return bacl_exit_error;
1071 * For this OSes setup the build and parse function pointer to the OS specific functions.
1073 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = freebsd_build_acl_streams;
1074 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = freebsd_parse_acl_streams;
1076 #elif defined(HAVE_IRIX_OS) || \
1077 defined(HAVE_LINUX_OS)
1079 * Define the supported ACL streams for these OSes
1081 #if defined(HAVE_IRIX_OS)
1082 static int os_access_acl_streams[1] = { STREAM_ACL_IRIX_ACCESS_ACL };
1083 static int os_default_acl_streams[1] = { STREAM_ACL_IRIX_DEFAULT_ACL };
1084 #elif defined(HAVE_LINUX_OS)
1085 static int os_access_acl_streams[1] = { STREAM_ACL_LINUX_ACCESS_ACL };
1086 static int os_default_acl_streams[1] = { STREAM_ACL_LINUX_DEFAULT_ACL };
1089 static bacl_exit_code generic_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1092 * Read access ACLs for files, dirs and links
1094 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1095 return bacl_exit_fatal;
1097 if (jcr->acl_data->content_length > 0) {
1098 if (send_acl_stream(jcr, os_access_acl_streams[0]) == bacl_exit_fatal)
1099 return bacl_exit_fatal;
1103 * Directories can have default ACLs too
1105 if (ff_pkt->type == FT_DIREND) {
1106 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
1107 return bacl_exit_fatal;
1108 if (jcr->acl_data->content_length > 0) {
1109 if (send_acl_stream(jcr, os_default_acl_streams[0]) == bacl_exit_fatal)
1110 return bacl_exit_fatal;
1113 return bacl_exit_ok;
1116 static bacl_exit_code generic_parse_acl_streams(JCR *jcr, int stream)
1121 case STREAM_UNIX_ACCESS_ACL:
1122 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
1123 case STREAM_UNIX_DEFAULT_ACL:
1124 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
1127 * See what type of acl it is.
1129 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1130 if (os_access_acl_streams[cnt] == stream) {
1131 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
1134 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1135 if (os_default_acl_streams[cnt] == stream) {
1136 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
1141 return bacl_exit_error;
1145 * For this OSes setup the build and parse function pointer to the OS specific functions.
1147 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_build_acl_streams;
1148 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = generic_parse_acl_streams;
1150 #elif defined(HAVE_OSF1_OS)
1153 * Define the supported ACL streams for this OS
1155 static int os_access_acl_streams[1] = { STREAM_ACL_TRU64_ACCESS_ACL };
1156 static int os_default_acl_streams[2] = { STREAM_ACL_TRU64_DEFAULT_ACL, STREAM_ACL_TRU64_DEFAULT_DIR_ACL };
1158 static bacl_exit_code tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1161 * Read access ACLs for files, dirs and links
1163 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
1164 return bacl_exit_error;
1165 if (jcr->acl_data->content_length > 0) {
1166 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL))
1167 return bacl_exit_error;
1170 * Directories can have default ACLs too
1172 if (ff_pkt->type == FT_DIREND) {
1173 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
1174 return bacl_exit_error;
1175 if (jcr->acl_data->content_length > 0) {
1176 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL))
1177 return bacl_exit_error;
1180 * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
1181 * This is an inherited acl for all subdirs.
1182 * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
1183 * Section 21.5 Default ACLs
1185 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR)) < 0)
1186 return bacl_exit_error;
1187 if (jcr->acl_data->content_length > 0) {
1188 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL))
1189 return bacl_exit_error;
1192 return bacl_exit_ok;
1195 static bacl_exit_code tru64_parse_acl_streams(JCR *jcr, int stream)
1198 case STREAM_UNIX_ACCESS_ACL:
1199 case STREAM_ACL_TRU64_ACCESS_ACL:
1200 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
1201 case STREAM_UNIX_DEFAULT_ACL:
1202 case STREAM_ACL_TRU64_DEFAULT_ACL:
1203 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
1204 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
1205 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR);
1209 * For this OS setup the build and parse function pointer to the OS specific functions.
1211 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = tru64_build_acl_streams;
1212 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = tru64_parse_acl_streams;
1216 #elif defined(HAVE_HPUX_OS)
1217 #ifdef HAVE_SYS_ACL_H
1218 #include <sys/acl.h>
1220 #error "configure failed to detect availability of sys/acl.h"
1226 * Define the supported ACL streams for this OS
1228 static int os_access_acl_streams[1] = { STREAM_ACL_HPUX_ACL_ENTRY };
1229 static int os_default_acl_streams[1] = { -1 };
1232 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1233 * There is no need to store those acls as we already store the stat bits too.
1235 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
1238 struct acl_entry ace
1240 for (n = 0; n < count; n++) {
1243 * See if this acl just is the stat mode in acl form.
1245 if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
1246 (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
1247 (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
1254 * OS specific functions for handling different types of acl streams.
1256 static bacl_exit_code hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1259 struct acl_entry acls[NACLENTRIES];
1263 if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
1265 #if defined(BACL_ENOTSUP)
1268 * Not supported, just pretend there is nothing to see
1270 * If the filesystem reports it doesn't support ACLs we clear the
1271 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1272 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1273 * when we change from one filesystem to an other.
1275 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1276 pm_strcpy(jcr->acl_data->content, "");
1277 jcr->acl_data->content_length = 0;
1278 return bacl_exit_ok;
1281 pm_strcpy(jcr->acl_data->content, "");
1282 jcr->acl_data->content_length = 0;
1283 return bacl_exit_ok;
1285 Mmsg2(jcr->errmsg, _("getacl error on file \"%s\": ERR=%s\n"),
1286 jcr->last_fname, be.bstrerror());
1287 Dmsg2(100, "getacl error file=%s ERR=%s\n",
1288 jcr->last_fname, be.bstrerror());
1290 pm_strcpy(jcr->acl_data->content, "");
1291 jcr->acl_data->content_length = 0;
1292 return bacl_exit_error;
1296 pm_strcpy(jcr->acl_data->content, "");
1297 jcr->acl_data->content_length = 0;
1298 return bacl_exit_ok;
1300 if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
1301 if (acl_is_trivial(n, acls, ff_pkt->statp)) {
1303 * The ACLs simply reflect the (already known) standard permissions
1304 * So we don't send an ACL stream to the SD.
1306 pm_strcpy(jcr->acl_data->content, "");
1307 jcr->acl_data->content_length = 0;
1308 return bacl_exit_ok;
1310 if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
1311 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1312 actuallyfree(acl_text);
1314 return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
1316 Mmsg2(jcr->errmsg, _("acltostr error on file \"%s\": ERR=%s\n"),
1317 jcr->last_fname, be.bstrerror());
1318 Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",
1319 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1320 return bacl_exit_error;
1322 return bacl_exit_error;
1325 static bacl_exit_code hpux_parse_acl_streams(JCR *jcr, int stream)
1328 struct acl_entry acls[NACLENTRIES];
1331 n = strtoacl(jcr->acl_data->content, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
1333 Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
1334 jcr->last_fname, be.bstrerror());
1335 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
1336 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1337 return bacl_exit_error;
1339 if (strtoacl(jcr->acl_data->content, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
1340 Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
1341 jcr->last_fname, be.bstrerror());
1342 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
1343 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1345 return bacl_exit_error;
1348 * Restore the ACLs, but don't complain about links which really should
1349 * not have attributes, and the file it is linked to may not yet be restored.
1350 * This is only true for the old acl streams as in the new implementation we
1351 * don't save acls of symlinks (which cannot have acls anyhow)
1353 if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
1356 return bacl_exit_ok;
1358 Mmsg2(jcr->errmsg, _("setacl error on file \"%s\": ERR=%s\n"),
1359 jcr->last_fname, be.bstrerror());
1360 Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
1361 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1362 return bacl_exit_error;
1365 return bacl_exit_ok;
1369 * For this OS setup the build and parse function pointer to the OS specific functions.
1371 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = hpux_build_acl_streams;
1372 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = hpux_parse_acl_streams;
1374 #elif defined(HAVE_SUN_OS)
1375 #ifdef HAVE_SYS_ACL_H
1376 #include <sys/acl.h>
1378 #error "configure failed to detect availability of sys/acl.h"
1381 #if defined(HAVE_EXTENDED_ACL)
1383 * We define some internals of the Solaris acl libs here as those
1384 * are not exposed yet. Probably because they want us to see the
1385 * acls as opague data. But as we need to support different platforms
1386 * and versions of Solaris we need to expose some data to be able
1387 * to determine the type of acl used to stuff it into the correct
1388 * data stream. I know this is far from portable, but maybe the
1389 * proper interface is exposed later on and we can get ride of
1390 * this kludge. Newer versions of Solaris include sys/acl_impl.h
1391 * which has implementation details of acls, if thats included we
1392 * don't have to define it ourself.
1394 #if !defined(_SYS_ACL_IMPL_H)
1395 typedef enum acl_type {
1402 * Two external references to functions in the libsec library function not in current include files.
1405 int acl_type(acl_t *);
1406 char *acl_strerror(int);
1410 * Define the supported ACL streams for this OS
1412 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT, STREAM_ACL_SOLARIS_ACE };
1413 static int os_default_acl_streams[1] = { -1 };
1416 * As the new libsec interface with acl_totext and acl_fromtext also handles
1417 * the old format from acltotext we can use the new functions even
1418 * for acls retrieved and stored in the database with older fd versions. If the
1419 * new interface is not defined (Solaris 9 and older we fall back to the old code)
1421 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1423 int acl_enabled, flags;
1426 bacl_exit_code stream_status = bacl_exit_error;
1430 * See if filesystem supports acls.
1432 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1433 switch (acl_enabled) {
1436 * If the filesystem reports it doesn't support ACLs we clear the
1437 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1438 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1439 * when we change from one filesystem to an other.
1441 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1442 pm_strcpy(jcr->acl_data->content, "");
1443 jcr->acl_data->content_length = 0;
1444 return bacl_exit_ok;
1448 return bacl_exit_ok;
1450 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1451 jcr->last_fname, be.bstrerror());
1452 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
1453 jcr->last_fname, be.bstrerror());
1454 return bacl_exit_error;
1461 * Get ACL info: don't bother allocating space if there is only a trivial ACL.
1463 if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
1466 return bacl_exit_ok;
1468 Mmsg2(jcr->errmsg, _("acl_get error on file \"%s\": ERR=%s\n"),
1469 jcr->last_fname, acl_strerror(errno));
1470 Dmsg2(100, "acl_get error file=%s ERR=%s\n",
1471 jcr->last_fname, acl_strerror(errno));
1472 return bacl_exit_error;
1478 * The ACLs simply reflect the (already known) standard permissions
1479 * So we don't send an ACL stream to the SD.
1481 pm_strcpy(jcr->acl_data->content, "");
1482 jcr->acl_data->content_length = 0;
1483 return bacl_exit_ok;
1486 #if defined(ACL_SID_FMT)
1488 * New format flag added in newer Solaris versions.
1490 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
1492 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
1493 #endif /* ACL_SID_FMT */
1495 if ((acl_text = acl_totext(aclp, flags)) != NULL) {
1496 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1497 actuallyfree(acl_text);
1499 switch (acl_type(aclp)) {
1501 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1504 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE);
1512 return stream_status;
1515 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
1518 int acl_enabled, error;
1522 case STREAM_UNIX_ACCESS_ACL:
1523 case STREAM_ACL_SOLARIS_ACLENT:
1524 case STREAM_ACL_SOLARIS_ACE:
1526 * First make sure the filesystem supports acls.
1528 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1529 switch (acl_enabled) {
1531 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
1533 return bacl_exit_error;
1537 return bacl_exit_ok;
1539 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1540 jcr->last_fname, be.bstrerror());
1541 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1542 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1543 return bacl_exit_error;
1547 * On a filesystem with ACL support make sure this particular ACL type can be restored.
1550 case STREAM_ACL_SOLARIS_ACLENT:
1552 * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
1554 if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
1555 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without aclent acl support\n"),
1557 return bacl_exit_error;
1560 case STREAM_ACL_SOLARIS_ACE:
1562 * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
1564 if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
1565 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without ace acl support\n"),
1567 return bacl_exit_error;
1572 * Stream id which doesn't describe the type of acl which is encoded.
1579 if ((error = acl_fromtext(jcr->acl_data->content, &aclp)) != 0) {
1580 Mmsg2(jcr->errmsg, _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1581 jcr->last_fname, acl_strerror(error));
1582 Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",
1583 jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1584 return bacl_exit_error;
1588 * Validate that the conversion gave us the correct acl type.
1591 case STREAM_ACL_SOLARIS_ACLENT:
1592 if (acl_type(aclp) != ACLENT_T) {
1593 Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1595 return bacl_exit_error;
1598 case STREAM_ACL_SOLARIS_ACE:
1599 if (acl_type(aclp) != ACE_T) {
1600 Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1602 return bacl_exit_error;
1607 * Stream id which doesn't describe the type of acl which is encoded.
1613 * Restore the ACLs, but don't complain about links which really should
1614 * not have attributes, and the file it is linked to may not yet be restored.
1615 * This is only true for the old acl streams as in the new implementation we
1616 * don't save acls of symlinks (which cannot have acls anyhow)
1618 if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1622 return bacl_exit_ok;
1624 Mmsg2(jcr->errmsg, _("acl_set error on file \"%s\": ERR=%s\n"),
1625 jcr->last_fname, acl_strerror(error));
1626 Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",
1627 jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1629 return bacl_exit_error;
1634 return bacl_exit_ok;
1636 return bacl_exit_error;
1637 } /* end switch (stream) */
1640 #else /* HAVE_EXTENDED_ACL */
1643 * Define the supported ACL streams for this OS
1645 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT };
1646 static int os_default_acl_streams[1] = { -1 };
1649 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1650 * There is no need to store those acls as we already store the stat bits too.
1652 static bool acl_is_trivial(int count, aclent_t *entries)
1657 for (n = 0; n < count; n++) {
1660 if (!(ace->a_type == USER_OBJ ||
1661 ace->a_type == GROUP_OBJ ||
1662 ace->a_type == OTHER_OBJ ||
1663 ace->a_type == CLASS_OBJ))
1670 * OS specific functions for handling different types of acl streams.
1672 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1679 n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1680 if (n < MIN_ACL_ENTRIES)
1681 return bacl_exit_error;
1683 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1684 if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1685 if (acl_is_trivial(n, acls)) {
1687 * The ACLs simply reflect the (already known) standard permissions
1688 * So we don't send an ACL stream to the SD.
1691 pm_strcpy(jcr->acl_data->content, "");
1692 jcr->acl_data->content_length = 0;
1693 return bacl_exit_ok;
1696 if ((acl_text = acltotext(acls, n)) != NULL) {
1697 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1698 actuallyfree(acl_text);
1700 return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1703 Mmsg2(jcr->errmsg, _("acltotext error on file \"%s\": ERR=%s\n"),
1704 jcr->last_fname, be.bstrerror());
1705 Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",
1706 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1710 return bacl_exit_error;
1713 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
1719 acls = aclfromtext(jcr->acl_data->content, &n);
1721 Mmsg2(jcr->errmsg, _("aclfromtext error on file \"%s\": ERR=%s\n"),
1722 jcr->last_fname, be.bstrerror());
1723 Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",
1724 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1725 return bacl_exit_error;
1729 * Restore the ACLs, but don't complain about links which really should
1730 * not have attributes, and the file it is linked to may not yet be restored.
1732 if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
1736 return bacl_exit_ok;
1738 Mmsg2(jcr->errmsg, _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
1739 jcr->last_fname, be.bstrerror());
1740 Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
1741 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1743 return bacl_exit_error;
1747 return bacl_exit_ok;
1749 #endif /* HAVE_EXTENDED_ACL */
1752 * For this OS setup the build and parse function pointer to the OS specific functions.
1754 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_acl_streams;
1755 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = solaris_parse_acl_streams;
1757 #endif /* HAVE_SUN_OS */
1758 #endif /* HAVE_ACL */
1761 * Entry points when compiled with support for ACLs on a supported platform.
1765 * Read and send an ACL for the last encountered file.
1767 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1770 * See if we are changing from one device to an other.
1771 * We save the current device we are scanning and compare
1772 * it with the current st_dev in the last stat performed on
1773 * the file we are currently storing.
1775 if (jcr->acl_data->current_dev != ff_pkt->statp.st_dev) {
1777 * Reset the acl save flags.
1779 jcr->acl_data->flags = 0;
1781 jcr->acl_data->flags |= BACL_FLAG_SAVE_NATIVE;
1784 * Save that we started scanning a new filesystem.
1786 jcr->acl_data->current_dev = ff_pkt->statp.st_dev;
1789 #if defined(HAVE_ACL)
1791 * See if the BACL_FLAG_SAVE_NATIVE flag is set which lets us know if we should
1794 if (jcr->acl_data->flags & BACL_FLAG_SAVE_NATIVE) {
1796 * Call the appropriate function.
1798 if (os_build_acl_streams) {
1799 return (*os_build_acl_streams)(jcr, ff_pkt);
1802 return bacl_exit_ok;
1805 return bacl_exit_error;
1808 bacl_exit_code parse_acl_streams(JCR *jcr, int stream)
1813 #if defined(HAVE_ACL)
1814 case STREAM_UNIX_ACCESS_ACL:
1815 case STREAM_UNIX_DEFAULT_ACL:
1817 * Handle legacy ACL streams.
1819 if (os_parse_acl_streams) {
1820 return (*os_parse_acl_streams)(jcr, stream);
1824 if (os_parse_acl_streams) {
1826 * Walk the os_access_acl_streams array with the supported Access ACL streams for this OS.
1828 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1829 if (os_access_acl_streams[cnt] == stream) {
1830 return (*os_parse_acl_streams)(jcr, stream);
1834 * Walk the os_default_acl_streams array with the supported Default ACL streams for this OS.
1836 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1837 if (os_default_acl_streams[cnt] == stream) {
1838 return (*os_parse_acl_streams)(jcr, stream);
1848 Qmsg2(jcr, M_WARNING, 0,
1849 _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
1850 jcr->last_fname, stream);
1851 return bacl_exit_error;