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 * 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 #if defined(HAVE_EXTENDED_ACL)
131 #include <sys/access.h>
135 * Define the supported ACL streams for this OS
137 static int os_access_acl_streams[1] = { STREAM_ACL_AIX_TEXT, STREAM_ACL_AIX_AIXC, STREAM_ACL_AIX_NFS4 };
138 static int os_default_acl_streams[1] = { -1 };
140 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
142 return bacl_exit_error;
145 static bacl_exit_code aix_parse_acl_streams(JCR *jcr, int stream)
148 case STREAM_ACL_AIX_TEXT:
150 * Handle the old stream using the old system call.
152 if (acl_put(jcr->last_fname, jcr->acl_data->content, 0) != 0) {
153 return bacl_exit_error;
156 case STREAM_ACL_AIX_AIXC:
158 case STREAM_ACL_AIX_NFS4:
162 return bacl_exit_error;
165 #else /* HAVE_EXTENDED_ACL */
167 #include <sys/access.h>
170 * Define the supported ACL streams for this OS
172 static int os_access_acl_streams[1] = { STREAM_ACL_AIX_TEXT };
173 static int os_default_acl_streams[1] = { -1 };
175 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
179 if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
180 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
181 actuallyfree(acl_text);
182 return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT);
184 return bacl_exit_error;
187 static bacl_exit_code aix_parse_acl_streams(JCR *jcr, int stream)
189 if (acl_put(jcr->last_fname, jcr->acl_data->content, 0) != 0) {
190 return bacl_exit_error;
194 #endif /* HAVE_EXTENDED_ACL */
197 * For this OS setup the build and parse function pointer to the OS specific functions.
199 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = aix_build_acl_streams;
200 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = aix_parse_acl_streams;
202 #elif defined(HAVE_DARWIN_OS) || \
203 defined(HAVE_FREEBSD_OS) || \
204 defined(HAVE_IRIX_OS) || \
205 defined(HAVE_OSF1_OS) || \
206 defined(HAVE_LINUX_OS)
208 #include <sys/types.h>
210 #ifdef HAVE_SYS_ACL_H
213 #error "configure failed to detect availability of sys/acl.h"
217 * On IRIX we can get shortened ACLs
219 #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
220 #define acl_to_text(acl,len) acl_to_short_text((acl), (len))
224 * In Linux we can get numeric and/or shorted ACLs
226 #if defined(HAVE_LINUX_OS)
227 #if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
228 #define BACL_ALTERNATE_TEXT (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
229 #elif defined(BACL_WANT_SHORT_ACLS)
230 #define BACL_ALTERNATE_TEXT TEXT_ABBREVIATE
231 #elif defined(BACL_WANT_NUMERIC_IDS)
232 #define BACL_ALTERNATE_TEXT TEXT_NUMERIC_IDS
234 #ifdef BACL_ALTERNATE_TEXT
235 #include <acl/libacl.h>
236 #define acl_to_text(acl,len) (acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
241 * Some generic functions used by multiple OSes.
243 static acl_type_t bac_to_os_acltype(bacl_type acltype)
248 case BACL_TYPE_ACCESS:
249 ostype = ACL_TYPE_ACCESS;
251 case BACL_TYPE_DEFAULT:
252 ostype = ACL_TYPE_DEFAULT;
255 #ifdef ACL_TYPE_DEFAULT_DIR
256 case BACL_TYPE_DEFAULT_DIR:
258 * OSF1 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
260 ostype = ACL_TYPE_DEFAULT_DIR;
263 #ifdef ACL_TYPE_EXTENDED
264 case BACL_TYPE_EXTENDED:
266 * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
268 ostype = ACL_TYPE_EXTENDED;
273 * This should never happen, as the per OS version function only tries acl
274 * types supported on a certain platform.
276 ostype = (acl_type_t)ACL_TYPE_NONE;
282 #if !defined(HAVE_DARWIN_OS)
284 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
285 * There is no need to store those acls as we already store the stat bits too.
287 static bool acl_is_trivial(acl_t acl)
290 * acl is trivial if it has only the following entries:
297 #if defined(HAVE_FREEBSD_OS) || \
298 defined(HAVE_LINUX_OS)
301 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
302 while (entry_available == 1) {
304 * Get the tag type of this acl entry.
305 * If we fail to get the tagtype we call the acl non-trivial.
307 if (acl_get_tag_type(ace, &tag) < 0)
310 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
312 if (tag != ACL_USER_OBJ &&
313 tag != ACL_GROUP_OBJ &&
316 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
319 #elif defined(HAVE_IRIX_OS)
322 for (n = 0; n < acl->acl_cnt; n++) {
323 ace = &acl->acl_entry[n];
327 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
329 if (tag != ACL_USER_OBJ &&
330 tag != ACL_GROUP_OBJ &&
331 tag != ACL_OTHER_OBJ)
335 #elif defined(HAVE_OSF1_OS)
338 ace = acl->acl_first;
339 count = acl->acl_num;
342 tag = ace->entry->acl_type;
344 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
346 if (tag != ACL_USER_OBJ &&
347 tag != ACL_GROUP_OBJ &&
351 * On Tru64, perm can also contain non-standard bits such as
352 * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
354 if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
365 * Generic wrapper around acl_get_file call.
367 static bacl_exit_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
374 ostype = bac_to_os_acltype(acltype);
375 acl = acl_get_file(jcr->last_fname, ostype);
377 #if defined(HAVE_IRIX_OS)
379 * From observation, IRIX's acl_get_file() seems to return a
380 * non-NULL acl with a count field of -1 when a file has no ACL
381 * defined, while IRIX's acl_to_text() returns NULL when presented
384 * Checking the count in the acl structure before calling
385 * acl_to_text() lets us avoid error messages about files
386 * with no ACLs, without modifying the flow of the code used for
387 * other operating systems, and it saves making some calls
388 * to acl_to_text() besides.
390 if (acl->acl_cnt <= 0) {
391 pm_strcpy(jcr->acl_data->content, "");
392 jcr->acl_data->content_length = 0;
398 #if !defined(HAVE_DARWIN_OS)
400 * Make sure this is not just a trivial ACL.
402 if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
404 * The ACLs simply reflect the (already known) standard permissions
405 * So we don't send an ACL stream to the SD.
407 pm_strcpy(jcr->acl_data->content, "");
408 jcr->acl_data->content_length = 0;
414 if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
415 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
421 Mmsg2(jcr->errmsg, _("acl_to_text error on file \"%s\": ERR=%s\n"),
422 jcr->last_fname, be.bstrerror());
423 Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",
424 jcr->last_fname, be.bstrerror());
426 pm_strcpy(jcr->acl_data->content, "");
427 jcr->acl_data->content_length = 0;
429 return bacl_exit_error;
433 * Handle errors gracefully.
435 if (acl == (acl_t)NULL) {
437 #if defined(BACL_ENOTSUP)
440 * If the filesystem reports it doesn't support ACLs we clear the
441 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
442 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
443 * when we change from one filesystem to an other.
445 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
446 break; /* not supported */
449 pm_strcpy(jcr->acl_data->content, "");
450 jcr->acl_data->content_length = 0;
453 /* Some real error */
454 Mmsg2(jcr->errmsg, _("acl_get_file error on file \"%s\": ERR=%s\n"),
455 jcr->last_fname, be.bstrerror());
456 Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",
457 jcr->last_fname, be.bstrerror());
459 pm_strcpy(jcr->acl_data->content, "");
460 jcr->acl_data->content_length = 0;
461 return bacl_exit_error;
466 * Not supported, just pretend there is nothing to see
468 pm_strcpy(jcr->acl_data->content, "");
469 jcr->acl_data->content_length = 0;
474 * Generic wrapper around acl_set_file call.
476 static bacl_exit_code generic_set_acl_on_os(JCR *jcr, bacl_type acltype)
483 * If we get empty default ACLs, clear ACLs now
485 ostype = bac_to_os_acltype(acltype);
486 if (ostype == ACL_TYPE_DEFAULT && strlen(jcr->acl_data->content) == 0) {
487 if (acl_delete_def_file(jcr->last_fname) == 0) {
494 Mmsg2(jcr->errmsg, _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
495 jcr->last_fname, be.bstrerror());
496 return bacl_exit_error;
500 acl = acl_from_text(jcr->acl_data->content);
502 Mmsg2(jcr->errmsg, _("acl_from_text error on file \"%s\": ERR=%s\n"),
503 jcr->last_fname, be.bstrerror());
504 Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",
505 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
506 return bacl_exit_error;
509 #ifndef HAVE_FREEBSD_OS
511 * FreeBSD always fails acl_valid() - at least on valid input...
512 * As it does the right thing, given valid input, just ignore acl_valid().
514 if (acl_valid(acl) != 0) {
515 Mmsg2(jcr->errmsg, _("acl_valid error on file \"%s\": ERR=%s\n"),
516 jcr->last_fname, be.bstrerror());
517 Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",
518 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
520 return bacl_exit_error;
525 * Restore the ACLs, but don't complain about links which really should
526 * not have attributes, and the file it is linked to may not yet be restored.
527 * This is only true for the old acl streams as in the new implementation we
528 * don't save acls of symlinks (which cannot have acls anyhow)
530 if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
536 Mmsg2(jcr->errmsg, _("acl_set_file error on file \"%s\": ERR=%s\n"),
537 jcr->last_fname, be.bstrerror());
538 Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
539 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
541 return bacl_exit_error;
549 * OS specific functions for handling different types of acl streams.
551 #if defined(HAVE_DARWIN_OS)
553 * Define the supported ACL streams for this OS
555 static int os_access_acl_streams[1] = { STREAM_ACL_DARWIN_ACCESS_ACL };
556 static int os_default_acl_streams[1] = { -1 };
558 static bacl_exit_code darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
560 #if defined(ACL_TYPE_EXTENDED)
562 * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
563 * and acl_get_file (name, ACL_TYPE_DEFAULT)
564 * always return NULL / EINVAL. There is no point in making
565 * these two useless calls. The real ACL is retrieved through
566 * acl_get_file (name, ACL_TYPE_EXTENDED).
568 * Read access ACLs for files, dirs and links
570 if (generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED) == bacl_exit_fatal)
571 return bacl_exit_fatal;
574 * Read access ACLs for files, dirs and links
576 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
577 return bacl_exit_fatal;
580 if (jcr->acl_data->content_length > 0) {
581 return send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL);
586 static bacl_exit_code darwin_parse_acl_streams(JCR *jcr, int stream)
588 #if defined(ACL_TYPE_EXTENDED)
589 return generic_set_acl_on_os(jcr, BACL_TYPE_EXTENDED);
591 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
596 * For this OS setup the build and parse function pointer to the OS specific functions.
598 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = darwin_build_acl_streams;
599 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = darwin_parse_acl_streams;
601 #elif defined(HAVE_FREEBSD_OS) || \
602 defined(HAVE_IRIX_OS) || \
603 defined(HAVE_LINUX_OS)
606 * Define the supported ACL streams for these OSes
608 #if defined(HAVE_FREEBSD_OS)
609 static int os_access_acl_streams[1] = { STREAM_ACL_FREEBSD_ACCESS_ACL };
610 static int os_default_acl_streams[1] = { STREAM_ACL_FREEBSD_DEFAULT_ACL };
611 #elif defined(HAVE_IRIX_OS)
612 static int os_access_acl_streams[1] = { STREAM_ACL_IRIX_ACCESS_ACL };
613 static int os_default_acl_streams[1] = { STREAM_ACL_IRIX_DEFAULT_ACL };
614 #elif defined(HAVE_LINUX_OS)
615 static int os_access_acl_streams[1] = { STREAM_ACL_LINUX_ACCESS_ACL };
616 static int os_default_acl_streams[1] = { STREAM_ACL_LINUX_DEFAULT_ACL };
619 static bacl_exit_code generic_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
622 * Read access ACLs for files, dirs and links
624 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
625 return bacl_exit_fatal;
627 if (jcr->acl_data->content_length > 0) {
628 if (send_acl_stream(jcr, os_access_acl_streams[0]) == bacl_exit_fatal)
629 return bacl_exit_fatal;
633 * Directories can have default ACLs too
635 if (ff_pkt->type == FT_DIREND) {
636 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
637 return bacl_exit_fatal;
638 if (jcr->acl_data->content_length > 0) {
639 if (send_acl_stream(jcr, os_default_acl_streams[0]) == bacl_exit_fatal)
640 return bacl_exit_fatal;
646 static bacl_exit_code generic_parse_acl_streams(JCR *jcr, int stream)
651 case STREAM_UNIX_ACCESS_ACL:
652 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
653 case STREAM_UNIX_DEFAULT_ACL:
654 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
657 * See what type of acl it is.
659 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
660 if (os_access_acl_streams[cnt] == stream) {
661 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
664 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
665 if (os_default_acl_streams[cnt] == stream) {
666 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
671 return bacl_exit_error;
675 * For this OSes setup the build and parse function pointer to the OS specific functions.
677 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_build_acl_streams;
678 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = generic_parse_acl_streams;
680 #elif defined(HAVE_OSF1_OS)
683 * Define the supported ACL streams for this OS
685 static int os_access_acl_streams[1] = { STREAM_ACL_TRU64_ACCESS_ACL };
686 static int os_default_acl_streams[2] = { STREAM_ACL_TRU64_DEFAULT_ACL, STREAM_ACL_TRU64_DEFAULT_DIR_ACL };
688 static bacl_exit_code tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
691 * Read access ACLs for files, dirs and links
693 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
694 return bacl_exit_error;
695 if (jcr->acl_data->content_length > 0) {
696 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL))
697 return bacl_exit_error;
700 * Directories can have default ACLs too
702 if (ff_pkt->type == FT_DIREND) {
703 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
704 return bacl_exit_error;
705 if (jcr->acl_data->content_length > 0) {
706 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL))
707 return bacl_exit_error;
710 * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
711 * This is an inherited acl for all subdirs.
712 * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
713 * Section 21.5 Default ACLs
715 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR)) < 0)
716 return bacl_exit_error;
717 if (jcr->acl_data->content_length > 0) {
718 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL))
719 return bacl_exit_error;
725 static bacl_exit_code tru64_parse_acl_streams(JCR *jcr, int stream)
728 case STREAM_UNIX_ACCESS_ACL:
729 case STREAM_ACL_TRU64_ACCESS_ACL:
730 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
731 case STREAM_UNIX_DEFAULT_ACL:
732 case STREAM_ACL_TRU64_DEFAULT_ACL:
733 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
734 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
735 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR);
739 * For this OS setup the build and parse function pointer to the OS specific functions.
741 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = tru64_build_acl_streams;
742 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = tru64_parse_acl_streams;
746 #elif defined(HAVE_HPUX_OS)
747 #ifdef HAVE_SYS_ACL_H
750 #error "configure failed to detect availability of sys/acl.h"
756 * Define the supported ACL streams for this OS
758 static int os_access_acl_streams[1] = { STREAM_ACL_HPUX_ACL_ENTRY };
759 static int os_default_acl_streams[1] = { -1 };
762 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
763 * There is no need to store those acls as we already store the stat bits too.
765 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
770 for (n = 0; n < count; n++) {
773 * See if this acl just is the stat mode in acl form.
775 if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
776 (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
777 (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
784 * OS specific functions for handling different types of acl streams.
786 static bacl_exit_code hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
789 struct acl_entry acls[NACLENTRIES];
793 if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
795 #if defined(BACL_ENOTSUP)
798 * Not supported, just pretend there is nothing to see
800 * If the filesystem reports it doesn't support ACLs we clear the
801 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
802 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
803 * when we change from one filesystem to an other.
805 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
806 pm_strcpy(jcr->acl_data->content, "");
807 jcr->acl_data->content_length = 0;
811 pm_strcpy(jcr->acl_data->content, "");
812 jcr->acl_data->content_length = 0;
815 Mmsg2(jcr->errmsg, _("getacl error on file \"%s\": ERR=%s\n"),
816 jcr->last_fname, be.bstrerror());
817 Dmsg2(100, "getacl error file=%s ERR=%s\n",
818 jcr->last_fname, be.bstrerror());
820 pm_strcpy(jcr->acl_data->content, "");
821 jcr->acl_data->content_length = 0;
822 return bacl_exit_error;
826 pm_strcpy(jcr->acl_data->content, "");
827 jcr->acl_data->content_length = 0;
830 if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
831 if (acl_is_trivial(n, acls, ff_pkt->statp)) {
833 * The ACLs simply reflect the (already known) standard permissions
834 * So we don't send an ACL stream to the SD.
836 pm_strcpy(jcr->acl_data->content, "");
837 jcr->acl_data->content_length = 0;
840 if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
841 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
842 actuallyfree(acl_text);
844 return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
846 Mmsg2(jcr->errmsg, _("acltostr error on file \"%s\": ERR=%s\n"),
847 jcr->last_fname, be.bstrerror());
848 Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",
849 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
850 return bacl_exit_error;
852 return bacl_exit_error;
855 static bacl_exit_code hpux_parse_acl_streams(JCR *jcr, int stream)
858 struct acl_entry acls[NACLENTRIES];
861 n = strtoacl(jcr->acl_data->content, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
863 Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
864 jcr->last_fname, be.bstrerror());
865 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
866 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
867 return bacl_exit_error;
869 if (strtoacl(jcr->acl_data->content, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
870 Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
871 jcr->last_fname, be.bstrerror());
872 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
873 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
875 return bacl_exit_error;
878 * Restore the ACLs, but don't complain about links which really should
879 * not have attributes, and the file it is linked to may not yet be restored.
880 * This is only true for the old acl streams as in the new implementation we
881 * don't save acls of symlinks (which cannot have acls anyhow)
883 if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
888 Mmsg2(jcr->errmsg, _("setacl error on file \"%s\": ERR=%s\n"),
889 jcr->last_fname, be.bstrerror());
890 Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
891 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
892 return bacl_exit_error;
899 * For this OS setup the build and parse function pointer to the OS specific functions.
901 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = hpux_build_acl_streams;
902 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = hpux_parse_acl_streams;
904 #elif defined(HAVE_SUN_OS)
905 #ifdef HAVE_SYS_ACL_H
908 #error "configure failed to detect availability of sys/acl.h"
911 #if defined(HAVE_EXTENDED_ACL)
913 * We define some internals of the Solaris acl libs here as those
914 * are not exposed yet. Probably because they want us to see the
915 * acls as opague data. But as we need to support different platforms
916 * and versions of Solaris we need to expose some data to be able
917 * to determine the type of acl used to stuff it into the correct
918 * data stream. I know this is far from portable, but maybe the
919 * proper interface is exposed later on and we can get ride of
920 * this kludge. Newer versions of Solaris include sys/acl_impl.h
921 * which has implementation details of acls, if thats included we
922 * don't have to define it ourself.
924 #if !defined(_SYS_ACL_IMPL_H)
925 typedef enum acl_type {
932 * Two external references to functions in the libsec library function not in current include files.
935 int acl_type(acl_t *);
936 char *acl_strerror(int);
940 * Define the supported ACL streams for this OS
942 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT, STREAM_ACL_SOLARIS_ACE };
943 static int os_default_acl_streams[1] = { -1 };
946 * As the new libsec interface with acl_totext and acl_fromtext also handles
947 * the old format from acltotext we can use the new functions even
948 * for acls retrieved and stored in the database with older fd versions. If the
949 * new interface is not defined (Solaris 9 and older we fall back to the old code)
951 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
953 int acl_enabled, flags;
956 bacl_exit_code stream_status = bacl_exit_error;
960 * See if filesystem supports acls.
962 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
963 switch (acl_enabled) {
966 * If the filesystem reports it doesn't support ACLs we clear the
967 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
968 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
969 * when we change from one filesystem to an other.
971 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
972 pm_strcpy(jcr->acl_data->content, "");
973 jcr->acl_data->content_length = 0;
980 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
981 jcr->last_fname, be.bstrerror());
982 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
983 jcr->last_fname, be.bstrerror());
984 return bacl_exit_error;
991 * Get ACL info: don't bother allocating space if there is only a trivial ACL.
993 if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
998 Mmsg2(jcr->errmsg, _("acl_get error on file \"%s\": ERR=%s\n"),
999 jcr->last_fname, acl_strerror(errno));
1000 Dmsg2(100, "acl_get error file=%s ERR=%s\n",
1001 jcr->last_fname, acl_strerror(errno));
1002 return bacl_exit_error;
1008 * The ACLs simply reflect the (already known) standard permissions
1009 * So we don't send an ACL stream to the SD.
1011 pm_strcpy(jcr->acl_data->content, "");
1012 jcr->acl_data->content_length = 0;
1013 return bacl_exit_ok;
1016 #if defined(ACL_SID_FMT)
1018 * New format flag added in newer Solaris versions.
1020 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
1022 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
1023 #endif /* ACL_SID_FMT */
1025 if ((acl_text = acl_totext(aclp, flags)) != NULL) {
1026 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1027 actuallyfree(acl_text);
1029 switch (acl_type(aclp)) {
1031 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1034 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE);
1042 return stream_status;
1045 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
1048 int acl_enabled, error;
1052 case STREAM_UNIX_ACCESS_ACL:
1053 case STREAM_ACL_SOLARIS_ACLENT:
1054 case STREAM_ACL_SOLARIS_ACE:
1056 * First make sure the filesystem supports acls.
1058 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1059 switch (acl_enabled) {
1061 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
1063 return bacl_exit_error;
1067 return bacl_exit_ok;
1069 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1070 jcr->last_fname, be.bstrerror());
1071 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1072 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1073 return bacl_exit_error;
1077 * On a filesystem with ACL support make sure this particilar ACL type can be restored.
1080 case STREAM_ACL_SOLARIS_ACLENT:
1082 * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
1084 if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
1085 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without aclent acl support\n"),
1087 return bacl_exit_error;
1090 case STREAM_ACL_SOLARIS_ACE:
1092 * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
1094 if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
1095 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without ace acl support\n"),
1097 return bacl_exit_error;
1102 * Stream id which doesn't describe the type of acl which is encoded.
1109 if ((error = acl_fromtext(jcr->acl_data->content, &aclp)) != 0) {
1110 Mmsg2(jcr->errmsg, _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1111 jcr->last_fname, acl_strerror(error));
1112 Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",
1113 jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1114 return bacl_exit_error;
1118 * Validate that the conversion gave us the correct acl type.
1121 case STREAM_ACL_SOLARIS_ACLENT:
1122 if (acl_type(aclp) != ACLENT_T) {
1123 Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1125 return bacl_exit_error;
1128 case STREAM_ACL_SOLARIS_ACE:
1129 if (acl_type(aclp) != ACE_T) {
1130 Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1132 return bacl_exit_error;
1137 * Stream id which doesn't describe the type of acl which is encoded.
1143 * Restore the ACLs, but don't complain about links which really should
1144 * not have attributes, and the file it is linked to may not yet be restored.
1145 * This is only true for the old acl streams as in the new implementation we
1146 * don't save acls of symlinks (which cannot have acls anyhow)
1148 if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1152 return bacl_exit_ok;
1154 Mmsg2(jcr->errmsg, _("acl_set error on file \"%s\": ERR=%s\n"),
1155 jcr->last_fname, acl_strerror(error));
1156 Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",
1157 jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1159 return bacl_exit_error;
1164 return bacl_exit_ok;
1166 return bacl_exit_error;
1167 } /* end switch (stream) */
1170 #else /* HAVE_EXTENDED_ACL */
1173 * Define the supported ACL streams for this OS
1175 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT };
1176 static int os_default_acl_streams[1] = { -1 };
1179 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1180 * There is no need to store those acls as we already store the stat bits too.
1182 static bool acl_is_trivial(int count, aclent_t *entries)
1187 for (n = 0; n < count; n++) {
1190 if (!(ace->a_type == USER_OBJ ||
1191 ace->a_type == GROUP_OBJ ||
1192 ace->a_type == OTHER_OBJ ||
1193 ace->a_type == CLASS_OBJ))
1200 * OS specific functions for handling different types of acl streams.
1202 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1209 n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1210 if (n < MIN_ACL_ENTRIES)
1211 return bacl_exit_error;
1213 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1214 if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1215 if (acl_is_trivial(n, acls)) {
1217 * The ACLs simply reflect the (already known) standard permissions
1218 * So we don't send an ACL stream to the SD.
1221 pm_strcpy(jcr->acl_data->content, "");
1222 jcr->acl_data->content_length = 0;
1223 return bacl_exit_ok;
1226 if ((acl_text = acltotext(acls, n)) != NULL) {
1227 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1228 actuallyfree(acl_text);
1230 return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1233 Mmsg2(jcr->errmsg, _("acltotext error on file \"%s\": ERR=%s\n"),
1234 jcr->last_fname, be.bstrerror());
1235 Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",
1236 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1240 return bacl_exit_error;
1243 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
1249 acls = aclfromtext(jcr->acl_data->content, &n);
1251 Mmsg2(jcr->errmsg, _("aclfromtext error on file \"%s\": ERR=%s\n"),
1252 jcr->last_fname, be.bstrerror());
1253 Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",
1254 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1255 return bacl_exit_error;
1259 * Restore the ACLs, but don't complain about links which really should
1260 * not have attributes, and the file it is linked to may not yet be restored.
1262 if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
1266 return bacl_exit_ok;
1268 Mmsg2(jcr->errmsg, _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
1269 jcr->last_fname, be.bstrerror());
1270 Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
1271 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1273 return bacl_exit_error;
1277 return bacl_exit_ok;
1279 #endif /* HAVE_EXTENDED_ACL */
1282 * For this OS setup the build and parse function pointer to the OS specific functions.
1284 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_acl_streams;
1285 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = solaris_parse_acl_streams;
1287 #endif /* HAVE_SUN_OS */
1288 #endif /* HAVE_ACL */
1291 * Entry points when compiled with support for ACLs on a supported platform.
1295 * Read and send an ACL for the last encountered file.
1297 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1300 * See if we are changing from one device to an other.
1301 * We save the current device we are scanning and compare
1302 * it with the current st_dev in the last stat performed on
1303 * the file we are currently storing.
1305 if (jcr->acl_data->current_dev != ff_pkt->statp.st_dev) {
1307 * Reset the acl save flags.
1309 jcr->acl_data->flags = 0;
1311 jcr->acl_data->flags |= BACL_FLAG_SAVE_NATIVE;
1314 * Save that we started scanning a new filesystem.
1316 jcr->acl_data->current_dev = ff_pkt->statp.st_dev;
1319 #if defined(HAVE_ACL)
1321 * See if the BACL_FLAG_SAVE_NATIVE flag is set which lets us know if we should
1324 if (jcr->acl_data->flags & BACL_FLAG_SAVE_NATIVE) {
1326 * Call the appropriate function.
1328 if (os_build_acl_streams) {
1329 return (*os_build_acl_streams)(jcr, ff_pkt);
1332 return bacl_exit_ok;
1335 return bacl_exit_error;
1338 bacl_exit_code parse_acl_streams(JCR *jcr, int stream)
1343 #if defined(HAVE_ACL)
1344 case STREAM_UNIX_ACCESS_ACL:
1345 case STREAM_UNIX_DEFAULT_ACL:
1347 * Handle legacy ACL streams.
1349 if (os_parse_acl_streams) {
1350 return (*os_parse_acl_streams)(jcr, stream);
1354 if (os_parse_acl_streams) {
1356 * Walk the os_access_acl_streams array with the supported Access ACL streams for this OS.
1358 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1359 if (os_access_acl_streams[cnt] == stream) {
1360 return (*os_parse_acl_streams)(jcr, stream);
1364 * Walk the os_default_acl_streams array with the supported Default ACL streams for this OS.
1366 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1367 if (os_default_acl_streams[cnt] == stream) {
1368 return (*os_parse_acl_streams)(jcr, stream);
1378 Qmsg2(jcr, M_WARNING, 0,
1379 _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
1380 jcr->last_fname, stream);
1381 return bacl_exit_error;