2 Bacula® - The Network Backup Solution
4 Copyright (C) 2004-2009 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)
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);
123 #if defined(HAVE_AIX_OS)
125 #include <sys/access.h>
128 * Define the supported ACL streams for this OS
130 static int os_access_acl_streams[1] = { STREAM_ACL_AIX_TEXT };
131 static int os_default_acl_streams[1] = { -1 };
133 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
137 if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
138 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
139 actuallyfree(acl_text);
140 return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT);
142 return bacl_exit_error;
145 static bacl_exit_code aix_parse_acl_streams(JCR *jcr, int stream)
147 if (acl_put(jcr->last_fname, jcr->acl_data->content, 0) != 0) {
148 return bacl_exit_error;
154 * For this OS setup the build and parse function pointer to the OS specific functions.
156 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = aix_build_acl_streams;
157 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = aix_parse_acl_streams;
159 #elif defined(HAVE_DARWIN_OS) || \
160 defined(HAVE_FREEBSD_OS) || \
161 defined(HAVE_IRIX_OS) || \
162 defined(HAVE_OSF1_OS) || \
163 defined(HAVE_LINUX_OS)
165 #include <sys/types.h>
167 #ifdef HAVE_SYS_ACL_H
170 #error "configure failed to detect availability of sys/acl.h"
173 /* On IRIX we can get shortened ACLs */
174 #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
175 #define acl_to_text(acl,len) acl_to_short_text((acl), (len))
178 /* In Linux we can get numeric and/or shorted ACLs */
179 #if defined(HAVE_LINUX_OS)
180 #if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
181 #define BACL_ALTERNATE_TEXT (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
182 #elif defined(BACL_WANT_SHORT_ACLS)
183 #define BACL_ALTERNATE_TEXT TEXT_ABBREVIATE
184 #elif defined(BACL_WANT_NUMERIC_IDS)
185 #define BACL_ALTERNATE_TEXT TEXT_NUMERIC_IDS
187 #ifdef BACL_ALTERNATE_TEXT
188 #include <acl/libacl.h>
189 #define acl_to_text(acl,len) (acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
194 * Some generic functions used by multiple OSes.
196 static acl_type_t bac_to_os_acltype(bacl_type acltype)
201 case BACL_TYPE_ACCESS:
202 ostype = ACL_TYPE_ACCESS;
204 case BACL_TYPE_DEFAULT:
205 ostype = ACL_TYPE_DEFAULT;
208 #ifdef ACL_TYPE_DEFAULT_DIR
209 case BACL_TYPE_DEFAULT_DIR:
211 * OSF1 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
213 ostype = ACL_TYPE_DEFAULT_DIR;
216 #ifdef ACL_TYPE_EXTENDED
217 case BACL_TYPE_EXTENDED:
219 * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
221 ostype = ACL_TYPE_EXTENDED;
226 * This should never happen, as the per OS version function only tries acl
227 * types supported on a certain platform.
229 ostype = (acl_type_t)ACL_TYPE_NONE;
235 #if !defined(HAVE_DARWIN_OS)
237 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
238 * There is no need to store those acls as we already store the stat bits too.
240 static bool acl_is_trivial(acl_t acl)
243 * acl is trivial if it has only the following entries:
250 #if defined(HAVE_FREEBSD_OS) || \
251 defined(HAVE_LINUX_OS)
254 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
255 while (entry_available == 1) {
257 * Get the tag type of this acl entry.
258 * If we fail to get the tagtype we call the acl non-trivial.
260 if (acl_get_tag_type(ace, &tag) < 0)
263 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
265 if (tag != ACL_USER_OBJ &&
266 tag != ACL_GROUP_OBJ &&
269 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
272 #elif defined(HAVE_IRIX_OS)
275 for (n = 0; n < acl->acl_cnt; n++) {
276 ace = &acl->acl_entry[n];
280 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
282 if (tag != ACL_USER_OBJ &&
283 tag != ACL_GROUP_OBJ &&
284 tag != ACL_OTHER_OBJ)
288 #elif defined(HAVE_OSF1_OS)
291 ace = acl->acl_first;
292 count = acl->acl_num;
295 tag = ace->entry->acl_type;
297 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
299 if (tag != ACL_USER_OBJ &&
300 tag != ACL_GROUP_OBJ &&
304 * On Tru64, perm can also contain non-standard bits such as
305 * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
307 if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
318 * Generic wrapper around acl_get_file call.
320 static bacl_exit_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
327 ostype = bac_to_os_acltype(acltype);
328 acl = acl_get_file(jcr->last_fname, ostype);
330 #if defined(HAVE_IRIX_OS)
332 * From observation, IRIX's acl_get_file() seems to return a
333 * non-NULL acl with a count field of -1 when a file has no ACL
334 * defined, while IRIX's acl_to_text() returns NULL when presented
337 * Checking the count in the acl structure before calling
338 * acl_to_text() lets us avoid error messages about files
339 * with no ACLs, without modifying the flow of the code used for
340 * other operating systems, and it saves making some calls
341 * to acl_to_text() besides.
343 if (acl->acl_cnt <= 0) {
344 pm_strcpy(jcr->acl_data->content, "");
345 jcr->acl_data->content_length = 0;
351 #if !defined(HAVE_DARWIN_OS)
353 * Make sure this is not just a trivial ACL.
355 if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
357 * The ACLs simply reflect the (already known) standard permissions
358 * So we don't send an ACL stream to the SD.
360 pm_strcpy(jcr->acl_data->content, "");
361 jcr->acl_data->content_length = 0;
367 if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
368 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
374 Mmsg2(jcr->errmsg, _("acl_to_text error on file \"%s\": ERR=%s\n"),
375 jcr->last_fname, be.bstrerror());
376 Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",
377 jcr->last_fname, be.bstrerror());
379 pm_strcpy(jcr->acl_data->content, "");
380 jcr->acl_data->content_length = 0;
382 return bacl_exit_error;
386 * Handle errors gracefully.
388 if (acl == (acl_t)NULL) {
390 #if defined(BACL_ENOTSUP)
392 break; /* not supported */
395 pm_strcpy(jcr->acl_data->content, "");
396 jcr->acl_data->content_length = 0;
399 /* Some real error */
400 Mmsg2(jcr->errmsg, _("acl_get_file error on file \"%s\": ERR=%s\n"),
401 jcr->last_fname, be.bstrerror());
402 Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",
403 jcr->last_fname, be.bstrerror());
405 pm_strcpy(jcr->acl_data->content, "");
406 jcr->acl_data->content_length = 0;
407 return bacl_exit_error;
411 * Not supported, just pretend there is nothing to see
413 pm_strcpy(jcr->acl_data->content, "");
414 jcr->acl_data->content_length = 0;
419 * Generic wrapper around acl_set_file call.
421 static bacl_exit_code generic_set_acl_on_os(JCR *jcr, bacl_type acltype)
428 * If we get empty default ACLs, clear ACLs now
430 ostype = bac_to_os_acltype(acltype);
431 if (ostype == ACL_TYPE_DEFAULT && strlen(jcr->acl_data->content) == 0) {
432 if (acl_delete_def_file(jcr->last_fname) == 0) {
439 Mmsg2(jcr->errmsg, _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
440 jcr->last_fname, be.bstrerror());
441 return bacl_exit_error;
445 acl = acl_from_text(jcr->acl_data->content);
447 Mmsg2(jcr->errmsg, _("acl_from_text error on file \"%s\": ERR=%s\n"),
448 jcr->last_fname, be.bstrerror());
449 Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",
450 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
451 return bacl_exit_error;
454 #ifndef HAVE_FREEBSD_OS
456 * FreeBSD always fails acl_valid() - at least on valid input...
457 * As it does the right thing, given valid input, just ignore acl_valid().
459 if (acl_valid(acl) != 0) {
460 Mmsg2(jcr->errmsg, _("acl_valid error on file \"%s\": ERR=%s\n"),
461 jcr->last_fname, be.bstrerror());
462 Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",
463 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
465 return bacl_exit_error;
470 * Restore the ACLs, but don't complain about links which really should
471 * not have attributes, and the file it is linked to may not yet be restored.
472 * This is only true for the old acl streams as in the new implementation we
473 * don't save acls of symlinks (which cannot have acls anyhow)
475 if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
481 Mmsg2(jcr->errmsg, _("acl_set_file error on file \"%s\": ERR=%s\n"),
482 jcr->last_fname, be.bstrerror());
483 Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
484 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
486 return bacl_exit_error;
494 * OS specific functions for handling different types of acl streams.
496 #if defined(HAVE_DARWIN_OS)
498 * Define the supported ACL streams for this OS
500 static int os_access_acl_streams[1] = { STREAM_ACL_DARWIN_ACCESS_ACL };
501 static int os_default_acl_streams[1] = { -1 };
503 static bacl_exit_code darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
505 #if defined(ACL_TYPE_EXTENDED)
507 * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
508 * and acl_get_file (name, ACL_TYPE_DEFAULT)
509 * always return NULL / EINVAL. There is no point in making
510 * these two useless calls. The real ACL is retrieved through
511 * acl_get_file (name, ACL_TYPE_EXTENDED).
513 * Read access ACLs for files, dirs and links
515 if (generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED) == bacl_exit_fatal)
516 return bacl_exit_fatal;
519 * Read access ACLs for files, dirs and links
521 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
522 return bacl_exit_fatal;
525 if (jcr->acl_data->content_length > 0) {
526 return send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL);
531 static bacl_exit_code darwin_parse_acl_streams(JCR *jcr, int stream)
533 #if defined(ACL_TYPE_EXTENDED)
534 return generic_set_acl_on_os(jcr, BACL_TYPE_EXTENDED);
536 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
541 * For this OS setup the build and parse function pointer to the OS specific functions.
543 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = darwin_build_acl_streams;
544 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = darwin_parse_acl_streams;
546 #elif defined(HAVE_FREEBSD_OS) || \
547 defined(HAVE_IRIX_OS) || \
548 defined(HAVE_LINUX_OS)
551 * Define the supported ACL streams for these OSes
553 #if defined(HAVE_FREEBSD_OS)
554 static int os_access_acl_streams[1] = { STREAM_ACL_FREEBSD_ACCESS_ACL };
555 static int os_default_acl_streams[1] = { STREAM_ACL_FREEBSD_DEFAULT_ACL };
556 #elif defined(HAVE_IRIX_OS)
557 static int os_access_acl_streams[1] = { STREAM_ACL_IRIX_ACCESS_ACL };
558 static int os_default_acl_streams[1] = { STREAM_ACL_IRIX_DEFAULT_ACL };
559 #elif defined(HAVE_LINUX_OS)
560 static int os_access_acl_streams[1] = { STREAM_ACL_LINUX_ACCESS_ACL };
561 static int os_default_acl_streams[1] = { STREAM_ACL_LINUX_DEFAULT_ACL };
564 static bacl_exit_code generic_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
567 * Read access ACLs for files, dirs and links
569 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
570 return bacl_exit_fatal;
572 if (jcr->acl_data->content_length > 0) {
573 if (send_acl_stream(jcr, os_access_acl_streams[0]) == bacl_exit_fatal)
574 return bacl_exit_fatal;
578 * Directories can have default ACLs too
580 if (ff_pkt->type == FT_DIREND) {
581 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
582 return bacl_exit_fatal;
583 if (jcr->acl_data->content_length > 0) {
584 if (send_acl_stream(jcr, os_default_acl_streams[0]) == bacl_exit_fatal)
585 return bacl_exit_fatal;
591 static bacl_exit_code generic_parse_acl_streams(JCR *jcr, int stream)
596 case STREAM_UNIX_ACCESS_ACL:
597 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
598 case STREAM_UNIX_DEFAULT_ACL:
599 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
602 * See what type of acl it is.
604 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
605 if (os_access_acl_streams[cnt] == stream) {
606 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
609 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
610 if (os_default_acl_streams[cnt] == stream) {
611 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
616 return bacl_exit_error;
620 * For this OSes setup the build and parse function pointer to the OS specific functions.
622 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_build_acl_streams;
623 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = generic_parse_acl_streams;
625 #elif defined(HAVE_OSF1_OS)
628 * Define the supported ACL streams for this OS
630 static int os_access_acl_streams[1] = { STREAM_ACL_TRU64_ACCESS_ACL };
631 static int os_default_acl_streams[2] = { STREAM_ACL_TRU64_DEFAULT_ACL, STREAM_ACL_TRU64_DEFAULT_DIR_ACL };
633 static bacl_exit_code tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
636 * Read access ACLs for files, dirs and links
638 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
639 return bacl_exit_error;
640 if (jcr->acl_data->content_length > 0) {
641 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL))
642 return bacl_exit_error;
645 * Directories can have default ACLs too
647 if (ff_pkt->type == FT_DIREND) {
648 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
649 return bacl_exit_error;
650 if (jcr->acl_data->content_length > 0) {
651 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL))
652 return bacl_exit_error;
655 * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
656 * This is an inherited acl for all subdirs.
657 * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
658 * Section 21.5 Default ACLs
660 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR)) < 0)
661 return bacl_exit_error;
662 if (jcr->acl_data->content_length > 0) {
663 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL))
664 return bacl_exit_error;
670 static bacl_exit_code tru64_parse_acl_streams(JCR *jcr, int stream)
673 case STREAM_UNIX_ACCESS_ACL:
674 case STREAM_ACL_TRU64_ACCESS_ACL:
675 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
676 case STREAM_UNIX_DEFAULT_ACL:
677 case STREAM_ACL_TRU64_DEFAULT_ACL:
678 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
679 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
680 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR);
684 * For this OS setup the build and parse function pointer to the OS specific functions.
686 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = tru64_build_acl_streams;
687 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = tru64_parse_acl_streams;
691 #elif defined(HAVE_HPUX_OS)
692 #ifdef HAVE_SYS_ACL_H
695 #error "configure failed to detect availability of sys/acl.h"
701 * Define the supported ACL streams for this OS
703 static int os_access_acl_streams[1] = { STREAM_ACL_HPUX_ACL_ENTRY };
704 static int os_default_acl_streams[1] = { -1 };
707 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
708 * There is no need to store those acls as we already store the stat bits too.
710 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
715 for (n = 0; n < count; n++) {
718 * See if this acl just is the stat mode in acl form.
720 if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
721 (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
722 (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
729 * OS specific functions for handling different types of acl streams.
731 static bacl_exit_code hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
734 struct acl_entry acls[NACLENTRIES];
738 if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
740 #if defined(BACL_ENOTSUP)
743 * Not supported, just pretend there is nothing to see
745 pm_strcpy(jcr->acl_data->content, "");
746 jcr->acl_data->content_length = 0;
750 pm_strcpy(jcr->acl_data->content, "");
751 jcr->acl_data->content_length = 0;
754 Mmsg2(jcr->errmsg, _("getacl error on file \"%s\": ERR=%s\n"),
755 jcr->last_fname, be.bstrerror());
756 Dmsg2(100, "getacl error file=%s ERR=%s\n",
757 jcr->last_fname, be.bstrerror());
759 pm_strcpy(jcr->acl_data->content, "");
760 jcr->acl_data->content_length = 0;
761 return bacl_exit_error;
765 pm_strcpy(jcr->acl_data->content, "");
766 jcr->acl_data->content_length = 0;
769 if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
770 if (acl_is_trivial(n, acls, ff_pkt->statp)) {
772 * The ACLs simply reflect the (already known) standard permissions
773 * So we don't send an ACL stream to the SD.
775 pm_strcpy(jcr->acl_data->content, "");
776 jcr->acl_data->content_length = 0;
779 if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
780 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
781 actuallyfree(acl_text);
783 return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
785 Mmsg2(jcr->errmsg, _("acltostr error on file \"%s\": ERR=%s\n"),
786 jcr->last_fname, be.bstrerror());
787 Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",
788 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
789 return bacl_exit_error;
791 return bacl_exit_error;
794 static bacl_exit_code hpux_parse_acl_streams(JCR *jcr, int stream)
797 struct acl_entry acls[NACLENTRIES];
800 n = strtoacl(jcr->acl_data->content, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
802 Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
803 jcr->last_fname, be.bstrerror());
804 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
805 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
806 return bacl_exit_error;
808 if (strtoacl(jcr->acl_data->content, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
809 Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
810 jcr->last_fname, be.bstrerror());
811 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
812 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
814 return bacl_exit_error;
817 * Restore the ACLs, but don't complain about links which really should
818 * not have attributes, and the file it is linked to may not yet be restored.
819 * This is only true for the old acl streams as in the new implementation we
820 * don't save acls of symlinks (which cannot have acls anyhow)
822 if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
827 Mmsg2(jcr->errmsg, _("setacl error on file \"%s\": ERR=%s\n"),
828 jcr->last_fname, be.bstrerror());
829 Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
830 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
831 return bacl_exit_error;
838 * For this OS setup the build and parse function pointer to the OS specific functions.
840 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = hpux_build_acl_streams;
841 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = hpux_parse_acl_streams;
843 #elif defined(HAVE_SUN_OS)
844 #ifdef HAVE_SYS_ACL_H
847 #error "configure failed to detect availability of sys/acl.h"
850 #if defined(HAVE_EXTENDED_ACL)
852 * We define some internals of the Solaris acl libs here as those
853 * are not exposed yet. Probably because they want us to see the
854 * acls as opague data. But as we need to support different platforms
855 * and versions of Solaris we need to expose some data to be able
856 * to determine the type of acl used to stuff it into the correct
857 * data stream. I know this is far from portable, but maybe the
858 * proper interface is exposed later on and we can get ride of
859 * this kludge. Newer versions of Solaris include sys/acl_impl.h
860 * which has implementation details of acls, if thats included we
861 * don't have to define it ourself.
863 #if !defined(_SYS_ACL_IMPL_H)
864 typedef enum acl_type {
871 * Two external references to functions in the libsec library function not in current include files.
874 int acl_type(acl_t *);
875 char *acl_strerror(int);
879 * Define the supported ACL streams for this OS
881 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT, STREAM_ACL_SOLARIS_ACE };
882 static int os_default_acl_streams[1] = { -1 };
885 * As the new libsec interface with acl_totext and acl_fromtext also handles
886 * the old format from acltotext we can use the new functions even
887 * for acls retrieved and stored in the database with older fd versions. If the
888 * new interface is not defined (Solaris 9 and older we fall back to the old code)
890 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
892 int acl_enabled, flags;
895 bacl_exit_code stream_status = bacl_exit_error;
899 * See if filesystem supports acls.
901 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
902 switch (acl_enabled) {
904 pm_strcpy(jcr->acl_data->content, "");
905 jcr->acl_data->content_length = 0;
912 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
913 jcr->last_fname, be.bstrerror());
914 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
915 jcr->last_fname, be.bstrerror());
916 return bacl_exit_error;
923 * Get ACL info: don't bother allocating space if there is only a trivial ACL.
925 if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
930 Mmsg2(jcr->errmsg, _("acl_get error on file \"%s\": ERR=%s\n"),
931 jcr->last_fname, acl_strerror(errno));
932 Dmsg2(100, "acl_get error file=%s ERR=%s\n",
933 jcr->last_fname, acl_strerror(errno));
934 return bacl_exit_error;
940 * The ACLs simply reflect the (already known) standard permissions
941 * So we don't send an ACL stream to the SD.
943 pm_strcpy(jcr->acl_data->content, "");
944 jcr->acl_data->content_length = 0;
948 #if defined(ACL_SID_FMT)
950 * New format flag added in newer Solaris versions.
952 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
954 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
955 #endif /* ACL_SID_FMT */
957 if ((acl_text = acl_totext(aclp, flags)) != NULL) {
958 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
959 actuallyfree(acl_text);
961 switch (acl_type(aclp)) {
963 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
966 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE);
974 return stream_status;
977 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
980 int acl_enabled, error;
984 case STREAM_UNIX_ACCESS_ACL:
985 case STREAM_ACL_SOLARIS_ACLENT:
986 case STREAM_ACL_SOLARIS_ACE:
988 * First make sure the filesystem supports acls.
990 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
991 switch (acl_enabled) {
993 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
995 return bacl_exit_error;
1001 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1002 jcr->last_fname, be.bstrerror());
1003 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1004 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1005 return bacl_exit_error;
1009 * On a filesystem with ACL support make sure this particilar ACL type can be restored.
1012 case STREAM_ACL_SOLARIS_ACLENT:
1014 * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
1016 if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
1017 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without aclent acl support\n"),
1019 return bacl_exit_error;
1022 case STREAM_ACL_SOLARIS_ACE:
1024 * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
1026 if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
1027 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without ace acl support\n"),
1029 return bacl_exit_error;
1034 * Stream id which doesn't describe the type of acl which is encoded.
1041 if ((error = acl_fromtext(jcr->acl_data->content, &aclp)) != 0) {
1042 Mmsg2(jcr->errmsg, _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1043 jcr->last_fname, acl_strerror(error));
1044 Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",
1045 jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1046 return bacl_exit_error;
1050 * Validate that the conversion gave us the correct acl type.
1053 case STREAM_ACL_SOLARIS_ACLENT:
1054 if (acl_type(aclp) != ACLENT_T) {
1055 Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1057 return bacl_exit_error;
1060 case STREAM_ACL_SOLARIS_ACE:
1061 if (acl_type(aclp) != ACE_T) {
1062 Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1064 return bacl_exit_error;
1069 * Stream id which doesn't describe the type of acl which is encoded.
1075 * Restore the ACLs, but don't complain about links which really should
1076 * not have attributes, and the file it is linked to may not yet be restored.
1077 * This is only true for the old acl streams as in the new implementation we
1078 * don't save acls of symlinks (which cannot have acls anyhow)
1080 if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1084 return bacl_exit_ok;
1086 Mmsg2(jcr->errmsg, _("acl_set error on file \"%s\": ERR=%s\n"),
1087 jcr->last_fname, acl_strerror(error));
1088 Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",
1089 jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1091 return bacl_exit_error;
1096 return bacl_exit_ok;
1098 return bacl_exit_error;
1099 } /* end switch (stream) */
1102 #else /* HAVE_EXTENDED_ACL */
1105 * Define the supported ACL streams for this OS
1107 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT };
1108 static int os_default_acl_streams[1] = { -1 };
1111 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1112 * There is no need to store those acls as we already store the stat bits too.
1114 static bool acl_is_trivial(int count, aclent_t *entries)
1119 for (n = 0; n < count; n++) {
1122 if (!(ace->a_type == USER_OBJ ||
1123 ace->a_type == GROUP_OBJ ||
1124 ace->a_type == OTHER_OBJ ||
1125 ace->a_type == CLASS_OBJ))
1132 * OS specific functions for handling different types of acl streams.
1134 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1141 n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1142 if (n < MIN_ACL_ENTRIES)
1143 return bacl_exit_error;
1145 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1146 if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1147 if (acl_is_trivial(n, acls)) {
1149 * The ACLs simply reflect the (already known) standard permissions
1150 * So we don't send an ACL stream to the SD.
1153 pm_strcpy(jcr->acl_data->content, "");
1154 jcr->acl_data->content_length = 0;
1155 return bacl_exit_ok;
1158 if ((acl_text = acltotext(acls, n)) != NULL) {
1159 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1160 actuallyfree(acl_text);
1162 return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1165 Mmsg2(jcr->errmsg, _("acltotext error on file \"%s\": ERR=%s\n"),
1166 jcr->last_fname, be.bstrerror());
1167 Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",
1168 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1172 return bacl_exit_error;
1175 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
1181 acls = aclfromtext(jcr->acl_data->content, &n);
1183 Mmsg2(jcr->errmsg, _("aclfromtext error on file \"%s\": ERR=%s\n"),
1184 jcr->last_fname, be.bstrerror());
1185 Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",
1186 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1187 return bacl_exit_error;
1191 * Restore the ACLs, but don't complain about links which really should
1192 * not have attributes, and the file it is linked to may not yet be restored.
1194 if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
1198 return bacl_exit_ok;
1200 Mmsg2(jcr->errmsg, _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
1201 jcr->last_fname, be.bstrerror());
1202 Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
1203 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1205 return bacl_exit_error;
1209 return bacl_exit_ok;
1211 #endif /* HAVE_EXTENDED_ACL */
1214 * For this OS setup the build and parse function pointer to the OS specific functions.
1216 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_acl_streams;
1217 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = solaris_parse_acl_streams;
1219 #endif /* HAVE_SUN_OS */
1222 * Entry points when compiled with support for ACLs on a supported platform.
1226 * Read and send an ACL for the last encountered file.
1228 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1231 * Call the appropriate function.
1233 if (os_build_acl_streams) {
1234 return (*os_build_acl_streams)(jcr, ff_pkt);
1236 return bacl_exit_error;
1239 bacl_exit_code parse_acl_streams(JCR *jcr, int stream)
1244 case STREAM_UNIX_ACCESS_ACL:
1245 case STREAM_UNIX_DEFAULT_ACL:
1247 * Handle legacy ACL streams.
1249 if (os_parse_acl_streams) {
1250 return (*os_parse_acl_streams)(jcr, stream);
1254 if (os_parse_acl_streams) {
1256 * Walk the os_access_acl_streams array with the supported Access ACL streams for this OS.
1258 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1259 if (os_access_acl_streams[cnt] == stream) {
1260 return (*os_parse_acl_streams)(jcr, stream);
1264 * Walk the os_default_acl_streams array with the supported Default ACL streams for this OS.
1266 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1267 if (os_default_acl_streams[cnt] == stream) {
1268 return (*os_parse_acl_streams)(jcr, stream);
1274 Qmsg2(jcr, M_WARNING, 0,
1275 _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
1276 jcr->last_fname, stream);
1277 return bacl_exit_error;