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
57 #if !defined(HAVE_ACL)
59 * Entry points when compiled without support for ACLs or on an unsupported platform.
61 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
63 return bacl_exit_fatal;
66 bacl_exit_code parse_acl_stream(JCR *jcr, int stream)
68 return bacl_exit_fatal;
72 * Send an ACL stream to the SD.
74 static bacl_exit_code send_acl_stream(JCR *jcr, int stream)
76 BSOCK *sd = jcr->store_bsock;
78 #ifdef FD_NO_SEND_TEST
85 if (jcr->acl_data->content_length <= 0) {
92 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
93 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
95 return bacl_exit_fatal;
99 * Send the buffer to the storage deamon
101 Dmsg1(400, "Backing up ACL <%s>\n", jcr->acl_data->content);
103 sd->msg = jcr->acl_data->content;
104 sd->msglen = jcr->acl_data->content_length + 1;
108 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
110 return bacl_exit_fatal;
113 jcr->JobBytes += sd->msglen;
115 if (!sd->signal(BNET_EOD)) {
116 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
118 return bacl_exit_fatal;
121 Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
125 #if defined(HAVE_AIX_OS)
127 #include <sys/access.h>
130 * Define the supported ACL streams for this OS
132 static int os_access_acl_streams[1] = { STREAM_ACL_AIX_TEXT };
133 static int os_default_acl_streams[1] = { -1 };
135 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
139 if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
140 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
141 actuallyfree(acl_text);
142 return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT);
144 return bacl_exit_error;
147 static bacl_exit_code aix_parse_acl_streams(JCR *jcr, int stream)
149 if (acl_put(jcr->last_fname, jcr->acl_data->content, 0) != 0) {
150 return bacl_exit_error;
156 * For this OS setup the build and parse function pointer to the OS specific functions.
158 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = aix_build_acl_streams;
159 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = aix_parse_acl_streams;
161 #elif defined(HAVE_DARWIN_OS) || \
162 defined(HAVE_FREEBSD_OS) || \
163 defined(HAVE_IRIX_OS) || \
164 defined(HAVE_OSF1_OS) || \
165 defined(HAVE_LINUX_OS)
167 #include <sys/types.h>
169 #ifdef HAVE_SYS_ACL_H
172 #error "configure failed to detect availability of sys/acl.h"
175 /* On IRIX we can get shortened ACLs */
176 #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
177 #define acl_to_text(acl,len) acl_to_short_text((acl), (len))
180 /* In Linux we can get numeric and/or shorted ACLs */
181 #if defined(HAVE_LINUX_OS)
182 #if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
183 #define BACL_ALTERNATE_TEXT (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
184 #elif defined(BACL_WANT_SHORT_ACLS)
185 #define BACL_ALTERNATE_TEXT TEXT_ABBREVIATE
186 #elif defined(BACL_WANT_NUMERIC_IDS)
187 #define BACL_ALTERNATE_TEXT TEXT_NUMERIC_IDS
189 #ifdef BACL_ALTERNATE_TEXT
190 #include <acl/libacl.h>
191 #define acl_to_text(acl,len) (acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
196 * Some generic functions used by multiple OSes.
198 static acl_type_t bac_to_os_acltype(bacl_type acltype)
203 case BACL_TYPE_ACCESS:
204 ostype = ACL_TYPE_ACCESS;
206 case BACL_TYPE_DEFAULT:
207 ostype = ACL_TYPE_DEFAULT;
210 #ifdef ACL_TYPE_DEFAULT_DIR
211 case BACL_TYPE_DEFAULT_DIR:
213 * OSF1 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
215 ostype = ACL_TYPE_DEFAULT_DIR;
218 #ifdef ACL_TYPE_EXTENDED
219 case BACL_TYPE_EXTENDED:
221 * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
223 ostype = ACL_TYPE_EXTENDED;
228 * This should never happen, as the per OS version function only tries acl
229 * types supported on a certain platform.
231 ostype = (acl_type_t)ACL_TYPE_NONE;
237 #if !defined(HAVE_DARWIN_OS)
239 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
240 * There is no need to store those acls as we already store the stat bits too.
242 static bool acl_is_trivial(acl_t acl)
245 * acl is trivial if it has only the following entries:
252 #if defined(HAVE_FREEBSD_OS) || \
253 defined(HAVE_LINUX_OS)
256 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
257 while (entry_available == 1) {
259 * Get the tag type of this acl entry.
260 * If we fail to get the tagtype we call the acl non-trivial.
262 if (acl_get_tag_type(ace, &tag) < 0)
265 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
267 if (tag != ACL_USER_OBJ &&
268 tag != ACL_GROUP_OBJ &&
271 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
274 #elif defined(HAVE_IRIX_OS)
277 for (n = 0; n < acl->acl_cnt; n++) {
278 ace = &acl->acl_entry[n];
282 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
284 if (tag != ACL_USER_OBJ &&
285 tag != ACL_GROUP_OBJ &&
286 tag != ACL_OTHER_OBJ)
290 #elif defined(HAVE_OSF1_OS)
293 ace = acl->acl_first;
294 count = acl->acl_num;
297 tag = ace->entry->acl_type;
299 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
301 if (tag != ACL_USER_OBJ &&
302 tag != ACL_GROUP_OBJ &&
306 * On Tru64, perm can also contain non-standard bits such as
307 * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
309 if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
320 * Generic wrapper around acl_get_file call.
322 static bacl_exit_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
329 ostype = bac_to_os_acltype(acltype);
330 acl = acl_get_file(jcr->last_fname, ostype);
332 #if defined(HAVE_IRIX_OS)
334 * From observation, IRIX's acl_get_file() seems to return a
335 * non-NULL acl with a count field of -1 when a file has no ACL
336 * defined, while IRIX's acl_to_text() returns NULL when presented
339 * Checking the count in the acl structure before calling
340 * acl_to_text() lets us avoid error messages about files
341 * with no ACLs, without modifying the flow of the code used for
342 * other operating systems, and it saves making some calls
343 * to acl_to_text() besides.
345 if (acl->acl_cnt <= 0) {
346 pm_strcpy(jcr->acl_data->content, "");
347 jcr->acl_data->content_length = 0;
353 #if !defined(HAVE_DARWIN_OS)
355 * Make sure this is not just a trivial ACL.
357 if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
359 * The ACLs simply reflect the (already known) standard permissions
360 * So we don't send an ACL stream to the SD.
362 pm_strcpy(jcr->acl_data->content, "");
363 jcr->acl_data->content_length = 0;
369 if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
370 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
376 Mmsg2(jcr->errmsg, _("acl_to_text error on file \"%s\": ERR=%s\n"),
377 jcr->last_fname, be.bstrerror());
378 Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",
379 jcr->last_fname, be.bstrerror());
381 pm_strcpy(jcr->acl_data->content, "");
382 jcr->acl_data->content_length = 0;
384 return bacl_exit_error;
388 * Handle errors gracefully.
390 if (acl == (acl_t)NULL) {
392 #if defined(BACL_ENOTSUP)
394 break; /* not supported */
397 pm_strcpy(jcr->acl_data->content, "");
398 jcr->acl_data->content_length = 0;
401 /* Some real error */
402 Mmsg2(jcr->errmsg, _("acl_get_file error on file \"%s\": ERR=%s\n"),
403 jcr->last_fname, be.bstrerror());
404 Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",
405 jcr->last_fname, be.bstrerror());
407 pm_strcpy(jcr->acl_data->content, "");
408 jcr->acl_data->content_length = 0;
409 return bacl_exit_error;
413 * Not supported, just pretend there is nothing to see
415 pm_strcpy(jcr->acl_data->content, "");
416 jcr->acl_data->content_length = 0;
421 * Generic wrapper around acl_set_file call.
423 static bacl_exit_code generic_set_acl_on_os(JCR *jcr, bacl_type acltype)
430 * If we get empty default ACLs, clear ACLs now
432 ostype = bac_to_os_acltype(acltype);
433 if (ostype == ACL_TYPE_DEFAULT && strlen(jcr->acl_data->content) == 0) {
434 if (acl_delete_def_file(jcr->last_fname) == 0) {
441 Mmsg2(jcr->errmsg, _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
442 jcr->last_fname, be.bstrerror());
443 return bacl_exit_error;
447 acl = acl_from_text(jcr->acl_data->content);
449 Mmsg2(jcr->errmsg, _("acl_from_text error on file \"%s\": ERR=%s\n"),
450 jcr->last_fname, be.bstrerror());
451 Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",
452 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
453 return bacl_exit_error;
456 #ifndef HAVE_FREEBSD_OS
458 * FreeBSD always fails acl_valid() - at least on valid input...
459 * As it does the right thing, given valid input, just ignore acl_valid().
461 if (acl_valid(acl) != 0) {
462 Mmsg2(jcr->errmsg, _("acl_valid error on file \"%s\": ERR=%s\n"),
463 jcr->last_fname, be.bstrerror());
464 Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",
465 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
467 return bacl_exit_error;
472 * Restore the ACLs, but don't complain about links which really should
473 * not have attributes, and the file it is linked to may not yet be restored.
474 * This is only true for the old acl streams as in the new implementation we
475 * don't save acls of symlinks (which cannot have acls anyhow)
477 if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
483 Mmsg2(jcr->errmsg, _("acl_set_file error on file \"%s\": ERR=%s\n"),
484 jcr->last_fname, be.bstrerror());
485 Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
486 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
488 return bacl_exit_error;
496 * OS specific functions for handling different types of acl streams.
498 #if defined(HAVE_DARWIN_OS)
500 * Define the supported ACL streams for this OS
502 static int os_access_acl_streams[1] = { STREAM_ACL_DARWIN_ACCESS_ACL };
503 static int os_default_acl_streams[1] = { -1 };
505 static bacl_exit_code darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
507 #if defined(ACL_TYPE_EXTENDED)
509 * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
510 * and acl_get_file (name, ACL_TYPE_DEFAULT)
511 * always return NULL / EINVAL. There is no point in making
512 * these two useless calls. The real ACL is retrieved through
513 * acl_get_file (name, ACL_TYPE_EXTENDED).
515 * Read access ACLs for files, dirs and links
517 if (generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED) == bacl_exit_fatal)
518 return bacl_exit_fatal;
521 * Read access ACLs for files, dirs and links
523 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
524 return bacl_exit_fatal;
527 if (jcr->acl_data->content_length > 0) {
528 return send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL);
533 static bacl_exit_code darwin_parse_acl_streams(JCR *jcr, int stream)
535 #if defined(ACL_TYPE_EXTENDED)
536 return generic_set_acl_on_os(jcr, BACL_TYPE_EXTENDED);
538 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
543 * For this OS setup the build and parse function pointer to the OS specific functions.
545 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = darwin_build_acl_streams;
546 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = darwin_parse_acl_streams;
548 #elif defined(HAVE_FREEBSD_OS) || \
549 defined(HAVE_IRIX_OS) || \
550 defined(HAVE_LINUX_OS)
553 * Define the supported ACL streams for these OSes
555 #if defined(HAVE_FREEBSD_OS)
556 static int os_access_acl_streams[1] = { STREAM_ACL_FREEBSD_ACCESS_ACL };
557 static int os_default_acl_streams[1] = { STREAM_ACL_FREEBSD_DEFAULT_ACL };
558 #elif defined(HAVE_IRIX_OS)
559 static int os_access_acl_streams[1] = { STREAM_ACL_IRIX_ACCESS_ACL };
560 static int os_default_acl_streams[1] = { STREAM_ACL_IRIX_DEFAULT_ACL };
561 #elif defined(HAVE_LINUX_OS)
562 static int os_access_acl_streams[1] = { STREAM_ACL_LINUX_ACCESS_ACL };
563 static int os_default_acl_streams[1] = { STREAM_ACL_LINUX_DEFAULT_ACL };
566 static bacl_exit_code generic_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
569 * Read access ACLs for files, dirs and links
571 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
572 return bacl_exit_fatal;
574 if (jcr->acl_data->content_length > 0) {
575 if (send_acl_stream(jcr, os_access_acl_streams[0]) == bacl_exit_fatal)
576 return bacl_exit_fatal;
580 * Directories can have default ACLs too
582 if (ff_pkt->type == FT_DIREND) {
583 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
584 return bacl_exit_fatal;
585 if (jcr->acl_data->content_length > 0) {
586 if (send_acl_stream(jcr, os_default_acl_streams[0]) == bacl_exit_fatal)
587 return bacl_exit_fatal;
593 static bacl_exit_code generic_parse_acl_streams(JCR *jcr, int stream)
598 case STREAM_UNIX_ACCESS_ACL:
599 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
600 case STREAM_UNIX_DEFAULT_ACL:
601 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
604 * See what type of acl it is.
606 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
607 if (os_access_acl_streams[cnt] == stream) {
608 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
611 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
612 if (os_default_acl_streams[cnt] == stream) {
613 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
618 return bacl_exit_error;
622 * For this OSes setup the build and parse function pointer to the OS specific functions.
624 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_build_acl_streams;
625 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = generic_parse_acl_streams;
627 #elif defined(HAVE_OSF1_OS)
630 * Define the supported ACL streams for this OS
632 static int os_access_acl_streams[1] = { STREAM_ACL_TRU64_ACCESS_ACL };
633 static int os_default_acl_streams[2] = { STREAM_ACL_TRU64_DEFAULT_ACL, STREAM_ACL_TRU64_DEFAULT_DIR_ACL };
635 static bacl_exit_code tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
638 * Read access ACLs for files, dirs and links
640 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
641 return bacl_exit_error;
642 if (jcr->acl_data->content_length > 0) {
643 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL))
644 return bacl_exit_error;
647 * Directories can have default ACLs too
649 if (ff_pkt->type == FT_DIREND) {
650 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
651 return bacl_exit_error;
652 if (jcr->acl_data->content_length > 0) {
653 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL))
654 return bacl_exit_error;
657 * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
658 * This is an inherited acl for all subdirs.
659 * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
660 * Section 21.5 Default ACLs
662 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR)) < 0)
663 return bacl_exit_error;
664 if (jcr->acl_data->content_length > 0) {
665 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL))
666 return bacl_exit_error;
672 static bacl_exit_code tru64_parse_acl_streams(JCR *jcr, int stream)
675 case STREAM_UNIX_ACCESS_ACL:
676 case STREAM_ACL_TRU64_ACCESS_ACL:
677 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
678 case STREAM_UNIX_DEFAULT_ACL:
679 case STREAM_ACL_TRU64_DEFAULT_ACL:
680 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
681 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
682 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR);
686 * For this OS setup the build and parse function pointer to the OS specific functions.
688 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = tru64_build_acl_streams;
689 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = tru64_parse_acl_streams;
693 #elif defined(HAVE_HPUX_OS)
694 #ifdef HAVE_SYS_ACL_H
697 #error "configure failed to detect availability of sys/acl.h"
703 * Define the supported ACL streams for this OS
705 static int os_access_acl_streams[1] = { STREAM_ACL_HPUX_ACL_ENTRY };
706 static int os_default_acl_streams[1] = { -1 };
709 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
710 * There is no need to store those acls as we already store the stat bits too.
712 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
717 for (n = 0; n < count; n++) {
720 * See if this acl just is the stat mode in acl form.
722 if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
723 (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
724 (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
731 * OS specific functions for handling different types of acl streams.
733 static bacl_exit_code hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
736 struct acl_entry acls[NACLENTRIES];
740 if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
742 #if defined(BACL_ENOTSUP)
745 * Not supported, just pretend there is nothing to see
747 pm_strcpy(jcr->acl_data->content, "");
748 jcr->acl_data->content_length = 0;
752 pm_strcpy(jcr->acl_data->content, "");
753 jcr->acl_data->content_length = 0;
756 Mmsg2(jcr->errmsg, _("getacl error on file \"%s\": ERR=%s\n"),
757 jcr->last_fname, be.bstrerror());
758 Dmsg2(100, "getacl error file=%s ERR=%s\n",
759 jcr->last_fname, be.bstrerror());
761 pm_strcpy(jcr->acl_data->content, "");
762 jcr->acl_data->content_length = 0;
763 return bacl_exit_error;
767 pm_strcpy(jcr->acl_data->content, "");
768 jcr->acl_data->content_length = 0;
771 if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
772 if (acl_is_trivial(n, acls, ff_pkt->statp)) {
774 * The ACLs simply reflect the (already known) standard permissions
775 * So we don't send an ACL stream to the SD.
777 pm_strcpy(jcr->acl_data->content, "");
778 jcr->acl_data->content_length = 0;
781 if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
782 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
783 actuallyfree(acl_text);
785 return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
787 Mmsg2(jcr->errmsg, _("acltostr error on file \"%s\": ERR=%s\n"),
788 jcr->last_fname, be.bstrerror());
789 Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",
790 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
791 return bacl_exit_error;
793 return bacl_exit_error;
796 static bacl_exit_code hpux_parse_acl_streams(JCR *jcr, int stream)
799 struct acl_entry acls[NACLENTRIES];
802 n = strtoacl(jcr->acl_data->content, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
804 Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
805 jcr->last_fname, be.bstrerror());
806 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
807 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
808 return bacl_exit_error;
810 if (strtoacl(jcr->acl_data->content, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
811 Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
812 jcr->last_fname, be.bstrerror());
813 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
814 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
816 return bacl_exit_error;
819 * Restore the ACLs, but don't complain about links which really should
820 * not have attributes, and the file it is linked to may not yet be restored.
821 * This is only true for the old acl streams as in the new implementation we
822 * don't save acls of symlinks (which cannot have acls anyhow)
824 if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
829 Mmsg2(jcr->errmsg, _("setacl error on file \"%s\": ERR=%s\n"),
830 jcr->last_fname, be.bstrerror());
831 Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
832 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
833 return bacl_exit_error;
840 * For this OS setup the build and parse function pointer to the OS specific functions.
842 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = hpux_build_acl_streams;
843 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = hpux_parse_acl_streams;
845 #elif defined(HAVE_SUN_OS)
846 #ifdef HAVE_SYS_ACL_H
849 #error "configure failed to detect availability of sys/acl.h"
852 #if defined(HAVE_EXTENDED_ACL)
854 * We define some internals of the Solaris acl libs here as those
855 * are not exposed yet. Probably because they want us to see the
856 * acls as opague data. But as we need to support different platforms
857 * and versions of Solaris we need to expose some data to be able
858 * to determine the type of acl used to stuff it into the correct
859 * data stream. I know this is far from portable, but maybe the
860 * proper interface is exposed later on and we can get ride of
861 * this kludge. Newer versions of Solaris include sys/acl_impl.h
862 * which has implementation details of acls, if thats included we
863 * don't have to define it ourself.
865 #if !defined(_SYS_ACL_IMPL_H)
866 typedef enum acl_type {
873 * Two external references to functions in the libsec library function not in current include files.
876 int acl_type(acl_t *);
877 char *acl_strerror(int);
881 * Define the supported ACL streams for this OS
883 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT, STREAM_ACL_SOLARIS_ACE };
884 static int os_default_acl_streams[1] = { -1 };
887 * As the new libsec interface with acl_totext and acl_fromtext also handles
888 * the old format from acltotext we can use the new functions even
889 * for acls retrieved and stored in the database with older fd versions. If the
890 * new interface is not defined (Solaris 9 and older we fall back to the old code)
892 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
894 int acl_enabled, flags;
897 bacl_exit_code stream_status = bacl_exit_error;
901 * See if filesystem supports acls.
903 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
904 switch (acl_enabled) {
906 pm_strcpy(jcr->acl_data->content, "");
907 jcr->acl_data->content_length = 0;
914 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
915 jcr->last_fname, be.bstrerror());
916 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
917 jcr->last_fname, be.bstrerror());
918 return bacl_exit_error;
925 * Get ACL info: don't bother allocating space if there is only a trivial ACL.
927 if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
932 Mmsg2(jcr->errmsg, _("acl_get error on file \"%s\": ERR=%s\n"),
933 jcr->last_fname, acl_strerror(errno));
934 Dmsg2(100, "acl_get error file=%s ERR=%s\n",
935 jcr->last_fname, acl_strerror(errno));
936 return bacl_exit_error;
942 * The ACLs simply reflect the (already known) standard permissions
943 * So we don't send an ACL stream to the SD.
945 pm_strcpy(jcr->acl_data->content, "");
946 jcr->acl_data->content_length = 0;
950 #if defined(ACL_SID_FMT)
952 * New format flag added in newer Solaris versions.
954 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
956 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
957 #endif /* ACL_SID_FMT */
959 if ((acl_text = acl_totext(aclp, flags)) != NULL) {
960 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
961 actuallyfree(acl_text);
963 switch (acl_type(aclp)) {
965 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
968 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE);
976 return stream_status;
979 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
982 int acl_enabled, error;
986 case STREAM_UNIX_ACCESS_ACL:
987 case STREAM_ACL_SOLARIS_ACLENT:
988 case STREAM_ACL_SOLARIS_ACE:
990 * First make sure the filesystem supports acls.
992 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
993 switch (acl_enabled) {
995 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
997 return bacl_exit_error;
1001 return bacl_exit_ok;
1003 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1004 jcr->last_fname, be.bstrerror());
1005 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1006 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1007 return bacl_exit_error;
1011 * On a filesystem with ACL support make sure this particilar ACL type can be restored.
1014 case STREAM_ACL_SOLARIS_ACLENT:
1016 * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
1018 if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
1019 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without aclent acl support\n"),
1021 return bacl_exit_error;
1024 case STREAM_ACL_SOLARIS_ACE:
1026 * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
1028 if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
1029 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without ace acl support\n"),
1031 return bacl_exit_error;
1036 * Stream id which doesn't describe the type of acl which is encoded.
1043 if ((error = acl_fromtext(jcr->acl_data->content, &aclp)) != 0) {
1044 Mmsg2(jcr->errmsg, _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1045 jcr->last_fname, acl_strerror(error));
1046 Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",
1047 jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1048 return bacl_exit_error;
1052 * Validate that the conversion gave us the correct acl type.
1055 case STREAM_ACL_SOLARIS_ACLENT:
1056 if (acl_type(aclp) != ACLENT_T) {
1057 Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1059 return bacl_exit_error;
1062 case STREAM_ACL_SOLARIS_ACE:
1063 if (acl_type(aclp) != ACE_T) {
1064 Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1066 return bacl_exit_error;
1071 * Stream id which doesn't describe the type of acl which is encoded.
1077 * Restore the ACLs, but don't complain about links which really should
1078 * not have attributes, and the file it is linked to may not yet be restored.
1079 * This is only true for the old acl streams as in the new implementation we
1080 * don't save acls of symlinks (which cannot have acls anyhow)
1082 if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1086 return bacl_exit_ok;
1088 Mmsg2(jcr->errmsg, _("acl_set error on file \"%s\": ERR=%s\n"),
1089 jcr->last_fname, acl_strerror(error));
1090 Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",
1091 jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1093 return bacl_exit_error;
1098 return bacl_exit_ok;
1100 return bacl_exit_error;
1101 } /* end switch (stream) */
1104 #else /* HAVE_EXTENDED_ACL */
1107 * Define the supported ACL streams for this OS
1109 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT };
1110 static int os_default_acl_streams[1] = { -1 };
1113 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1114 * There is no need to store those acls as we already store the stat bits too.
1116 static bool acl_is_trivial(int count, aclent_t *entries)
1121 for (n = 0; n < count; n++) {
1124 if (!(ace->a_type == USER_OBJ ||
1125 ace->a_type == GROUP_OBJ ||
1126 ace->a_type == OTHER_OBJ ||
1127 ace->a_type == CLASS_OBJ))
1134 * OS specific functions for handling different types of acl streams.
1136 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1143 n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1144 if (n < MIN_ACL_ENTRIES)
1145 return bacl_exit_error;
1147 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1148 if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1149 if (acl_is_trivial(n, acls)) {
1151 * The ACLs simply reflect the (already known) standard permissions
1152 * So we don't send an ACL stream to the SD.
1155 pm_strcpy(jcr->acl_data->content, "");
1156 jcr->acl_data->content_length = 0;
1157 return bacl_exit_ok;
1160 if ((acl_text = acltotext(acls, n)) != NULL) {
1161 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1162 actuallyfree(acl_text);
1164 return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1167 Mmsg2(jcr->errmsg, _("acltotext error on file \"%s\": ERR=%s\n"),
1168 jcr->last_fname, be.bstrerror());
1169 Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",
1170 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1174 return bacl_exit_error;
1177 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
1183 acls = aclfromtext(jcr->acl_data->content, &n);
1185 Mmsg2(jcr->errmsg, _("aclfromtext error on file \"%s\": ERR=%s\n"),
1186 jcr->last_fname, be.bstrerror());
1187 Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",
1188 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1189 return bacl_exit_error;
1193 * Restore the ACLs, but don't complain about links which really should
1194 * not have attributes, and the file it is linked to may not yet be restored.
1196 if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
1200 return bacl_exit_ok;
1202 Mmsg2(jcr->errmsg, _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
1203 jcr->last_fname, be.bstrerror());
1204 Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
1205 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1207 return bacl_exit_error;
1211 return bacl_exit_ok;
1213 #endif /* HAVE_EXTENDED_ACL */
1216 * For this OS setup the build and parse function pointer to the OS specific functions.
1218 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_acl_streams;
1219 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = solaris_parse_acl_streams;
1221 #endif /* HAVE_SUN_OS */
1224 * Entry points when compiled with support for ACLs on a supported platform.
1228 * Read and send an ACL for the last encountered file.
1230 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1233 * Call the appropriate function.
1235 if (os_build_acl_streams) {
1236 return (*os_build_acl_streams)(jcr, ff_pkt);
1238 return bacl_exit_error;
1241 bacl_exit_code parse_acl_streams(JCR *jcr, int stream)
1246 case STREAM_UNIX_ACCESS_ACL:
1247 case STREAM_UNIX_DEFAULT_ACL:
1249 * Handle legacy ACL streams.
1251 if (os_parse_acl_streams) {
1252 return (*os_parse_acl_streams)(jcr, stream);
1256 if (os_parse_acl_streams) {
1258 * Walk the os_access_acl_streams array with the supported Access ACL streams for this OS.
1260 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1261 if (os_access_acl_streams[cnt] == stream) {
1262 return (*os_parse_acl_streams)(jcr, stream);
1266 * Walk the os_default_acl_streams array with the supported Default ACL streams for this OS.
1268 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1269 if (os_default_acl_streams[cnt] == stream) {
1270 return (*os_parse_acl_streams)(jcr, stream);
1276 Qmsg2(jcr, M_WARNING, 0,
1277 _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
1278 jcr->last_fname, stream);
1279 return bacl_exit_error;