2 Bacula® - The Network Backup Solution
4 Copyright (C) 2004-2010 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Functions to handle ACLs for bacula.
31 * Currently we support the following OSes:
32 * - AIX (pre-5.3 and post 5.3 acls, acl_get and aclx_get interface)
34 * - FreeBSD (POSIX and NFSv4/ZFS acls)
38 * - Solaris (POSIX and NFSv4/ZFS acls)
41 * Next to OS specific acls we support AFS acls using the pioctl interface.
43 * We handle two different types of ACLs: access and default ACLS.
44 * On most systems that support default ACLs they only apply to directories.
46 * On some systems (eg. linux and FreeBSD) we must obtain the two ACLs
47 * independently, while others (eg. Solaris) provide both in one call.
49 * The Filed saves ACLs in their native format and uses different streams
50 * for all different platforms. Currently we only allow ACLs to be restored
51 * which were saved in the native format of the platform they are extracted
52 * on. Later on we might add conversion functions for mapping from one
53 * platform to an other or allow restores of systems that use the same
56 * Its also interesting to see what the exact format of acl text is on
57 * certain platforms and if they use they same encoding we might allow
58 * different platform streams to be decoded on an other similar platform.
60 * Original written by Preben 'Peppe' Guldberg, December MMIV
61 * Major rewrite by Marco van Wieringen, November MMVIII
67 #if !defined(HAVE_ACL) && !defined(HAVE_AFS_ACL)
69 * Entry points when compiled without support for ACLs or on an unsupported platform.
71 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
73 return bacl_exit_fatal;
76 bacl_exit_code parse_acl_streams(JCR *jcr, int stream)
78 return bacl_exit_fatal;
82 * Send an ACL stream to the SD.
84 static bacl_exit_code send_acl_stream(JCR *jcr, int stream)
86 BSOCK *sd = jcr->store_bsock;
88 #ifdef FD_NO_SEND_TEST
95 if (jcr->acl_data->content_length <= 0) {
102 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
103 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
105 return bacl_exit_fatal;
109 * Send the buffer to the storage deamon
111 Dmsg1(400, "Backing up ACL <%s>\n", jcr->acl_data->content);
113 sd->msg = jcr->acl_data->content;
114 sd->msglen = jcr->acl_data->content_length + 1;
118 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
120 return bacl_exit_fatal;
123 jcr->JobBytes += sd->msglen;
125 if (!sd->signal(BNET_EOD)) {
126 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
128 return bacl_exit_fatal;
131 Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
136 * First the native ACLs.
138 #if defined(HAVE_ACL)
139 #if defined(HAVE_AIX_OS)
141 #if defined(HAVE_EXTENDED_ACL)
143 #include <sys/access.h>
146 static bool acl_is_trivial(struct acl *acl)
148 return (acl_last(acl) != acl->acl_ext ? false : true);
151 static bool acl_nfs4_is_trivial(nfs4_acl_int_t *acl)
153 return (acl->aclEntryN > 0 ? false : true);
157 * Define the supported ACL streams for this OS
159 static int os_access_acl_streams[3] = { STREAM_ACL_AIX_TEXT, STREAM_ACL_AIX_AIXC, STREAM_ACL_AIX_NFS4 };
160 static int os_default_acl_streams[1] = { -1 };
162 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
167 size_t aclsize, acltxtsize;
168 bacl_exit_code retval = bacl_exit_error;
169 POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
172 * First see how big the buffers should be.
175 if (aclx_get(jcr->last_fname, GET_ACLINFO_ONLY, &type, NULL, &aclsize, NULL) < 0) {
178 retval = bacl_exit_ok;
181 Mmsg2(jcr->errmsg, _("aclx_get error on file \"%s\": ERR=%s\n"),
182 jcr->last_fname, be.bstrerror());
183 Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
184 jcr->last_fname, be.bstrerror());
190 * Make sure the buffers are big enough.
192 aclbuf = check_pool_memory_size(aclbuf, aclsize + 1);
195 * Retrieve the ACL info.
197 if (aclx_get(jcr->last_fname, 0, &type, aclbuf, &aclsize, &mode) < 0) {
200 retval = bacl_exit_ok;
203 Mmsg2(jcr->errmsg, _("aclx_get error on file \"%s\": ERR=%s\n"),
204 jcr->last_fname, be.bstrerror());
205 Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
206 jcr->last_fname, be.bstrerror());
212 * See if the acl is non trivial.
216 if (acl_is_trivial((struct acl *)aclbuf)) {
217 retval = bacl_exit_ok;
222 if (acl_nfs4_is_trivial((nfs4_acl_int_t *)aclbuf)) {
223 retval = bacl_exit_ok;
228 Mmsg2(jcr->errmsg, _("Unknown acl type encountered on file \"%s\": %ld\n"),
229 jcr->last_fname, type.u64);
230 Dmsg2(100, "Unknown acl type encountered on file \"%s\": %ld\n",
231 jcr->last_fname, type.u64);
236 * We have a non-trivial acl lets convert it into some ASCII form.
238 acltxtsize = sizeof_pool_memory(jcr->acl_data->content);
239 if (aclx_printStr(jcr->acl_data->content, &acltxtsize, aclbuf,
240 aclsize, type, jcr->last_fname, 0) < 0) {
244 * Our buffer is not big enough, acltxtsize should be updated with the value
245 * the aclx_printStr really need. So we increase the buffer and try again.
247 jcr->acl_data->content = check_pool_memory_size(jcr->acl_data->content, acltxtsize + 1);
248 if (aclx_printStr(jcr->acl_data->content, &acltxtsize, aclbuf,
249 aclsize, type, jcr->last_fname, 0) < 0) {
250 Mmsg1(jcr->errmsg, _("Failed to convert acl into text on file \"%s\"\n"),
252 Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
253 jcr->last_fname, type.u64);
258 Mmsg1(jcr->errmsg, _("Failed to convert acl into text on file \"%s\"\n"),
260 Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
261 jcr->last_fname, type.u64);
266 jcr->acl_data->content_length = strlen(jcr->acl_data->content) + 1;
269 retval = send_acl_stream(jcr, STREAM_ACL_AIX_AIXC);
271 retval = send_acl_stream(jcr, STREAM_ACL_AIX_NFS4);
275 free_pool_memory(aclbuf);
280 static bacl_exit_code aix_parse_acl_streams(JCR *jcr, int stream)
286 bacl_exit_code retval = bacl_exit_error;
287 POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
290 case STREAM_ACL_AIX_TEXT:
292 * Handle the old stream using the old system call for now.
294 if (acl_put(jcr->last_fname, jcr->acl_data->content, 0) != 0) {
295 retval = bacl_exit_error;
298 retval = bacl_exit_ok;
300 case STREAM_ACL_AIX_AIXC:
303 case STREAM_ACL_AIX_NFS4:
308 } /* end switch (stream) */
311 * Set the acl buffer to an initial size. For now we set it
312 * to the same size as the ASCII representation.
314 aclbuf = check_pool_memory_size(aclbuf, jcr->acl_data->content_length);
315 aclsize = jcr->acl_data->content_length;
316 if (aclx_scanStr(jcr->acl_data->content, aclbuf, &aclsize, type) < 0) {
320 * The buffer isn't big enough. The man page doesn't say that aclsize
321 * is updated to the needed size as what is done with aclx_printStr.
322 * So for now we try to increase the buffer a maximum of 3 times
323 * and retry the conversion.
325 for (cnt = 0; cnt < 3; cnt++) {
326 aclsize = 2 * aclsize;
327 aclbuf = check_pool_memory_size(aclbuf, aclsize);
329 if (aclx_scanStr(jcr->acl_data->content, aclbuf, &aclsize, type) == 0) {
334 * See why we failed this time, ENOSPC retry if max retries not met,
344 Mmsg2(jcr->errmsg, _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
345 jcr->last_fname, be.bstrerror());
346 Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
347 jcr->last_fname, be.bstrerror());
353 Mmsg2(jcr->errmsg, _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
354 jcr->last_fname, be.bstrerror());
355 Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
356 jcr->last_fname, be.bstrerror());
360 if (aclx_put(jcr->last_fname, SET_ACL, type, aclbuf, aclsize, 0) < 0) {
363 retval = bacl_exit_ok;
366 Mmsg2(jcr->errmsg, _("aclx_put error on file \"%s\": ERR=%s\n"),
367 jcr->last_fname, be.bstrerror());
368 Dmsg2(100, "aclx_put error file=%s ERR=%s\n",
369 jcr->last_fname, be.bstrerror());
374 retval = bacl_exit_ok;
377 free_pool_memory(aclbuf);
382 #else /* HAVE_EXTENDED_ACL */
384 #include <sys/access.h>
387 * Define the supported ACL streams for this OS
389 static int os_access_acl_streams[1] = { STREAM_ACL_AIX_TEXT };
390 static int os_default_acl_streams[1] = { -1 };
392 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
396 if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
397 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
398 actuallyfree(acl_text);
399 return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT);
401 return bacl_exit_error;
404 static bacl_exit_code aix_parse_acl_streams(JCR *jcr, int stream)
406 if (acl_put(jcr->last_fname, jcr->acl_data->content, 0) != 0) {
407 return bacl_exit_error;
411 #endif /* HAVE_EXTENDED_ACL */
414 * For this OS setup the build and parse function pointer to the OS specific functions.
416 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = aix_build_acl_streams;
417 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = aix_parse_acl_streams;
419 #elif defined(HAVE_DARWIN_OS) || \
420 defined(HAVE_FREEBSD_OS) || \
421 defined(HAVE_IRIX_OS) || \
422 defined(HAVE_OSF1_OS) || \
423 defined(HAVE_LINUX_OS)
425 #include <sys/types.h>
427 #ifdef HAVE_SYS_ACL_H
430 #error "configure failed to detect availability of sys/acl.h"
434 * On IRIX we can get shortened ACLs
436 #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
437 #define acl_to_text(acl,len) acl_to_short_text((acl), (len))
441 * On Linux we can get numeric and/or shorted ACLs
443 #if defined(HAVE_LINUX_OS)
444 #if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
445 #define BACL_ALTERNATE_TEXT (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
446 #elif defined(BACL_WANT_SHORT_ACLS)
447 #define BACL_ALTERNATE_TEXT TEXT_ABBREVIATE
448 #elif defined(BACL_WANT_NUMERIC_IDS)
449 #define BACL_ALTERNATE_TEXT TEXT_NUMERIC_IDS
451 #ifdef BACL_ALTERNATE_TEXT
452 #include <acl/libacl.h>
453 #define acl_to_text(acl,len) (acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
458 * On FreeBSD we can get numeric ACLs
460 #if defined(HAVE_FREEBSD_OS)
461 #if defined(BACL_WANT_NUMERIC_IDS)
462 #define BACL_ALTERNATE_TEXT ACL_TEXT_NUMERIC_IDS
464 #ifdef BACL_ALTERNATE_TEXT
465 #define acl_to_text(acl,len) (acl_to_text_np((acl), (len), BACL_ALTERNATE_TEXT))
470 * Some generic functions used by multiple OSes.
472 static acl_type_t bac_to_os_acltype(bacl_type acltype)
477 case BACL_TYPE_ACCESS:
478 ostype = ACL_TYPE_ACCESS;
480 case BACL_TYPE_DEFAULT:
481 ostype = ACL_TYPE_DEFAULT;
485 * FreeBSD has an additional acl type named ACL_TYPE_NFS4.
488 ostype = ACL_TYPE_NFS4;
491 #ifdef ACL_TYPE_DEFAULT_DIR
492 case BACL_TYPE_DEFAULT_DIR:
494 * TRU64 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
496 ostype = ACL_TYPE_DEFAULT_DIR;
499 #ifdef ACL_TYPE_EXTENDED
500 case BACL_TYPE_EXTENDED:
502 * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
504 ostype = ACL_TYPE_EXTENDED;
509 * This should never happen, as the per OS version function only tries acl
510 * types supported on a certain platform.
512 ostype = (acl_type_t)ACL_TYPE_NONE;
518 #if !defined(HAVE_DARWIN_OS)
520 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
521 * There is no need to store those acls as we already store the stat bits too.
523 static bool acl_is_trivial(acl_t acl)
526 * acl is trivial if it has only the following entries:
533 #if defined(HAVE_FREEBSD_OS) || \
534 defined(HAVE_LINUX_OS)
537 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
538 while (entry_available == 1) {
540 * Get the tag type of this acl entry.
541 * If we fail to get the tagtype we call the acl non-trivial.
543 if (acl_get_tag_type(ace, &tag) < 0)
546 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
548 if (tag != ACL_USER_OBJ &&
549 tag != ACL_GROUP_OBJ &&
552 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
555 #elif defined(HAVE_IRIX_OS)
558 for (n = 0; n < acl->acl_cnt; n++) {
559 ace = &acl->acl_entry[n];
563 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
565 if (tag != ACL_USER_OBJ &&
566 tag != ACL_GROUP_OBJ &&
567 tag != ACL_OTHER_OBJ)
571 #elif defined(HAVE_OSF1_OS)
574 ace = acl->acl_first;
575 count = acl->acl_num;
578 tag = ace->entry->acl_type;
580 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
582 if (tag != ACL_USER_OBJ &&
583 tag != ACL_GROUP_OBJ &&
587 * On Tru64, perm can also contain non-standard bits such as
588 * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
590 if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
601 * Generic wrapper around acl_get_file call.
603 static bacl_exit_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
610 ostype = bac_to_os_acltype(acltype);
611 acl = acl_get_file(jcr->last_fname, ostype);
613 #if defined(HAVE_IRIX_OS)
615 * From observation, IRIX's acl_get_file() seems to return a
616 * non-NULL acl with a count field of -1 when a file has no ACL
617 * defined, while IRIX's acl_to_text() returns NULL when presented
620 * Checking the count in the acl structure before calling
621 * acl_to_text() lets us avoid error messages about files
622 * with no ACLs, without modifying the flow of the code used for
623 * other operating systems, and it saves making some calls
624 * to acl_to_text() besides.
626 if (acl->acl_cnt <= 0) {
627 pm_strcpy(jcr->acl_data->content, "");
628 jcr->acl_data->content_length = 0;
635 * Make sure this is not just a trivial ACL.
637 #if !defined(HAVE_DARWIN_OS)
638 if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
640 * The ACLs simply reflect the (already known) standard permissions
641 * So we don't send an ACL stream to the SD.
643 pm_strcpy(jcr->acl_data->content, "");
644 jcr->acl_data->content_length = 0;
649 #if defined(HAVE_FREEBSD_OS) && defined(_PC_ACL_NFS4)
650 if (acltype == BACL_TYPE_NFS4) {
652 if (acl_is_trivial_np(acl, &trivial) == 0) {
655 * The ACLs simply reflect the (already known) standard permissions
656 * So we don't send an ACL stream to the SD.
658 pm_strcpy(jcr->acl_data->content, "");
659 jcr->acl_data->content_length = 0;
667 if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
668 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
674 Mmsg2(jcr->errmsg, _("acl_to_text error on file \"%s\": ERR=%s\n"),
675 jcr->last_fname, be.bstrerror());
676 Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",
677 jcr->last_fname, be.bstrerror());
679 pm_strcpy(jcr->acl_data->content, "");
680 jcr->acl_data->content_length = 0;
682 return bacl_exit_error;
686 * Handle errors gracefully.
688 if (acl == (acl_t)NULL) {
690 #if defined(BACL_ENOTSUP)
693 * If the filesystem reports it doesn't support ACLs we clear the
694 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
695 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
696 * when we change from one filesystem to an other.
698 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
699 break; /* not supported */
702 pm_strcpy(jcr->acl_data->content, "");
703 jcr->acl_data->content_length = 0;
706 /* Some real error */
707 Mmsg2(jcr->errmsg, _("acl_get_file error on file \"%s\": ERR=%s\n"),
708 jcr->last_fname, be.bstrerror());
709 Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",
710 jcr->last_fname, be.bstrerror());
712 pm_strcpy(jcr->acl_data->content, "");
713 jcr->acl_data->content_length = 0;
714 return bacl_exit_error;
719 * Not supported, just pretend there is nothing to see
721 pm_strcpy(jcr->acl_data->content, "");
722 jcr->acl_data->content_length = 0;
727 * Generic wrapper around acl_set_file call.
729 static bacl_exit_code generic_set_acl_on_os(JCR *jcr, bacl_type acltype)
736 * If we get empty default ACLs, clear ACLs now
738 ostype = bac_to_os_acltype(acltype);
739 if (ostype == ACL_TYPE_DEFAULT && strlen(jcr->acl_data->content) == 0) {
740 if (acl_delete_def_file(jcr->last_fname) == 0) {
747 Mmsg2(jcr->errmsg, _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
748 jcr->last_fname, be.bstrerror());
749 return bacl_exit_error;
753 acl = acl_from_text(jcr->acl_data->content);
755 Mmsg2(jcr->errmsg, _("acl_from_text error on file \"%s\": ERR=%s\n"),
756 jcr->last_fname, be.bstrerror());
757 Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",
758 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
759 return bacl_exit_error;
762 #ifndef HAVE_FREEBSD_OS
764 * FreeBSD always fails acl_valid() - at least on valid input...
765 * As it does the right thing, given valid input, just ignore acl_valid().
767 if (acl_valid(acl) != 0) {
768 Mmsg2(jcr->errmsg, _("acl_valid error on file \"%s\": ERR=%s\n"),
769 jcr->last_fname, be.bstrerror());
770 Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",
771 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
773 return bacl_exit_error;
778 * Restore the ACLs, but don't complain about links which really should
779 * not have attributes, and the file it is linked to may not yet be restored.
780 * This is only true for the old acl streams as in the new implementation we
781 * don't save acls of symlinks (which cannot have acls anyhow)
783 if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
789 Mmsg2(jcr->errmsg, _("acl_set_file error on file \"%s\": ERR=%s\n"),
790 jcr->last_fname, be.bstrerror());
791 Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
792 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
794 return bacl_exit_error;
802 * OS specific functions for handling different types of acl streams.
804 #if defined(HAVE_DARWIN_OS)
806 * Define the supported ACL streams for this OS
808 static int os_access_acl_streams[1] = { STREAM_ACL_DARWIN_ACCESS_ACL };
809 static int os_default_acl_streams[1] = { -1 };
811 static bacl_exit_code darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
813 #if defined(ACL_TYPE_EXTENDED)
815 * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
816 * and acl_get_file (name, ACL_TYPE_DEFAULT)
817 * always return NULL / EINVAL. There is no point in making
818 * these two useless calls. The real ACL is retrieved through
819 * acl_get_file (name, ACL_TYPE_EXTENDED).
821 * Read access ACLs for files, dirs and links
823 if (generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED) == bacl_exit_fatal)
824 return bacl_exit_fatal;
827 * Read access ACLs for files, dirs and links
829 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
830 return bacl_exit_fatal;
833 if (jcr->acl_data->content_length > 0) {
834 return send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL);
839 static bacl_exit_code darwin_parse_acl_streams(JCR *jcr, int stream)
841 #if defined(ACL_TYPE_EXTENDED)
842 return generic_set_acl_on_os(jcr, BACL_TYPE_EXTENDED);
844 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
849 * For this OS setup the build and parse function pointer to the OS specific functions.
851 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = darwin_build_acl_streams;
852 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = darwin_parse_acl_streams;
854 #elif defined(HAVE_FREEBSD_OS)
856 * Define the supported ACL streams for these OSes
858 static int os_access_acl_streams[2] = { STREAM_ACL_FREEBSD_ACCESS_ACL, STREAM_ACL_FREEBSD_NFS4_ACL };
859 static int os_default_acl_streams[1] = { STREAM_ACL_FREEBSD_DEFAULT_ACL };
861 static bacl_exit_code freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
864 bacl_type acltype = BACL_TYPE_NONE;
867 #if defined(_PC_ACL_NFS4)
869 * See if filesystem supports NFS4 acls.
871 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
872 switch (acl_enabled) {
878 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
879 jcr->last_fname, be.bstrerror());
880 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
881 jcr->last_fname, be.bstrerror());
882 return bacl_exit_error;
887 acltype = BACL_TYPE_NFS4;
892 if (acl_enabled == 0) {
894 * See if filesystem supports POSIX acls.
896 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
897 switch (acl_enabled) {
903 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
904 jcr->last_fname, be.bstrerror());
905 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
906 jcr->last_fname, be.bstrerror());
907 return bacl_exit_error;
912 acltype = BACL_TYPE_ACCESS;
918 * If the filesystem reports it doesn't support ACLs we clear the
919 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
920 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
921 * when we change from one filesystem to an other.
923 if (acl_enabled == 0) {
924 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
925 pm_strcpy(jcr->acl_data->content, "");
926 jcr->acl_data->content_length = 0;
931 * Based on the supported ACLs retrieve and store them.
936 * Read NFS4 ACLs for files, dirs and links
938 if (generic_get_acl_from_os(jcr, BACL_TYPE_NFS4) == bacl_exit_fatal)
939 return bacl_exit_fatal;
941 if (jcr->acl_data->content_length > 0) {
942 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_NFS4_ACL) == bacl_exit_fatal)
943 return bacl_exit_fatal;
946 case BACL_TYPE_ACCESS:
948 * Read access ACLs for files, dirs and links
950 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
951 return bacl_exit_fatal;
953 if (jcr->acl_data->content_length > 0) {
954 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_ACCESS_ACL) == bacl_exit_fatal)
955 return bacl_exit_fatal;
959 * Directories can have default ACLs too
961 if (ff_pkt->type == FT_DIREND) {
962 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
963 return bacl_exit_fatal;
964 if (jcr->acl_data->content_length > 0) {
965 if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_DEFAULT_ACL) == bacl_exit_fatal)
966 return bacl_exit_fatal;
977 static bacl_exit_code freebsd_parse_acl_streams(JCR *jcr, int stream)
980 const char *acl_type_name;
984 * First make sure the filesystem supports acls.
987 case STREAM_UNIX_ACCESS_ACL:
988 case STREAM_ACL_FREEBSD_ACCESS_ACL:
989 case STREAM_UNIX_DEFAULT_ACL:
990 case STREAM_ACL_FREEBSD_DEFAULT_ACL:
991 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
992 acl_type_name = "POSIX";
994 case STREAM_ACL_FREEBSD_NFS4_ACL:
995 #if defined(_PC_ACL_NFS4)
996 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
998 acl_type_name = "NFS4";
1001 acl_type_name = "unknown";
1005 switch (acl_enabled) {
1009 return bacl_exit_ok;
1011 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1012 jcr->last_fname, be.bstrerror());
1013 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1014 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1015 return bacl_exit_error;
1018 Mmsg2(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without %s acl support\n"),
1019 jcr->last_fname, acl_type_name);
1020 return bacl_exit_error;
1029 case STREAM_UNIX_ACCESS_ACL:
1030 case STREAM_ACL_FREEBSD_ACCESS_ACL:
1031 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
1032 case STREAM_UNIX_DEFAULT_ACL:
1033 case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1034 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
1035 case STREAM_ACL_FREEBSD_NFS4_ACL:
1036 return generic_set_acl_on_os(jcr, BACL_TYPE_NFS4);
1040 return bacl_exit_error;
1044 * For this OSes setup the build and parse function pointer to the OS specific functions.
1046 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = freebsd_build_acl_streams;
1047 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = freebsd_parse_acl_streams;
1049 #elif defined(HAVE_IRIX_OS) || \
1050 defined(HAVE_LINUX_OS)
1052 * Define the supported ACL streams for these OSes
1054 #if defined(HAVE_IRIX_OS)
1055 static int os_access_acl_streams[1] = { STREAM_ACL_IRIX_ACCESS_ACL };
1056 static int os_default_acl_streams[1] = { STREAM_ACL_IRIX_DEFAULT_ACL };
1057 #elif defined(HAVE_LINUX_OS)
1058 static int os_access_acl_streams[1] = { STREAM_ACL_LINUX_ACCESS_ACL };
1059 static int os_default_acl_streams[1] = { STREAM_ACL_LINUX_DEFAULT_ACL };
1062 static bacl_exit_code generic_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1065 * Read access ACLs for files, dirs and links
1067 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1068 return bacl_exit_fatal;
1070 if (jcr->acl_data->content_length > 0) {
1071 if (send_acl_stream(jcr, os_access_acl_streams[0]) == bacl_exit_fatal)
1072 return bacl_exit_fatal;
1076 * Directories can have default ACLs too
1078 if (ff_pkt->type == FT_DIREND) {
1079 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
1080 return bacl_exit_fatal;
1081 if (jcr->acl_data->content_length > 0) {
1082 if (send_acl_stream(jcr, os_default_acl_streams[0]) == bacl_exit_fatal)
1083 return bacl_exit_fatal;
1086 return bacl_exit_ok;
1089 static bacl_exit_code generic_parse_acl_streams(JCR *jcr, int stream)
1094 case STREAM_UNIX_ACCESS_ACL:
1095 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
1096 case STREAM_UNIX_DEFAULT_ACL:
1097 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
1100 * See what type of acl it is.
1102 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1103 if (os_access_acl_streams[cnt] == stream) {
1104 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
1107 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1108 if (os_default_acl_streams[cnt] == stream) {
1109 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
1114 return bacl_exit_error;
1118 * For this OSes setup the build and parse function pointer to the OS specific functions.
1120 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_build_acl_streams;
1121 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = generic_parse_acl_streams;
1123 #elif defined(HAVE_OSF1_OS)
1126 * Define the supported ACL streams for this OS
1128 static int os_access_acl_streams[1] = { STREAM_ACL_TRU64_ACCESS_ACL };
1129 static int os_default_acl_streams[2] = { STREAM_ACL_TRU64_DEFAULT_ACL, STREAM_ACL_TRU64_DEFAULT_DIR_ACL };
1131 static bacl_exit_code tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1134 * Read access ACLs for files, dirs and links
1136 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
1137 return bacl_exit_error;
1138 if (jcr->acl_data->content_length > 0) {
1139 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL))
1140 return bacl_exit_error;
1143 * Directories can have default ACLs too
1145 if (ff_pkt->type == FT_DIREND) {
1146 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
1147 return bacl_exit_error;
1148 if (jcr->acl_data->content_length > 0) {
1149 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL))
1150 return bacl_exit_error;
1153 * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
1154 * This is an inherited acl for all subdirs.
1155 * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
1156 * Section 21.5 Default ACLs
1158 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR)) < 0)
1159 return bacl_exit_error;
1160 if (jcr->acl_data->content_length > 0) {
1161 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL))
1162 return bacl_exit_error;
1165 return bacl_exit_ok;
1168 static bacl_exit_code tru64_parse_acl_streams(JCR *jcr, int stream)
1171 case STREAM_UNIX_ACCESS_ACL:
1172 case STREAM_ACL_TRU64_ACCESS_ACL:
1173 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
1174 case STREAM_UNIX_DEFAULT_ACL:
1175 case STREAM_ACL_TRU64_DEFAULT_ACL:
1176 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
1177 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
1178 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR);
1182 * For this OS setup the build and parse function pointer to the OS specific functions.
1184 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = tru64_build_acl_streams;
1185 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = tru64_parse_acl_streams;
1189 #elif defined(HAVE_HPUX_OS)
1190 #ifdef HAVE_SYS_ACL_H
1191 #include <sys/acl.h>
1193 #error "configure failed to detect availability of sys/acl.h"
1199 * Define the supported ACL streams for this OS
1201 static int os_access_acl_streams[1] = { STREAM_ACL_HPUX_ACL_ENTRY };
1202 static int os_default_acl_streams[1] = { -1 };
1205 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1206 * There is no need to store those acls as we already store the stat bits too.
1208 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
1211 struct acl_entry ace
1213 for (n = 0; n < count; n++) {
1216 * See if this acl just is the stat mode in acl form.
1218 if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
1219 (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
1220 (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
1227 * OS specific functions for handling different types of acl streams.
1229 static bacl_exit_code hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1232 struct acl_entry acls[NACLENTRIES];
1236 if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
1238 #if defined(BACL_ENOTSUP)
1241 * Not supported, just pretend there is nothing to see
1243 * If the filesystem reports it doesn't support ACLs we clear the
1244 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1245 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1246 * when we change from one filesystem to an other.
1248 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1249 pm_strcpy(jcr->acl_data->content, "");
1250 jcr->acl_data->content_length = 0;
1251 return bacl_exit_ok;
1254 pm_strcpy(jcr->acl_data->content, "");
1255 jcr->acl_data->content_length = 0;
1256 return bacl_exit_ok;
1258 Mmsg2(jcr->errmsg, _("getacl error on file \"%s\": ERR=%s\n"),
1259 jcr->last_fname, be.bstrerror());
1260 Dmsg2(100, "getacl error file=%s ERR=%s\n",
1261 jcr->last_fname, be.bstrerror());
1263 pm_strcpy(jcr->acl_data->content, "");
1264 jcr->acl_data->content_length = 0;
1265 return bacl_exit_error;
1269 pm_strcpy(jcr->acl_data->content, "");
1270 jcr->acl_data->content_length = 0;
1271 return bacl_exit_ok;
1273 if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
1274 if (acl_is_trivial(n, acls, ff_pkt->statp)) {
1276 * The ACLs simply reflect the (already known) standard permissions
1277 * So we don't send an ACL stream to the SD.
1279 pm_strcpy(jcr->acl_data->content, "");
1280 jcr->acl_data->content_length = 0;
1281 return bacl_exit_ok;
1283 if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
1284 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1285 actuallyfree(acl_text);
1287 return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
1289 Mmsg2(jcr->errmsg, _("acltostr error on file \"%s\": ERR=%s\n"),
1290 jcr->last_fname, be.bstrerror());
1291 Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",
1292 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1293 return bacl_exit_error;
1295 return bacl_exit_error;
1298 static bacl_exit_code hpux_parse_acl_streams(JCR *jcr, int stream)
1301 struct acl_entry acls[NACLENTRIES];
1304 n = strtoacl(jcr->acl_data->content, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
1306 Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
1307 jcr->last_fname, be.bstrerror());
1308 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
1309 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1310 return bacl_exit_error;
1312 if (strtoacl(jcr->acl_data->content, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
1313 Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
1314 jcr->last_fname, be.bstrerror());
1315 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
1316 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1318 return bacl_exit_error;
1321 * Restore the ACLs, but don't complain about links which really should
1322 * not have attributes, and the file it is linked to may not yet be restored.
1323 * This is only true for the old acl streams as in the new implementation we
1324 * don't save acls of symlinks (which cannot have acls anyhow)
1326 if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
1329 return bacl_exit_ok;
1331 Mmsg2(jcr->errmsg, _("setacl error on file \"%s\": ERR=%s\n"),
1332 jcr->last_fname, be.bstrerror());
1333 Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
1334 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1335 return bacl_exit_error;
1338 return bacl_exit_ok;
1342 * For this OS setup the build and parse function pointer to the OS specific functions.
1344 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = hpux_build_acl_streams;
1345 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = hpux_parse_acl_streams;
1347 #elif defined(HAVE_SUN_OS)
1348 #ifdef HAVE_SYS_ACL_H
1349 #include <sys/acl.h>
1351 #error "configure failed to detect availability of sys/acl.h"
1354 #if defined(HAVE_EXTENDED_ACL)
1356 * We define some internals of the Solaris acl libs here as those
1357 * are not exposed yet. Probably because they want us to see the
1358 * acls as opague data. But as we need to support different platforms
1359 * and versions of Solaris we need to expose some data to be able
1360 * to determine the type of acl used to stuff it into the correct
1361 * data stream. I know this is far from portable, but maybe the
1362 * proper interface is exposed later on and we can get ride of
1363 * this kludge. Newer versions of Solaris include sys/acl_impl.h
1364 * which has implementation details of acls, if thats included we
1365 * don't have to define it ourself.
1367 #if !defined(_SYS_ACL_IMPL_H)
1368 typedef enum acl_type {
1375 * Two external references to functions in the libsec library function not in current include files.
1378 int acl_type(acl_t *);
1379 char *acl_strerror(int);
1383 * Define the supported ACL streams for this OS
1385 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT, STREAM_ACL_SOLARIS_ACE };
1386 static int os_default_acl_streams[1] = { -1 };
1389 * As the new libsec interface with acl_totext and acl_fromtext also handles
1390 * the old format from acltotext we can use the new functions even
1391 * for acls retrieved and stored in the database with older fd versions. If the
1392 * new interface is not defined (Solaris 9 and older we fall back to the old code)
1394 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1396 int acl_enabled, flags;
1399 bacl_exit_code stream_status = bacl_exit_error;
1403 * See if filesystem supports acls.
1405 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1406 switch (acl_enabled) {
1409 * If the filesystem reports it doesn't support ACLs we clear the
1410 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1411 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1412 * when we change from one filesystem to an other.
1414 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1415 pm_strcpy(jcr->acl_data->content, "");
1416 jcr->acl_data->content_length = 0;
1417 return bacl_exit_ok;
1421 return bacl_exit_ok;
1423 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1424 jcr->last_fname, be.bstrerror());
1425 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
1426 jcr->last_fname, be.bstrerror());
1427 return bacl_exit_error;
1434 * Get ACL info: don't bother allocating space if there is only a trivial ACL.
1436 if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
1439 return bacl_exit_ok;
1441 Mmsg2(jcr->errmsg, _("acl_get error on file \"%s\": ERR=%s\n"),
1442 jcr->last_fname, acl_strerror(errno));
1443 Dmsg2(100, "acl_get error file=%s ERR=%s\n",
1444 jcr->last_fname, acl_strerror(errno));
1445 return bacl_exit_error;
1451 * The ACLs simply reflect the (already known) standard permissions
1452 * So we don't send an ACL stream to the SD.
1454 pm_strcpy(jcr->acl_data->content, "");
1455 jcr->acl_data->content_length = 0;
1456 return bacl_exit_ok;
1459 #if defined(ACL_SID_FMT)
1461 * New format flag added in newer Solaris versions.
1463 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
1465 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
1466 #endif /* ACL_SID_FMT */
1468 if ((acl_text = acl_totext(aclp, flags)) != NULL) {
1469 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1470 actuallyfree(acl_text);
1472 switch (acl_type(aclp)) {
1474 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1477 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE);
1485 return stream_status;
1488 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
1491 int acl_enabled, error;
1495 case STREAM_UNIX_ACCESS_ACL:
1496 case STREAM_ACL_SOLARIS_ACLENT:
1497 case STREAM_ACL_SOLARIS_ACE:
1499 * First make sure the filesystem supports acls.
1501 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1502 switch (acl_enabled) {
1504 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
1506 return bacl_exit_error;
1510 return bacl_exit_ok;
1512 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1513 jcr->last_fname, be.bstrerror());
1514 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1515 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1516 return bacl_exit_error;
1520 * On a filesystem with ACL support make sure this particular ACL type can be restored.
1523 case STREAM_ACL_SOLARIS_ACLENT:
1525 * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
1527 if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
1528 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without aclent acl support\n"),
1530 return bacl_exit_error;
1533 case STREAM_ACL_SOLARIS_ACE:
1535 * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
1537 if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
1538 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without ace acl support\n"),
1540 return bacl_exit_error;
1545 * Stream id which doesn't describe the type of acl which is encoded.
1552 if ((error = acl_fromtext(jcr->acl_data->content, &aclp)) != 0) {
1553 Mmsg2(jcr->errmsg, _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1554 jcr->last_fname, acl_strerror(error));
1555 Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",
1556 jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1557 return bacl_exit_error;
1561 * Validate that the conversion gave us the correct acl type.
1564 case STREAM_ACL_SOLARIS_ACLENT:
1565 if (acl_type(aclp) != ACLENT_T) {
1566 Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1568 return bacl_exit_error;
1571 case STREAM_ACL_SOLARIS_ACE:
1572 if (acl_type(aclp) != ACE_T) {
1573 Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1575 return bacl_exit_error;
1580 * Stream id which doesn't describe the type of acl which is encoded.
1586 * Restore the ACLs, but don't complain about links which really should
1587 * not have attributes, and the file it is linked to may not yet be restored.
1588 * This is only true for the old acl streams as in the new implementation we
1589 * don't save acls of symlinks (which cannot have acls anyhow)
1591 if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1595 return bacl_exit_ok;
1597 Mmsg2(jcr->errmsg, _("acl_set error on file \"%s\": ERR=%s\n"),
1598 jcr->last_fname, acl_strerror(error));
1599 Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",
1600 jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1602 return bacl_exit_error;
1607 return bacl_exit_ok;
1609 return bacl_exit_error;
1610 } /* end switch (stream) */
1613 #else /* HAVE_EXTENDED_ACL */
1616 * Define the supported ACL streams for this OS
1618 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT };
1619 static int os_default_acl_streams[1] = { -1 };
1622 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1623 * There is no need to store those acls as we already store the stat bits too.
1625 static bool acl_is_trivial(int count, aclent_t *entries)
1630 for (n = 0; n < count; n++) {
1633 if (!(ace->a_type == USER_OBJ ||
1634 ace->a_type == GROUP_OBJ ||
1635 ace->a_type == OTHER_OBJ ||
1636 ace->a_type == CLASS_OBJ))
1643 * OS specific functions for handling different types of acl streams.
1645 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1652 n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1653 if (n < MIN_ACL_ENTRIES)
1654 return bacl_exit_error;
1656 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1657 if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1658 if (acl_is_trivial(n, acls)) {
1660 * The ACLs simply reflect the (already known) standard permissions
1661 * So we don't send an ACL stream to the SD.
1664 pm_strcpy(jcr->acl_data->content, "");
1665 jcr->acl_data->content_length = 0;
1666 return bacl_exit_ok;
1669 if ((acl_text = acltotext(acls, n)) != NULL) {
1670 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1671 actuallyfree(acl_text);
1673 return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1676 Mmsg2(jcr->errmsg, _("acltotext error on file \"%s\": ERR=%s\n"),
1677 jcr->last_fname, be.bstrerror());
1678 Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",
1679 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1683 return bacl_exit_error;
1686 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
1692 acls = aclfromtext(jcr->acl_data->content, &n);
1694 Mmsg2(jcr->errmsg, _("aclfromtext error on file \"%s\": ERR=%s\n"),
1695 jcr->last_fname, be.bstrerror());
1696 Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",
1697 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1698 return bacl_exit_error;
1702 * Restore the ACLs, but don't complain about links which really should
1703 * not have attributes, and the file it is linked to may not yet be restored.
1705 if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
1709 return bacl_exit_ok;
1711 Mmsg2(jcr->errmsg, _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
1712 jcr->last_fname, be.bstrerror());
1713 Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
1714 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1716 return bacl_exit_error;
1720 return bacl_exit_ok;
1722 #endif /* HAVE_EXTENDED_ACL */
1725 * For this OS setup the build and parse function pointer to the OS specific functions.
1727 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_acl_streams;
1728 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = solaris_parse_acl_streams;
1730 #endif /* HAVE_SUN_OS */
1731 #endif /* HAVE_ACL */
1734 * Entry points when compiled with support for ACLs on a supported platform.
1738 * Read and send an ACL for the last encountered file.
1740 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1743 * See if we are changing from one device to an other.
1744 * We save the current device we are scanning and compare
1745 * it with the current st_dev in the last stat performed on
1746 * the file we are currently storing.
1748 if (jcr->acl_data->current_dev != ff_pkt->statp.st_dev) {
1750 * Reset the acl save flags.
1752 jcr->acl_data->flags = 0;
1754 jcr->acl_data->flags |= BACL_FLAG_SAVE_NATIVE;
1757 * Save that we started scanning a new filesystem.
1759 jcr->acl_data->current_dev = ff_pkt->statp.st_dev;
1762 #if defined(HAVE_ACL)
1764 * See if the BACL_FLAG_SAVE_NATIVE flag is set which lets us know if we should
1767 if (jcr->acl_data->flags & BACL_FLAG_SAVE_NATIVE) {
1769 * Call the appropriate function.
1771 if (os_build_acl_streams) {
1772 return (*os_build_acl_streams)(jcr, ff_pkt);
1775 return bacl_exit_ok;
1778 return bacl_exit_error;
1781 bacl_exit_code parse_acl_streams(JCR *jcr, int stream)
1786 #if defined(HAVE_ACL)
1787 case STREAM_UNIX_ACCESS_ACL:
1788 case STREAM_UNIX_DEFAULT_ACL:
1790 * Handle legacy ACL streams.
1792 if (os_parse_acl_streams) {
1793 return (*os_parse_acl_streams)(jcr, stream);
1797 if (os_parse_acl_streams) {
1799 * Walk the os_access_acl_streams array with the supported Access ACL streams for this OS.
1801 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1802 if (os_access_acl_streams[cnt] == stream) {
1803 return (*os_parse_acl_streams)(jcr, stream);
1807 * Walk the os_default_acl_streams array with the supported Default ACL streams for this OS.
1809 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1810 if (os_default_acl_streams[cnt] == stream) {
1811 return (*os_parse_acl_streams)(jcr, stream);
1821 Qmsg2(jcr, M_WARNING, 0,
1822 _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
1823 jcr->last_fname, stream);
1824 return bacl_exit_error;