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 #include <sys/access.h>
132 * Define the supported ACL streams for this OS
134 static int os_access_acl_streams[1] = { STREAM_ACL_AIX_TEXT };
135 static int os_default_acl_streams[1] = { -1 };
137 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
141 /* TODO: need to use aclx_get and aclx_put instead of acl_get and acl_put
142 * to work on all AIX FS
144 if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
145 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
146 actuallyfree(acl_text);
147 return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT);
149 return bacl_exit_error;
152 static bacl_exit_code aix_parse_acl_streams(JCR *jcr, int stream)
154 if (acl_put(jcr->last_fname, jcr->acl_data->content, 0) != 0) {
155 return bacl_exit_error;
161 * For this OS setup the build and parse function pointer to the OS specific functions.
163 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = aix_build_acl_streams;
164 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = aix_parse_acl_streams;
166 #elif defined(HAVE_DARWIN_OS) || \
167 defined(HAVE_FREEBSD_OS) || \
168 defined(HAVE_IRIX_OS) || \
169 defined(HAVE_OSF1_OS) || \
170 defined(HAVE_LINUX_OS)
172 #include <sys/types.h>
174 #ifdef HAVE_SYS_ACL_H
177 #error "configure failed to detect availability of sys/acl.h"
181 * On IRIX we can get shortened ACLs
183 #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
184 #define acl_to_text(acl,len) acl_to_short_text((acl), (len))
188 * In Linux we can get numeric and/or shorted ACLs
190 #if defined(HAVE_LINUX_OS)
191 #if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
192 #define BACL_ALTERNATE_TEXT (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
193 #elif defined(BACL_WANT_SHORT_ACLS)
194 #define BACL_ALTERNATE_TEXT TEXT_ABBREVIATE
195 #elif defined(BACL_WANT_NUMERIC_IDS)
196 #define BACL_ALTERNATE_TEXT TEXT_NUMERIC_IDS
198 #ifdef BACL_ALTERNATE_TEXT
199 #include <acl/libacl.h>
200 #define acl_to_text(acl,len) (acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
205 * Some generic functions used by multiple OSes.
207 static acl_type_t bac_to_os_acltype(bacl_type acltype)
212 case BACL_TYPE_ACCESS:
213 ostype = ACL_TYPE_ACCESS;
215 case BACL_TYPE_DEFAULT:
216 ostype = ACL_TYPE_DEFAULT;
219 #ifdef ACL_TYPE_DEFAULT_DIR
220 case BACL_TYPE_DEFAULT_DIR:
222 * OSF1 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
224 ostype = ACL_TYPE_DEFAULT_DIR;
227 #ifdef ACL_TYPE_EXTENDED
228 case BACL_TYPE_EXTENDED:
230 * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
232 ostype = ACL_TYPE_EXTENDED;
237 * This should never happen, as the per OS version function only tries acl
238 * types supported on a certain platform.
240 ostype = (acl_type_t)ACL_TYPE_NONE;
246 #if !defined(HAVE_DARWIN_OS)
248 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
249 * There is no need to store those acls as we already store the stat bits too.
251 static bool acl_is_trivial(acl_t acl)
254 * acl is trivial if it has only the following entries:
261 #if defined(HAVE_FREEBSD_OS) || \
262 defined(HAVE_LINUX_OS)
265 entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
266 while (entry_available == 1) {
268 * Get the tag type of this acl entry.
269 * If we fail to get the tagtype we call the acl non-trivial.
271 if (acl_get_tag_type(ace, &tag) < 0)
274 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
276 if (tag != ACL_USER_OBJ &&
277 tag != ACL_GROUP_OBJ &&
280 entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
283 #elif defined(HAVE_IRIX_OS)
286 for (n = 0; n < acl->acl_cnt; n++) {
287 ace = &acl->acl_entry[n];
291 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
293 if (tag != ACL_USER_OBJ &&
294 tag != ACL_GROUP_OBJ &&
295 tag != ACL_OTHER_OBJ)
299 #elif defined(HAVE_OSF1_OS)
302 ace = acl->acl_first;
303 count = acl->acl_num;
306 tag = ace->entry->acl_type;
308 * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
310 if (tag != ACL_USER_OBJ &&
311 tag != ACL_GROUP_OBJ &&
315 * On Tru64, perm can also contain non-standard bits such as
316 * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
318 if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
329 * Generic wrapper around acl_get_file call.
331 static bacl_exit_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
338 ostype = bac_to_os_acltype(acltype);
339 acl = acl_get_file(jcr->last_fname, ostype);
341 #if defined(HAVE_IRIX_OS)
343 * From observation, IRIX's acl_get_file() seems to return a
344 * non-NULL acl with a count field of -1 when a file has no ACL
345 * defined, while IRIX's acl_to_text() returns NULL when presented
348 * Checking the count in the acl structure before calling
349 * acl_to_text() lets us avoid error messages about files
350 * with no ACLs, without modifying the flow of the code used for
351 * other operating systems, and it saves making some calls
352 * to acl_to_text() besides.
354 if (acl->acl_cnt <= 0) {
355 pm_strcpy(jcr->acl_data->content, "");
356 jcr->acl_data->content_length = 0;
362 #if !defined(HAVE_DARWIN_OS)
364 * Make sure this is not just a trivial ACL.
366 if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
368 * The ACLs simply reflect the (already known) standard permissions
369 * So we don't send an ACL stream to the SD.
371 pm_strcpy(jcr->acl_data->content, "");
372 jcr->acl_data->content_length = 0;
378 if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
379 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
385 Mmsg2(jcr->errmsg, _("acl_to_text error on file \"%s\": ERR=%s\n"),
386 jcr->last_fname, be.bstrerror());
387 Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",
388 jcr->last_fname, be.bstrerror());
390 pm_strcpy(jcr->acl_data->content, "");
391 jcr->acl_data->content_length = 0;
393 return bacl_exit_error;
397 * Handle errors gracefully.
399 if (acl == (acl_t)NULL) {
401 #if defined(BACL_ENOTSUP)
404 * If the filesystem reports it doesn't support ACLs we clear the
405 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
406 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
407 * when we change from one filesystem to an other.
409 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
410 break; /* not supported */
413 pm_strcpy(jcr->acl_data->content, "");
414 jcr->acl_data->content_length = 0;
417 /* Some real error */
418 Mmsg2(jcr->errmsg, _("acl_get_file error on file \"%s\": ERR=%s\n"),
419 jcr->last_fname, be.bstrerror());
420 Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",
421 jcr->last_fname, be.bstrerror());
423 pm_strcpy(jcr->acl_data->content, "");
424 jcr->acl_data->content_length = 0;
425 return bacl_exit_error;
430 * Not supported, just pretend there is nothing to see
432 pm_strcpy(jcr->acl_data->content, "");
433 jcr->acl_data->content_length = 0;
438 * Generic wrapper around acl_set_file call.
440 static bacl_exit_code generic_set_acl_on_os(JCR *jcr, bacl_type acltype)
447 * If we get empty default ACLs, clear ACLs now
449 ostype = bac_to_os_acltype(acltype);
450 if (ostype == ACL_TYPE_DEFAULT && strlen(jcr->acl_data->content) == 0) {
451 if (acl_delete_def_file(jcr->last_fname) == 0) {
458 Mmsg2(jcr->errmsg, _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
459 jcr->last_fname, be.bstrerror());
460 return bacl_exit_error;
464 acl = acl_from_text(jcr->acl_data->content);
466 Mmsg2(jcr->errmsg, _("acl_from_text error on file \"%s\": ERR=%s\n"),
467 jcr->last_fname, be.bstrerror());
468 Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",
469 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
470 return bacl_exit_error;
473 #ifndef HAVE_FREEBSD_OS
475 * FreeBSD always fails acl_valid() - at least on valid input...
476 * As it does the right thing, given valid input, just ignore acl_valid().
478 if (acl_valid(acl) != 0) {
479 Mmsg2(jcr->errmsg, _("acl_valid error on file \"%s\": ERR=%s\n"),
480 jcr->last_fname, be.bstrerror());
481 Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",
482 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
484 return bacl_exit_error;
489 * Restore the ACLs, but don't complain about links which really should
490 * not have attributes, and the file it is linked to may not yet be restored.
491 * This is only true for the old acl streams as in the new implementation we
492 * don't save acls of symlinks (which cannot have acls anyhow)
494 if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
500 Mmsg2(jcr->errmsg, _("acl_set_file error on file \"%s\": ERR=%s\n"),
501 jcr->last_fname, be.bstrerror());
502 Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
503 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
505 return bacl_exit_error;
513 * OS specific functions for handling different types of acl streams.
515 #if defined(HAVE_DARWIN_OS)
517 * Define the supported ACL streams for this OS
519 static int os_access_acl_streams[1] = { STREAM_ACL_DARWIN_ACCESS_ACL };
520 static int os_default_acl_streams[1] = { -1 };
522 static bacl_exit_code darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
524 #if defined(ACL_TYPE_EXTENDED)
526 * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
527 * and acl_get_file (name, ACL_TYPE_DEFAULT)
528 * always return NULL / EINVAL. There is no point in making
529 * these two useless calls. The real ACL is retrieved through
530 * acl_get_file (name, ACL_TYPE_EXTENDED).
532 * Read access ACLs for files, dirs and links
534 if (generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED) == bacl_exit_fatal)
535 return bacl_exit_fatal;
538 * Read access ACLs for files, dirs and links
540 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
541 return bacl_exit_fatal;
544 if (jcr->acl_data->content_length > 0) {
545 return send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL);
550 static bacl_exit_code darwin_parse_acl_streams(JCR *jcr, int stream)
552 #if defined(ACL_TYPE_EXTENDED)
553 return generic_set_acl_on_os(jcr, BACL_TYPE_EXTENDED);
555 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
560 * For this OS setup the build and parse function pointer to the OS specific functions.
562 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = darwin_build_acl_streams;
563 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = darwin_parse_acl_streams;
565 #elif defined(HAVE_FREEBSD_OS) || \
566 defined(HAVE_IRIX_OS) || \
567 defined(HAVE_LINUX_OS)
570 * Define the supported ACL streams for these OSes
572 #if defined(HAVE_FREEBSD_OS)
573 static int os_access_acl_streams[1] = { STREAM_ACL_FREEBSD_ACCESS_ACL };
574 static int os_default_acl_streams[1] = { STREAM_ACL_FREEBSD_DEFAULT_ACL };
575 #elif defined(HAVE_IRIX_OS)
576 static int os_access_acl_streams[1] = { STREAM_ACL_IRIX_ACCESS_ACL };
577 static int os_default_acl_streams[1] = { STREAM_ACL_IRIX_DEFAULT_ACL };
578 #elif defined(HAVE_LINUX_OS)
579 static int os_access_acl_streams[1] = { STREAM_ACL_LINUX_ACCESS_ACL };
580 static int os_default_acl_streams[1] = { STREAM_ACL_LINUX_DEFAULT_ACL };
583 static bacl_exit_code generic_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
586 * Read access ACLs for files, dirs and links
588 if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
589 return bacl_exit_fatal;
591 if (jcr->acl_data->content_length > 0) {
592 if (send_acl_stream(jcr, os_access_acl_streams[0]) == bacl_exit_fatal)
593 return bacl_exit_fatal;
597 * Directories can have default ACLs too
599 if (ff_pkt->type == FT_DIREND) {
600 if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
601 return bacl_exit_fatal;
602 if (jcr->acl_data->content_length > 0) {
603 if (send_acl_stream(jcr, os_default_acl_streams[0]) == bacl_exit_fatal)
604 return bacl_exit_fatal;
610 static bacl_exit_code generic_parse_acl_streams(JCR *jcr, int stream)
615 case STREAM_UNIX_ACCESS_ACL:
616 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
617 case STREAM_UNIX_DEFAULT_ACL:
618 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
621 * See what type of acl it is.
623 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
624 if (os_access_acl_streams[cnt] == stream) {
625 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
628 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
629 if (os_default_acl_streams[cnt] == stream) {
630 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
635 return bacl_exit_error;
639 * For this OSes setup the build and parse function pointer to the OS specific functions.
641 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_build_acl_streams;
642 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = generic_parse_acl_streams;
644 #elif defined(HAVE_OSF1_OS)
647 * Define the supported ACL streams for this OS
649 static int os_access_acl_streams[1] = { STREAM_ACL_TRU64_ACCESS_ACL };
650 static int os_default_acl_streams[2] = { STREAM_ACL_TRU64_DEFAULT_ACL, STREAM_ACL_TRU64_DEFAULT_DIR_ACL };
652 static bacl_exit_code tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
655 * Read access ACLs for files, dirs and links
657 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
658 return bacl_exit_error;
659 if (jcr->acl_data->content_length > 0) {
660 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL))
661 return bacl_exit_error;
664 * Directories can have default ACLs too
666 if (ff_pkt->type == FT_DIREND) {
667 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
668 return bacl_exit_error;
669 if (jcr->acl_data->content_length > 0) {
670 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL))
671 return bacl_exit_error;
674 * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
675 * This is an inherited acl for all subdirs.
676 * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
677 * Section 21.5 Default ACLs
679 if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR)) < 0)
680 return bacl_exit_error;
681 if (jcr->acl_data->content_length > 0) {
682 if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL))
683 return bacl_exit_error;
689 static bacl_exit_code tru64_parse_acl_streams(JCR *jcr, int stream)
692 case STREAM_UNIX_ACCESS_ACL:
693 case STREAM_ACL_TRU64_ACCESS_ACL:
694 return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
695 case STREAM_UNIX_DEFAULT_ACL:
696 case STREAM_ACL_TRU64_DEFAULT_ACL:
697 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
698 case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
699 return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR);
703 * For this OS setup the build and parse function pointer to the OS specific functions.
705 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = tru64_build_acl_streams;
706 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = tru64_parse_acl_streams;
710 #elif defined(HAVE_HPUX_OS)
711 #ifdef HAVE_SYS_ACL_H
714 #error "configure failed to detect availability of sys/acl.h"
720 * Define the supported ACL streams for this OS
722 static int os_access_acl_streams[1] = { STREAM_ACL_HPUX_ACL_ENTRY };
723 static int os_default_acl_streams[1] = { -1 };
726 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
727 * There is no need to store those acls as we already store the stat bits too.
729 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
734 for (n = 0; n < count; n++) {
737 * See if this acl just is the stat mode in acl form.
739 if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
740 (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
741 (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
748 * OS specific functions for handling different types of acl streams.
750 static bacl_exit_code hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
753 struct acl_entry acls[NACLENTRIES];
757 if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
759 #if defined(BACL_ENOTSUP)
762 * Not supported, just pretend there is nothing to see
764 * If the filesystem reports it doesn't support ACLs we clear the
765 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
766 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
767 * when we change from one filesystem to an other.
769 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
770 pm_strcpy(jcr->acl_data->content, "");
771 jcr->acl_data->content_length = 0;
775 pm_strcpy(jcr->acl_data->content, "");
776 jcr->acl_data->content_length = 0;
779 Mmsg2(jcr->errmsg, _("getacl error on file \"%s\": ERR=%s\n"),
780 jcr->last_fname, be.bstrerror());
781 Dmsg2(100, "getacl error file=%s ERR=%s\n",
782 jcr->last_fname, be.bstrerror());
784 pm_strcpy(jcr->acl_data->content, "");
785 jcr->acl_data->content_length = 0;
786 return bacl_exit_error;
790 pm_strcpy(jcr->acl_data->content, "");
791 jcr->acl_data->content_length = 0;
794 if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
795 if (acl_is_trivial(n, acls, ff_pkt->statp)) {
797 * The ACLs simply reflect the (already known) standard permissions
798 * So we don't send an ACL stream to the SD.
800 pm_strcpy(jcr->acl_data->content, "");
801 jcr->acl_data->content_length = 0;
804 if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
805 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
806 actuallyfree(acl_text);
808 return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
810 Mmsg2(jcr->errmsg, _("acltostr error on file \"%s\": ERR=%s\n"),
811 jcr->last_fname, be.bstrerror());
812 Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",
813 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
814 return bacl_exit_error;
816 return bacl_exit_error;
819 static bacl_exit_code hpux_parse_acl_streams(JCR *jcr, int stream)
822 struct acl_entry acls[NACLENTRIES];
825 n = strtoacl(jcr->acl_data->content, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
827 Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
828 jcr->last_fname, be.bstrerror());
829 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
830 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
831 return bacl_exit_error;
833 if (strtoacl(jcr->acl_data->content, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
834 Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
835 jcr->last_fname, be.bstrerror());
836 Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",
837 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
839 return bacl_exit_error;
842 * Restore the ACLs, but don't complain about links which really should
843 * not have attributes, and the file it is linked to may not yet be restored.
844 * This is only true for the old acl streams as in the new implementation we
845 * don't save acls of symlinks (which cannot have acls anyhow)
847 if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
852 Mmsg2(jcr->errmsg, _("setacl error on file \"%s\": ERR=%s\n"),
853 jcr->last_fname, be.bstrerror());
854 Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
855 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
856 return bacl_exit_error;
863 * For this OS setup the build and parse function pointer to the OS specific functions.
865 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = hpux_build_acl_streams;
866 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = hpux_parse_acl_streams;
868 #elif defined(HAVE_SUN_OS)
869 #ifdef HAVE_SYS_ACL_H
872 #error "configure failed to detect availability of sys/acl.h"
875 #if defined(HAVE_EXTENDED_ACL)
877 * We define some internals of the Solaris acl libs here as those
878 * are not exposed yet. Probably because they want us to see the
879 * acls as opague data. But as we need to support different platforms
880 * and versions of Solaris we need to expose some data to be able
881 * to determine the type of acl used to stuff it into the correct
882 * data stream. I know this is far from portable, but maybe the
883 * proper interface is exposed later on and we can get ride of
884 * this kludge. Newer versions of Solaris include sys/acl_impl.h
885 * which has implementation details of acls, if thats included we
886 * don't have to define it ourself.
888 #if !defined(_SYS_ACL_IMPL_H)
889 typedef enum acl_type {
896 * Two external references to functions in the libsec library function not in current include files.
899 int acl_type(acl_t *);
900 char *acl_strerror(int);
904 * Define the supported ACL streams for this OS
906 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT, STREAM_ACL_SOLARIS_ACE };
907 static int os_default_acl_streams[1] = { -1 };
910 * As the new libsec interface with acl_totext and acl_fromtext also handles
911 * the old format from acltotext we can use the new functions even
912 * for acls retrieved and stored in the database with older fd versions. If the
913 * new interface is not defined (Solaris 9 and older we fall back to the old code)
915 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
917 int acl_enabled, flags;
920 bacl_exit_code stream_status = bacl_exit_error;
924 * See if filesystem supports acls.
926 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
927 switch (acl_enabled) {
930 * If the filesystem reports it doesn't support ACLs we clear the
931 * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
932 * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
933 * when we change from one filesystem to an other.
935 jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
936 pm_strcpy(jcr->acl_data->content, "");
937 jcr->acl_data->content_length = 0;
944 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
945 jcr->last_fname, be.bstrerror());
946 Dmsg2(100, "pathconf error file=%s ERR=%s\n",
947 jcr->last_fname, be.bstrerror());
948 return bacl_exit_error;
955 * Get ACL info: don't bother allocating space if there is only a trivial ACL.
957 if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
962 Mmsg2(jcr->errmsg, _("acl_get error on file \"%s\": ERR=%s\n"),
963 jcr->last_fname, acl_strerror(errno));
964 Dmsg2(100, "acl_get error file=%s ERR=%s\n",
965 jcr->last_fname, acl_strerror(errno));
966 return bacl_exit_error;
972 * The ACLs simply reflect the (already known) standard permissions
973 * So we don't send an ACL stream to the SD.
975 pm_strcpy(jcr->acl_data->content, "");
976 jcr->acl_data->content_length = 0;
980 #if defined(ACL_SID_FMT)
982 * New format flag added in newer Solaris versions.
984 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
986 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
987 #endif /* ACL_SID_FMT */
989 if ((acl_text = acl_totext(aclp, flags)) != NULL) {
990 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
991 actuallyfree(acl_text);
993 switch (acl_type(aclp)) {
995 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
998 stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE);
1006 return stream_status;
1009 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
1012 int acl_enabled, error;
1016 case STREAM_UNIX_ACCESS_ACL:
1017 case STREAM_ACL_SOLARIS_ACLENT:
1018 case STREAM_ACL_SOLARIS_ACE:
1020 * First make sure the filesystem supports acls.
1022 acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1023 switch (acl_enabled) {
1025 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
1027 return bacl_exit_error;
1031 return bacl_exit_ok;
1033 Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1034 jcr->last_fname, be.bstrerror());
1035 Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1036 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1037 return bacl_exit_error;
1041 * On a filesystem with ACL support make sure this particilar ACL type can be restored.
1044 case STREAM_ACL_SOLARIS_ACLENT:
1046 * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
1048 if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
1049 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without aclent acl support\n"),
1051 return bacl_exit_error;
1054 case STREAM_ACL_SOLARIS_ACE:
1056 * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
1058 if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
1059 Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without ace acl support\n"),
1061 return bacl_exit_error;
1066 * Stream id which doesn't describe the type of acl which is encoded.
1073 if ((error = acl_fromtext(jcr->acl_data->content, &aclp)) != 0) {
1074 Mmsg2(jcr->errmsg, _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1075 jcr->last_fname, acl_strerror(error));
1076 Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",
1077 jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1078 return bacl_exit_error;
1082 * Validate that the conversion gave us the correct acl type.
1085 case STREAM_ACL_SOLARIS_ACLENT:
1086 if (acl_type(aclp) != ACLENT_T) {
1087 Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1089 return bacl_exit_error;
1092 case STREAM_ACL_SOLARIS_ACE:
1093 if (acl_type(aclp) != ACE_T) {
1094 Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1096 return bacl_exit_error;
1101 * Stream id which doesn't describe the type of acl which is encoded.
1107 * Restore the ACLs, but don't complain about links which really should
1108 * not have attributes, and the file it is linked to may not yet be restored.
1109 * This is only true for the old acl streams as in the new implementation we
1110 * don't save acls of symlinks (which cannot have acls anyhow)
1112 if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1116 return bacl_exit_ok;
1118 Mmsg2(jcr->errmsg, _("acl_set error on file \"%s\": ERR=%s\n"),
1119 jcr->last_fname, acl_strerror(error));
1120 Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",
1121 jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1123 return bacl_exit_error;
1128 return bacl_exit_ok;
1130 return bacl_exit_error;
1131 } /* end switch (stream) */
1134 #else /* HAVE_EXTENDED_ACL */
1137 * Define the supported ACL streams for this OS
1139 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT };
1140 static int os_default_acl_streams[1] = { -1 };
1143 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1144 * There is no need to store those acls as we already store the stat bits too.
1146 static bool acl_is_trivial(int count, aclent_t *entries)
1151 for (n = 0; n < count; n++) {
1154 if (!(ace->a_type == USER_OBJ ||
1155 ace->a_type == GROUP_OBJ ||
1156 ace->a_type == OTHER_OBJ ||
1157 ace->a_type == CLASS_OBJ))
1164 * OS specific functions for handling different types of acl streams.
1166 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1173 n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1174 if (n < MIN_ACL_ENTRIES)
1175 return bacl_exit_error;
1177 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1178 if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1179 if (acl_is_trivial(n, acls)) {
1181 * The ACLs simply reflect the (already known) standard permissions
1182 * So we don't send an ACL stream to the SD.
1185 pm_strcpy(jcr->acl_data->content, "");
1186 jcr->acl_data->content_length = 0;
1187 return bacl_exit_ok;
1190 if ((acl_text = acltotext(acls, n)) != NULL) {
1191 jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1192 actuallyfree(acl_text);
1194 return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1197 Mmsg2(jcr->errmsg, _("acltotext error on file \"%s\": ERR=%s\n"),
1198 jcr->last_fname, be.bstrerror());
1199 Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",
1200 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1204 return bacl_exit_error;
1207 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
1213 acls = aclfromtext(jcr->acl_data->content, &n);
1215 Mmsg2(jcr->errmsg, _("aclfromtext error on file \"%s\": ERR=%s\n"),
1216 jcr->last_fname, be.bstrerror());
1217 Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",
1218 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1219 return bacl_exit_error;
1223 * Restore the ACLs, but don't complain about links which really should
1224 * not have attributes, and the file it is linked to may not yet be restored.
1226 if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
1230 return bacl_exit_ok;
1232 Mmsg2(jcr->errmsg, _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
1233 jcr->last_fname, be.bstrerror());
1234 Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
1235 jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1237 return bacl_exit_error;
1241 return bacl_exit_ok;
1243 #endif /* HAVE_EXTENDED_ACL */
1246 * For this OS setup the build and parse function pointer to the OS specific functions.
1248 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_acl_streams;
1249 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = solaris_parse_acl_streams;
1251 #endif /* HAVE_SUN_OS */
1252 #endif /* HAVE_ACL */
1255 * Entry points when compiled with support for ACLs on a supported platform.
1259 * Read and send an ACL for the last encountered file.
1261 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1264 * See if we are changing from one device to an other.
1265 * We save the current device we are scanning and compare
1266 * it with the current st_dev in the last stat performed on
1267 * the file we are currently storing.
1269 if (jcr->acl_data->current_dev != ff_pkt->statp.st_dev) {
1271 * Reset the acl save flags.
1273 jcr->acl_data->flags = 0;
1275 jcr->acl_data->flags |= BACL_FLAG_SAVE_NATIVE;
1278 * Save that we started scanning a new filesystem.
1280 jcr->acl_data->current_dev = ff_pkt->statp.st_dev;
1283 #if defined(HAVE_ACL)
1285 * See if the BACL_FLAG_SAVE_NATIVE flag is set which lets us know if we should
1288 if (jcr->acl_data->flags & BACL_FLAG_SAVE_NATIVE) {
1290 * Call the appropriate function.
1292 if (os_build_acl_streams) {
1293 return (*os_build_acl_streams)(jcr, ff_pkt);
1296 return bacl_exit_ok;
1299 return bacl_exit_error;
1302 bacl_exit_code parse_acl_streams(JCR *jcr, int stream)
1307 #if defined(HAVE_ACL)
1308 case STREAM_UNIX_ACCESS_ACL:
1309 case STREAM_UNIX_DEFAULT_ACL:
1311 * Handle legacy ACL streams.
1313 if (os_parse_acl_streams) {
1314 return (*os_parse_acl_streams)(jcr, stream);
1318 if (os_parse_acl_streams) {
1320 * Walk the os_access_acl_streams array with the supported Access ACL streams for this OS.
1322 for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1323 if (os_access_acl_streams[cnt] == stream) {
1324 return (*os_parse_acl_streams)(jcr, stream);
1328 * Walk the os_default_acl_streams array with the supported Default ACL streams for this OS.
1330 for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1331 if (os_default_acl_streams[cnt] == stream) {
1332 return (*os_parse_acl_streams)(jcr, stream);
1342 Qmsg2(jcr, M_WARNING, 0,
1343 _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
1344 jcr->last_fname, stream);
1345 return bacl_exit_error;