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 two of the GNU 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 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 * We handle two different types of ACLs: access and default ACLS.
32 * On most systems that support default ACLs they only apply to directories.
34 * On some systems (eg. linux and FreeBSD) we must obtain the two ACLs
35 * independently, while others (eg. Solaris) provide both in one call.
37 * The Filed saves ACLs in their native format and uses different streams
38 * for all different platforms. Currently we only allow ACLs to be restored
39 * which were saved in the native format of the platform they are extracted
40 * on. Later on we might add conversion functions for mapping from one
41 * platform to an other or allow restores of systems that use the same
44 * Its also interesting to see what the exact format of acl text is on
45 * certain platforms and if they use they same encoding we might allow
46 * different platform streams to be decoded on an other similar platform.
48 * Original written by Preben 'Peppe' Guldberg, December MMIV
49 * Major rewrite by Marco van Wieringen, November MMVIII
55 #if !defined(HAVE_ACL) && !defined(HAVE_AFS_ACL)
57 * Entry points when compiled without support for ACLs or on an unsupported platform.
59 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
61 return bacl_exit_fatal;
64 bacl_exit_code parse_acl_streams(JCR *jcr, int stream)
66 return bacl_exit_fatal;
70 * Send an ACL stream to the SD.
72 static bacl_exit_code send_acl_stream(JCR *jcr, int stream)
74 BSOCK *sd = jcr->store_bsock;
76 #ifdef FD_NO_SEND_TEST
83 if (jcr->acl_data->content_length <= 0) {
90 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
91 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
93 return bacl_exit_fatal;
97 * Send the buffer to the storage deamon
99 Dmsg1(400, "Backing up ACL <%s>\n", jcr->acl_data->content);
101 sd->msg = jcr->acl_data->content;
102 sd->msglen = jcr->acl_data->content_length + 1;
106 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
108 return bacl_exit_fatal;
111 jcr->JobBytes += sd->msglen;
113 if (!sd->signal(BNET_EOD)) {
114 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
116 return bacl_exit_fatal;
119 Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
124 * First the native ACLs.
126 #if defined(HAVE_ACL)
127 #if defined(HAVE_AIX_OS)
129 #include <sys/access.h>
132 * Define the supported ACL streams for this OS
134 static int os_access_acl_streams[1] = { STREAM_ACL_AIX_TEXT };
135 static int os_default_acl_streams[1] = { -1 };
137 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
141 if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
142 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
143 actuallyfree(acl_text);
144 return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT);
146 return bacl_exit_error;
149 static bacl_exit_code aix_parse_acl_streams(JCR *jcr, int stream)
151 if (acl_put(jcr->last_fname, jcr->acl_data->content, 0) != 0) {
152 return bacl_exit_error;
158 * For this OS setup the build and parse function pointer to the OS specific functions.
160 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = aix_build_acl_streams;
161 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = aix_parse_acl_streams;
163 #elif defined(HAVE_DARWIN_OS) || \
164 defined(HAVE_FREEBSD_OS) || \
165 defined(HAVE_IRIX_OS) || \
166 defined(HAVE_OSF1_OS) || \
167 defined(HAVE_LINUX_OS)
169 #include <sys/types.h>
171 #ifdef HAVE_SYS_ACL_H
174 #error "configure failed to detect availability of sys/acl.h"
178 * On IRIX we can get shortened ACLs
180 #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
181 #define acl_to_text(acl,len) acl_to_short_text((acl), (len))
185 * In Linux we can get numeric and/or shorted ACLs
187 #if defined(HAVE_LINUX_OS)
188 #if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
189 #define BACL_ALTERNATE_TEXT (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
190 #elif defined(BACL_WANT_SHORT_ACLS)
191 #define BACL_ALTERNATE_TEXT TEXT_ABBREVIATE
192 #elif defined(BACL_WANT_NUMERIC_IDS)
193 #define BACL_ALTERNATE_TEXT TEXT_NUMERIC_IDS
195 #ifdef BACL_ALTERNATE_TEXT
196 #include <acl/libacl.h>
197 #define acl_to_text(acl,len) (acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
202 * Some generic functions used by multiple OSes.
204 static acl_type_t bac_to_os_acltype(bacl_type acltype)
209 case BACL_TYPE_ACCESS:
210 ostype = ACL_TYPE_ACCESS;
212 case BACL_TYPE_DEFAULT:
213 ostype = ACL_TYPE_DEFAULT;
216 #ifdef ACL_TYPE_DEFAULT_DIR
217 case BACL_TYPE_DEFAULT_DIR:
219 * OSF1 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
221 ostype = ACL_TYPE_DEFAULT_DIR;
224 #ifdef ACL_TYPE_EXTENDED
225 case BACL_TYPE_EXTENDED:
227 * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
229 ostype = ACL_TYPE_EXTENDED;
234 * This should never happen, as the per OS version function only tries acl
235 * types supported on a certain platform.
237 ostype = (acl_type_t)ACL_TYPE_NONE;
243 #if !defined(HAVE_DARWIN_OS)
245 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
246 * There is no need to store those acls as we already store the stat bits too.
248 static bool acl_is_trivial(acl_t acl)
251 * acl is trivial if it has only the following entries:
258 #if defined(HAVE_FREEBSD_OS) || \
259 defined(HAVE_LINUX_OS)
262 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
263 while (entry_available == 1) {
265 * Get the tag type of this acl entry.
266 * If we fail to get the tagtype we call the acl non-trivial.
268 if (acl_get_tag_type(ace, &tag) < 0)
271 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
273 if (tag != ACL_USER_OBJ &&
274 tag != ACL_GROUP_OBJ &&
277 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
280 #elif defined(HAVE_IRIX_OS)
283 for (n = 0; n < acl->acl_cnt; n++) {
284 ace = &acl->acl_entry[n];
288 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
290 if (tag != ACL_USER_OBJ &&
291 tag != ACL_GROUP_OBJ &&
292 tag != ACL_OTHER_OBJ)
296 #elif defined(HAVE_OSF1_OS)
299 ace = acl->acl_first;
300 count = acl->acl_num;
303 tag = ace->entry->acl_type;
305 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
307 if (tag != ACL_USER_OBJ &&
308 tag != ACL_GROUP_OBJ &&
312 * On Tru64, perm can also contain non-standard bits such as
313 * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
315 if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
326 * Generic wrapper around acl_get_file call.
328 static bacl_exit_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
335 ostype = bac_to_os_acltype(acltype);
336 acl = acl_get_file(jcr->last_fname, ostype);
338 #if defined(HAVE_IRIX_OS)
340 * From observation, IRIX's acl_get_file() seems to return a
341 * non-NULL acl with a count field of -1 when a file has no ACL
342 * defined, while IRIX's acl_to_text() returns NULL when presented
345 * Checking the count in the acl structure before calling
346 * acl_to_text() lets us avoid error messages about files
347 * with no ACLs, without modifying the flow of the code used for
348 * other operating systems, and it saves making some calls
349 * to acl_to_text() besides.
351 if (acl->acl_cnt <= 0) {
352 pm_strcpy(jcr->acl_data->content, "");
353 jcr->acl_data->content_length = 0;
359 #if !defined(HAVE_DARWIN_OS)
361 * Make sure this is not just a trivial ACL.
363 if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
365 * The ACLs simply reflect the (already known) standard permissions
366 * So we don't send an ACL stream to the SD.
368 pm_strcpy(jcr->acl_data->content, "");
369 jcr->acl_data->content_length = 0;
375 if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
376 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
382 Mmsg2(jcr->errmsg, _("acl_to_text error on file \"%s\": ERR=%s\n"),
383 jcr->last_fname, be.bstrerror());
384 Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",
385 jcr->last_fname, be.bstrerror());
387 pm_strcpy(jcr->acl_data->content, "");
388 jcr->acl_data->content_length = 0;
390 return bacl_exit_error;
394 * Handle errors gracefully.
396 if (acl == (acl_t)NULL) {
398 #if defined(BACL_ENOTSUP)
401 * If the filesystem reports it doesn't support ACLs we clear the
402 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
403 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
404 * when we change from one filesystem to an other.
406 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
407 break; /* not supported */
410 pm_strcpy(jcr->acl_data->content, "");
411 jcr->acl_data->content_length = 0;
414 /* Some real error */
415 Mmsg2(jcr->errmsg, _("acl_get_file error on file \"%s\": ERR=%s\n"),
416 jcr->last_fname, be.bstrerror());
417 Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",
418 jcr->last_fname, be.bstrerror());
420 pm_strcpy(jcr->acl_data->content, "");
421 jcr->acl_data->content_length = 0;
422 return bacl_exit_error;
427 * Not supported, just pretend there is nothing to see
429 pm_strcpy(jcr->acl_data->content, "");
430 jcr->acl_data->content_length = 0;
435 * Generic wrapper around acl_set_file call.
437 static bacl_exit_code generic_set_acl_on_os(JCR *jcr, bacl_type acltype)
444 * If we get empty default ACLs, clear ACLs now
446 ostype = bac_to_os_acltype(acltype);
447 if (ostype == ACL_TYPE_DEFAULT && strlen(jcr->acl_data->content) == 0) {
448 if (acl_delete_def_file(jcr->last_fname) == 0) {
455 Mmsg2(jcr->errmsg, _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
456 jcr->last_fname, be.bstrerror());
457 return bacl_exit_error;
461 acl = acl_from_text(jcr->acl_data->content);
463 Mmsg2(jcr->errmsg, _("acl_from_text error on file \"%s\": ERR=%s\n"),
464 jcr->last_fname, be.bstrerror());
465 Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",
466 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
467 return bacl_exit_error;
470 #ifndef HAVE_FREEBSD_OS
472 * FreeBSD always fails acl_valid() - at least on valid input...
473 * As it does the right thing, given valid input, just ignore acl_valid().
475 if (acl_valid(acl) != 0) {
476 Mmsg2(jcr->errmsg, _("acl_valid error on file \"%s\": ERR=%s\n"),
477 jcr->last_fname, be.bstrerror());
478 Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",
479 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
481 return bacl_exit_error;
486 * Restore the ACLs, but don't complain about links which really should
487 * not have attributes, and the file it is linked to may not yet be restored.
488 * This is only true for the old acl streams as in the new implementation we
489 * don't save acls of symlinks (which cannot have acls anyhow)
491 if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
497 Mmsg2(jcr->errmsg, _("acl_set_file error on file \"%s\": ERR=%s\n"),
498 jcr->last_fname, be.bstrerror());
499 Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
500 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
502 return bacl_exit_error;
510 * OS specific functions for handling different types of acl streams.
512 #if defined(HAVE_DARWIN_OS)
514 * Define the supported ACL streams for this OS
516 static int os_access_acl_streams[1] = { STREAM_ACL_DARWIN_ACCESS_ACL };
517 static int os_default_acl_streams[1] = { -1 };
519 static bacl_exit_code darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
521 #if defined(ACL_TYPE_EXTENDED)
523 * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
524 * and acl_get_file (name, ACL_TYPE_DEFAULT)
525 * always return NULL / EINVAL. There is no point in making
526 * these two useless calls. The real ACL is retrieved through
527 * acl_get_file (name, ACL_TYPE_EXTENDED).
529 * Read access ACLs for files, dirs and links
531 if (generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED) == bacl_exit_fatal)
532 return bacl_exit_fatal;
535 * Read access ACLs for files, dirs and links
537 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
538 return bacl_exit_fatal;
541 if (jcr->acl_data->content_length > 0) {
542 return send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL);
547 static bacl_exit_code darwin_parse_acl_streams(JCR *jcr, int stream)
549 #if defined(ACL_TYPE_EXTENDED)
550 return generic_set_acl_on_os(jcr, BACL_TYPE_EXTENDED);
552 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
557 * For this OS setup the build and parse function pointer to the OS specific functions.
559 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = darwin_build_acl_streams;
560 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = darwin_parse_acl_streams;
562 #elif defined(HAVE_FREEBSD_OS) || \
563 defined(HAVE_IRIX_OS) || \
564 defined(HAVE_LINUX_OS)
567 * Define the supported ACL streams for these OSes
569 #if defined(HAVE_FREEBSD_OS)
570 static int os_access_acl_streams[1] = { STREAM_ACL_FREEBSD_ACCESS_ACL };
571 static int os_default_acl_streams[1] = { STREAM_ACL_FREEBSD_DEFAULT_ACL };
572 #elif defined(HAVE_IRIX_OS)
573 static int os_access_acl_streams[1] = { STREAM_ACL_IRIX_ACCESS_ACL };
574 static int os_default_acl_streams[1] = { STREAM_ACL_IRIX_DEFAULT_ACL };
575 #elif defined(HAVE_LINUX_OS)
576 static int os_access_acl_streams[1] = { STREAM_ACL_LINUX_ACCESS_ACL };
577 static int os_default_acl_streams[1] = { STREAM_ACL_LINUX_DEFAULT_ACL };
580 static bacl_exit_code generic_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
583 * Read access ACLs for files, dirs and links
585 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
586 return bacl_exit_fatal;
588 if (jcr->acl_data->content_length > 0) {
589 if (send_acl_stream(jcr, os_access_acl_streams[0]) == bacl_exit_fatal)
590 return bacl_exit_fatal;
594 * Directories can have default ACLs too
596 if (ff_pkt->type == FT_DIREND) {
597 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
598 return bacl_exit_fatal;
599 if (jcr->acl_data->content_length > 0) {
600 if (send_acl_stream(jcr, os_default_acl_streams[0]) == bacl_exit_fatal)
601 return bacl_exit_fatal;
607 static bacl_exit_code generic_parse_acl_streams(JCR *jcr, int stream)
612 case STREAM_UNIX_ACCESS_ACL:
613 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
614 case STREAM_UNIX_DEFAULT_ACL:
615 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
618 * See what type of acl it is.
620 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
621 if (os_access_acl_streams[cnt] == stream) {
622 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
625 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
626 if (os_default_acl_streams[cnt] == stream) {
627 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
632 return bacl_exit_error;
636 * For this OSes setup the build and parse function pointer to the OS specific functions.
638 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_build_acl_streams;
639 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = generic_parse_acl_streams;
641 #elif defined(HAVE_OSF1_OS)
644 * Define the supported ACL streams for this OS
646 static int os_access_acl_streams[1] = { STREAM_ACL_TRU64_ACCESS_ACL };
647 static int os_default_acl_streams[2] = { STREAM_ACL_TRU64_DEFAULT_ACL, STREAM_ACL_TRU64_DEFAULT_DIR_ACL };
649 static bacl_exit_code tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
652 * Read access ACLs for files, dirs and links
654 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
655 return bacl_exit_error;
656 if (jcr->acl_data->content_length > 0) {
657 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL))
658 return bacl_exit_error;
661 * Directories can have default ACLs too
663 if (ff_pkt->type == FT_DIREND) {
664 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
665 return bacl_exit_error;
666 if (jcr->acl_data->content_length > 0) {
667 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL))
668 return bacl_exit_error;
671 * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
672 * This is an inherited acl for all subdirs.
673 * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
674 * Section 21.5 Default ACLs
676 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR)) < 0)
677 return bacl_exit_error;
678 if (jcr->acl_data->content_length > 0) {
679 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL))
680 return bacl_exit_error;
686 static bacl_exit_code tru64_parse_acl_streams(JCR *jcr, int stream)
689 case STREAM_UNIX_ACCESS_ACL:
690 case STREAM_ACL_TRU64_ACCESS_ACL:
691 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
692 case STREAM_UNIX_DEFAULT_ACL:
693 case STREAM_ACL_TRU64_DEFAULT_ACL:
694 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
695 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
696 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR);
700 * For this OS setup the build and parse function pointer to the OS specific functions.
702 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = tru64_build_acl_streams;
703 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = tru64_parse_acl_streams;
707 #elif defined(HAVE_HPUX_OS)
708 #ifdef HAVE_SYS_ACL_H
711 #error "configure failed to detect availability of sys/acl.h"
717 * Define the supported ACL streams for this OS
719 static int os_access_acl_streams[1] = { STREAM_ACL_HPUX_ACL_ENTRY };
720 static int os_default_acl_streams[1] = { -1 };
723 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
724 * There is no need to store those acls as we already store the stat bits too.
726 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
731 for (n = 0; n < count; n++) {
734 * See if this acl just is the stat mode in acl form.
736 if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
737 (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
738 (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
745 * OS specific functions for handling different types of acl streams.
747 static bacl_exit_code hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
750 struct acl_entry acls[NACLENTRIES];
754 if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
756 #if defined(BACL_ENOTSUP)
759 * Not supported, just pretend there is nothing to see
761 * If the filesystem reports it doesn't support ACLs we clear the
762 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
763 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
764 * when we change from one filesystem to an other.
766 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
767 pm_strcpy(jcr->acl_data->content, "");
768 jcr->acl_data->content_length = 0;
772 pm_strcpy(jcr->acl_data->content, "");
773 jcr->acl_data->content_length = 0;
776 Mmsg2(jcr->errmsg, _("getacl error on file \"%s\": ERR=%s\n"),
777 jcr->last_fname, be.bstrerror());
778 Dmsg2(100, "getacl error file=%s ERR=%s\n",
779 jcr->last_fname, be.bstrerror());
781 pm_strcpy(jcr->acl_data->content, "");
782 jcr->acl_data->content_length = 0;
783 return bacl_exit_error;
787 pm_strcpy(jcr->acl_data->content, "");
788 jcr->acl_data->content_length = 0;
791 if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
792 if (acl_is_trivial(n, acls, ff_pkt->statp)) {
794 * The ACLs simply reflect the (already known) standard permissions
795 * So we don't send an ACL stream to the SD.
797 pm_strcpy(jcr->acl_data->content, "");
798 jcr->acl_data->content_length = 0;
801 if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
802 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
803 actuallyfree(acl_text);
805 return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
807 Mmsg2(jcr->errmsg, _("acltostr error on file \"%s\": ERR=%s\n"),
808 jcr->last_fname, be.bstrerror());
809 Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",
810 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
811 return bacl_exit_error;
813 return bacl_exit_error;
816 static bacl_exit_code hpux_parse_acl_streams(JCR *jcr, int stream)
819 struct acl_entry acls[NACLENTRIES];
822 n = strtoacl(jcr->acl_data->content, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
824 Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
825 jcr->last_fname, be.bstrerror());
826 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
827 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
828 return bacl_exit_error;
830 if (strtoacl(jcr->acl_data->content, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
831 Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
832 jcr->last_fname, be.bstrerror());
833 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
834 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
836 return bacl_exit_error;
839 * Restore the ACLs, but don't complain about links which really should
840 * not have attributes, and the file it is linked to may not yet be restored.
841 * This is only true for the old acl streams as in the new implementation we
842 * don't save acls of symlinks (which cannot have acls anyhow)
844 if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
849 Mmsg2(jcr->errmsg, _("setacl error on file \"%s\": ERR=%s\n"),
850 jcr->last_fname, be.bstrerror());
851 Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
852 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
853 return bacl_exit_error;
860 * For this OS setup the build and parse function pointer to the OS specific functions.
862 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = hpux_build_acl_streams;
863 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = hpux_parse_acl_streams;
865 #elif defined(HAVE_SUN_OS)
866 #ifdef HAVE_SYS_ACL_H
869 #error "configure failed to detect availability of sys/acl.h"
872 #if defined(HAVE_EXTENDED_ACL)
874 * We define some internals of the Solaris acl libs here as those
875 * are not exposed yet. Probably because they want us to see the
876 * acls as opague data. But as we need to support different platforms
877 * and versions of Solaris we need to expose some data to be able
878 * to determine the type of acl used to stuff it into the correct
879 * data stream. I know this is far from portable, but maybe the
880 * proper interface is exposed later on and we can get ride of
881 * this kludge. Newer versions of Solaris include sys/acl_impl.h
882 * which has implementation details of acls, if thats included we
883 * don't have to define it ourself.
885 #if !defined(_SYS_ACL_IMPL_H)
886 typedef enum acl_type {
893 * Two external references to functions in the libsec library function not in current include files.
896 int acl_type(acl_t *);
897 char *acl_strerror(int);
901 * Define the supported ACL streams for this OS
903 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT, STREAM_ACL_SOLARIS_ACE };
904 static int os_default_acl_streams[1] = { -1 };
907 * As the new libsec interface with acl_totext and acl_fromtext also handles
908 * the old format from acltotext we can use the new functions even
909 * for acls retrieved and stored in the database with older fd versions. If the
910 * new interface is not defined (Solaris 9 and older we fall back to the old code)
912 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
914 int acl_enabled, flags;
917 bacl_exit_code stream_status = bacl_exit_error;
921 * See if filesystem supports acls.
923 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
924 switch (acl_enabled) {
927 * If the filesystem reports it doesn't support ACLs we clear the
928 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
929 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
930 * when we change from one filesystem to an other.
932 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
933 pm_strcpy(jcr->acl_data->content, "");
934 jcr->acl_data->content_length = 0;
941 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
942 jcr->last_fname, be.bstrerror());
943 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
944 jcr->last_fname, be.bstrerror());
945 return bacl_exit_error;
952 * Get ACL info: don't bother allocating space if there is only a trivial ACL.
954 if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
959 Mmsg2(jcr->errmsg, _("acl_get error on file \"%s\": ERR=%s\n"),
960 jcr->last_fname, acl_strerror(errno));
961 Dmsg2(100, "acl_get error file=%s ERR=%s\n",
962 jcr->last_fname, acl_strerror(errno));
963 return bacl_exit_error;
969 * The ACLs simply reflect the (already known) standard permissions
970 * So we don't send an ACL stream to the SD.
972 pm_strcpy(jcr->acl_data->content, "");
973 jcr->acl_data->content_length = 0;
977 #if defined(ACL_SID_FMT)
979 * New format flag added in newer Solaris versions.
981 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
983 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
984 #endif /* ACL_SID_FMT */
986 if ((acl_text = acl_totext(aclp, flags)) != NULL) {
987 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
988 actuallyfree(acl_text);
990 switch (acl_type(aclp)) {
992 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
995 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE);
1003 return stream_status;
1006 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
1009 int acl_enabled, error;
1013 case STREAM_UNIX_ACCESS_ACL:
1014 case STREAM_ACL_SOLARIS_ACLENT:
1015 case STREAM_ACL_SOLARIS_ACE:
1017 * First make sure the filesystem supports acls.
1019 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1020 switch (acl_enabled) {
1022 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
1024 return bacl_exit_error;
1028 return bacl_exit_ok;
1030 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1031 jcr->last_fname, be.bstrerror());
1032 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1033 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1034 return bacl_exit_error;
1038 * On a filesystem with ACL support make sure this particilar ACL type can be restored.
1041 case STREAM_ACL_SOLARIS_ACLENT:
1043 * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
1045 if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
1046 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without aclent acl support\n"),
1048 return bacl_exit_error;
1051 case STREAM_ACL_SOLARIS_ACE:
1053 * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
1055 if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
1056 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without ace acl support\n"),
1058 return bacl_exit_error;
1063 * Stream id which doesn't describe the type of acl which is encoded.
1070 if ((error = acl_fromtext(jcr->acl_data->content, &aclp)) != 0) {
1071 Mmsg2(jcr->errmsg, _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1072 jcr->last_fname, acl_strerror(error));
1073 Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",
1074 jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1075 return bacl_exit_error;
1079 * Validate that the conversion gave us the correct acl type.
1082 case STREAM_ACL_SOLARIS_ACLENT:
1083 if (acl_type(aclp) != ACLENT_T) {
1084 Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1086 return bacl_exit_error;
1089 case STREAM_ACL_SOLARIS_ACE:
1090 if (acl_type(aclp) != ACE_T) {
1091 Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1093 return bacl_exit_error;
1098 * Stream id which doesn't describe the type of acl which is encoded.
1104 * Restore the ACLs, but don't complain about links which really should
1105 * not have attributes, and the file it is linked to may not yet be restored.
1106 * This is only true for the old acl streams as in the new implementation we
1107 * don't save acls of symlinks (which cannot have acls anyhow)
1109 if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1113 return bacl_exit_ok;
1115 Mmsg2(jcr->errmsg, _("acl_set error on file \"%s\": ERR=%s\n"),
1116 jcr->last_fname, acl_strerror(error));
1117 Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",
1118 jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1120 return bacl_exit_error;
1125 return bacl_exit_ok;
1127 return bacl_exit_error;
1128 } /* end switch (stream) */
1131 #else /* HAVE_EXTENDED_ACL */
1134 * Define the supported ACL streams for this OS
1136 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT };
1137 static int os_default_acl_streams[1] = { -1 };
1140 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1141 * There is no need to store those acls as we already store the stat bits too.
1143 static bool acl_is_trivial(int count, aclent_t *entries)
1148 for (n = 0; n < count; n++) {
1151 if (!(ace->a_type == USER_OBJ ||
1152 ace->a_type == GROUP_OBJ ||
1153 ace->a_type == OTHER_OBJ ||
1154 ace->a_type == CLASS_OBJ))
1161 * OS specific functions for handling different types of acl streams.
1163 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1170 n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1171 if (n < MIN_ACL_ENTRIES)
1172 return bacl_exit_error;
1174 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1175 if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1176 if (acl_is_trivial(n, acls)) {
1178 * The ACLs simply reflect the (already known) standard permissions
1179 * So we don't send an ACL stream to the SD.
1182 pm_strcpy(jcr->acl_data->content, "");
1183 jcr->acl_data->content_length = 0;
1184 return bacl_exit_ok;
1187 if ((acl_text = acltotext(acls, n)) != NULL) {
1188 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1189 actuallyfree(acl_text);
1191 return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1194 Mmsg2(jcr->errmsg, _("acltotext error on file \"%s\": ERR=%s\n"),
1195 jcr->last_fname, be.bstrerror());
1196 Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",
1197 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1201 return bacl_exit_error;
1204 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
1210 acls = aclfromtext(jcr->acl_data->content, &n);
1212 Mmsg2(jcr->errmsg, _("aclfromtext error on file \"%s\": ERR=%s\n"),
1213 jcr->last_fname, be.bstrerror());
1214 Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",
1215 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1216 return bacl_exit_error;
1220 * Restore the ACLs, but don't complain about links which really should
1221 * not have attributes, and the file it is linked to may not yet be restored.
1223 if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
1227 return bacl_exit_ok;
1229 Mmsg2(jcr->errmsg, _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
1230 jcr->last_fname, be.bstrerror());
1231 Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
1232 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1234 return bacl_exit_error;
1238 return bacl_exit_ok;
1240 #endif /* HAVE_EXTENDED_ACL */
1243 * For this OS setup the build and parse function pointer to the OS specific functions.
1245 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_acl_streams;
1246 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = solaris_parse_acl_streams;
1248 #endif /* HAVE_SUN_OS */
1249 #endif /* HAVE_ACL */
1251 #if defined(HAVE_AFS_ACL)
1253 #include <afs/stds.h>
1254 #include <afs/afs.h>
1255 #include <afs/auth.h>
1256 #include <afs/venus.h>
1257 #include <afs/prs_fs.h>
1260 * External references to functions in the libsys library function not in current include files.
1263 long pioctl(char *pathp, long opcode, struct ViceIoctl *blobp, int follow);
1266 static bacl_exit_code afs_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1269 struct ViceIoctl vip;
1270 char acl_text[BUFSIZ];
1274 * AFS ACLs can only be set on a directory, so no need to try to
1275 * request them for anything other then that.
1277 if (ff_pkt->type != FT_DIREND) {
1278 return bacl_exit_ok;
1284 vip.out_size = sizeof(acl_text);
1285 memset((caddr_t)acl_text, 0, sizeof(acl_text));
1287 if ((error = pioctl(jcr->last_fname, VIOCGETAL, &vip, 0)) < 0) {
1288 Mmsg2(jcr->errmsg, _("pioctl VIOCGETAL error on file \"%s\": ERR=%s\n"),
1289 jcr->last_fname, be.bstrerror());
1290 Dmsg2(100, "pioctl VIOCGETAL error file=%s ERR=%s\n",
1291 jcr->last_fname, be.bstrerror());
1292 return bacl_exit_error;
1294 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1295 return send_acl_stream(jcr, STREAM_ACL_AFS_TEXT);
1298 static bacl_exit_code afs_parse_acl_stream(JCR *jcr, int stream)
1301 struct ViceIoctl vip;
1304 vip.in = jcr->acl_data->content;
1305 vip.in_size = jcr->acl_data->content_length;
1309 if ((error = pioctl(jcr->last_fname, VIOCSETAL, &vip, 0)) < 0) {
1310 Mmsg2(jcr->errmsg, _("pioctl VIOCSETAL error on file \"%s\": ERR=%s\n"),
1311 jcr->last_fname, be.bstrerror());
1312 Dmsg2(100, "pioctl VIOCSETAL error file=%s ERR=%s\n",
1313 jcr->last_fname, be.bstrerror());
1315 return bacl_exit_error;
1317 return bacl_exit_ok;
1319 #endif /* HAVE_AFS_ACL */
1322 * Entry points when compiled with support for ACLs on a supported platform.
1326 * Read and send an ACL for the last encountered file.
1328 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1331 * See if we are changing from one device to an other.
1332 * We save the current device we are scanning and compare
1333 * it with the current st_dev in the last stat performed on
1334 * the file we are currently storing.
1336 if (jcr->acl_data->current_dev != ff_pkt->statp.st_dev) {
1338 * Reset the acl save flags.
1340 jcr->acl_data->flags = 0;
1342 #if defined(HAVE_AFS_ACL)
1344 * AFS is a non OS specific filesystem so see if this path is on an AFS filesystem
1345 * Set the BACL_FLAG_SAVE_AFS flag if it is. If not set the BACL_FLAG_SAVE_NATIVE flag.
1347 if (fstype_equals(jcr->last_fname, "afs")) {
1348 jcr->acl_data->flags |= BACL_FLAG_SAVE_AFS;
1350 jcr->acl_data->flags |= BACL_FLAG_SAVE_NATIVE;
1353 jcr->acl_data->flags |= BACL_FLAG_SAVE_NATIVE;
1357 * Save that we started scanning a new filesystem.
1359 jcr->acl_data->current_dev = ff_pkt->statp.st_dev;
1362 #if defined(HAVE_AFS_ACL)
1364 * See if the BACL_FLAG_SAVE_AFS flag is set which lets us know if we should
1367 if (jcr->acl_data->flags & BACL_FLAG_SAVE_AFS) {
1368 return afs_build_acl_streams(jcr, ff_pkt);
1371 #if defined(HAVE_ACL)
1373 * See if the BACL_FLAG_SAVE_NATIVE flag is set which lets us know if we should
1376 if (jcr->acl_data->flags & BACL_FLAG_SAVE_NATIVE) {
1378 * Call the appropriate function.
1380 if (os_build_acl_streams) {
1381 return (*os_build_acl_streams)(jcr, ff_pkt);
1384 return bacl_exit_ok;
1387 return bacl_exit_error;
1390 bacl_exit_code parse_acl_streams(JCR *jcr, int stream)
1395 #if defined(HAVE_AFS_ACL)
1396 case STREAM_ACL_AFS_TEXT:
1397 return afs_parse_acl_stream(jcr, stream);
1399 #if defined(HAVE_ACL)
1400 case STREAM_UNIX_ACCESS_ACL:
1401 case STREAM_UNIX_DEFAULT_ACL:
1403 * Handle legacy ACL streams.
1405 if (os_parse_acl_streams) {
1406 return (*os_parse_acl_streams)(jcr, stream);
1410 if (os_parse_acl_streams) {
1412 * Walk the os_access_acl_streams array with the supported Access ACL streams for this OS.
1414 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1415 if (os_access_acl_streams[cnt] == stream) {
1416 return (*os_parse_acl_streams)(jcr, stream);
1420 * Walk the os_default_acl_streams array with the supported Default ACL streams for this OS.
1422 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1423 if (os_default_acl_streams[cnt] == stream) {
1424 return (*os_parse_acl_streams)(jcr, stream);
1434 Qmsg2(jcr, M_WARNING, 0,
1435 _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
1436 jcr->last_fname, stream);
1437 return bacl_exit_error;