]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/acl.c
6e17b198c653ee4b7bc4898c4f24e616816cee29
[bacula/bacula] / bacula / src / filed / acl.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2004-2008 Free Software Foundation Europe e.V.
5
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
11    in the file LICENSE.
12
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.
17
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
21    02110-1301, USA.
22
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.
27 */
28 /*
29  * Functions to handle ACLs for bacula.
30  *
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.
33  *
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.
36  *
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
42  * native format.
43  *
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.
47  * As we implement the decoding/restoring process as a big switch based
48  * on the stream number being passed in extending the switching code is
49  * easy.
50  *
51  *   Original written by Preben 'Peppe' Guldberg, December MMIV
52  *   Major rewrite by Marco van Wieringen, November MMVIII
53  *
54  *   Version $Id$
55  */
56   
57 #include "bacula.h"
58 #include "filed.h"
59   
60 /*
61  * List of supported OSs.
62  * Not sure if all the HAVE_XYZ_OS are correct for autoconf.
63  * The ones that says man page, are coded according to man pages only.
64  */
65 #if !defined(HAVE_ACL)              /* ACL support is required, of course */ \
66    || !( defined(HAVE_AIX_OS)       /* man page -- may need flags         */ \
67       || defined(HAVE_DARWIN_OS)    /* tested   -- compile without flags  */ \
68       || defined(HAVE_FREEBSD_OS)   /* tested   -- compile without flags  */ \
69       || defined(HAVE_HPUX_OS)      /* man page -- may need flags         */ \
70       || defined(HAVE_IRIX_OS)      /* man page -- compile without flags  */ \
71       || defined(HAVE_LINUX_OS)     /* tested   -- compile with -lacl     */ \
72       || defined(HAVE_OSF1_OS)      /* man page -- may need -lpacl        */ \
73       || defined(HAVE_SUN_OS)       /* tested   -- compile with -lsec     */ \
74        )
75
76 /*
77  * Entry points when compiled without support for ACLs or on an unsupported platform.
78  */
79 bool build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
80 {
81    Jmsg(jcr, M_FATAL, 0, _("ACL support not configured for your machine.\n"));
82    return false;
83 }
84
85 bool parse_acl_stream(JCR *jcr, int stream)
86 {
87    Jmsg(jcr, M_FATAL, 0, _("ACL support not configured for your machine.\n"));
88    return false;
89 }
90
91 #else
92
93 /*
94  * Send an ACL stream to the SD.
95  */
96 static bool send_acl_stream(JCR *jcr, int stream, int len)
97 {
98    BSOCK *sd = jcr->store_bsock;
99    POOLMEM *msgsave;
100 #ifdef FD_NO_SEND_TEST
101    return true;
102 #endif
103
104    /*
105     * Send header
106     */
107    if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
108       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
109             sd->bstrerror());
110
111       return false;
112    }
113
114    /*
115     * Send the buffer to the storage deamon
116     */
117    Dmsg1(400, "Backing up ACL <%s>\n", jcr->acl_data);
118    msgsave = sd->msg;
119    sd->msg = jcr->acl_data;
120    sd->msglen = len + 1;
121    if (!sd->send()) {
122       sd->msg = msgsave;
123       sd->msglen = 0;
124       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
125             sd->bstrerror());
126
127       return false;
128    }
129
130    jcr->JobBytes += sd->msglen;
131    sd->msg = msgsave;
132    if (!sd->signal(BNET_EOD)) {
133       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
134             sd->bstrerror());
135
136       return false;
137    }
138
139    Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
140
141    return true;
142 }
143
144 #if defined(HAVE_AIX_OS)
145
146 #include <sys/access.h>
147
148 static bool aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
149 {
150    char *acl_text;
151    int len;
152
153    if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
154       len = pm_strcpy(jcr->acl_data, acl_text);
155       actuallyfree(acl_text);
156
157       return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT, len);
158    }
159
160    return false;
161 }
162
163 static bool aix_parse_acl_stream(JCR *jcr, int stream)
164 {
165    if (acl_put(jcr->last_fname, jcr->acl_data, 0) != 0) {
166       return false;
167    }
168
169    return true;
170 }
171
172 #elif defined(HAVE_DARWIN_OS) \
173    || defined(HAVE_FREEBSD_OS) \
174    || defined(HAVE_IRIX_OS) \
175    || defined(HAVE_OSF1_OS) \
176    || defined(HAVE_LINUX_OS)
177
178 #include <sys/types.h>
179
180 #ifdef HAVE_SYS_ACL_H
181 #include <sys/acl.h>
182 #else
183 #error "configure failed to detect availability of sys/acl.h"
184 #endif
185
186 /* On IRIX we can get shortened ACLs */
187 #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
188 #define acl_to_text(acl,len)     acl_to_short_text((acl), (len))
189 #endif
190
191 /* In Linux we can get numeric and/or shorted ACLs */
192 #if defined(HAVE_LINUX_OS)
193 #if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
194 #define BACL_ALTERNATE_TEXT            (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
195 #elif defined(BACL_WANT_SHORT_ACLS)
196 #define BACL_ALTERNATE_TEXT            TEXT_ABBREVIATE
197 #elif defined(BACL_WANT_NUMERIC_IDS)
198 #define BACL_ALTERNATE_TEXT            TEXT_NUMERIC_IDS
199 #endif
200 #ifdef BACL_ALTERNATE_TEXT
201 #include <acl/libacl.h>
202 #define acl_to_text(acl,len)     (acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
203 #endif
204 #endif
205
206 /*
207  * Some generic functions used by multiple OSes.
208  */
209 static acl_type_t bac_to_os_acltype(bacl_type acltype)
210 {
211    acl_type_t ostype;
212
213    switch (acltype) {
214    case BACL_TYPE_ACCESS:
215       ostype = ACL_TYPE_ACCESS;
216       break;
217    case BACL_TYPE_DEFAULT:
218       ostype = ACL_TYPE_DEFAULT;
219       break;
220
221 #ifdef ACL_TYPE_DEFAULT_DIR
222    case BACL_TYPE_DEFAULT_DIR:
223       /*
224        * OSF1 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
225        */
226       ostype = ACL_TYPE_DEFAULT_DIR;
227       break;
228 #endif
229 #ifdef ACL_TYPE_EXTENDED
230    case BACL_TYPE_EXTENDED:
231       /*
232        * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
233        */
234       ostype = ACL_TYPE_EXTENDED;
235       break;
236 #endif
237    default:
238       /*
239        * This should never happen, as the per os version function only tries acl
240        * types supported on a certain platform.
241        */
242       ostype = (acl_type_t)ACL_TYPE_NONE;
243       break;
244    }
245
246    return ostype;
247 }
248
249 /*
250  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
251  * There is no need to store those acls as we already store the stat bits too.
252  */
253 #if defined(HAVE_DARWIN_OS)
254 static bool acl_is_trivial(acl_t acl)
255 {
256    /*
257     * acl is trivial if it is empty.
258     */
259    return (acl_entries(acl) == 0);
260 }
261 #else /* FreeBSD, IRIX, OSF1, Linux */
262 static bool acl_is_trivial(acl_t acl)
263 {
264   /*
265    * acl is trivial if it has only the following entries:
266    * "user::",
267    * "group::",
268    * "other::"
269    */
270    acl_entry_t ace;
271    acl_tag_t tag;
272 #if defined(HAVE_FREEBSD_OS) || defined(HAVE_LINUX_OS)
273    int entry_available;
274
275    entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
276    while (entry_available == 1) {
277       /*
278        * Get the tag type of this acl entry.
279        * If we fail to get the tagtype we call the acl non-trivial.
280        */
281       if (acl_get_tag_type(ace, &tag) < 0)
282          return false;
283
284       /*
285        * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
286        */
287       if (tag != ACL_USER_OBJ &&
288           tag != ACL_GROUP_OBJ &&
289           tag != ACL_OTHER)
290          return false;
291
292       entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
293    }
294
295    return true;
296 #elif defined(HAVE_IRIX_OS)
297    int n;
298
299    for (n = 0; n < acl->acl_cnt; n++) {
300       ace = &acl->acl_entry[n];
301       tag = ace->ae_tag;
302
303       /*
304        * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
305        */
306       if (tag != ACL_USER_OBJ &&
307           tag != ACL_GROUP_OBJ &&
308           tag != ACL_OTHER)
309          return false;
310    }
311
312    return true;
313 #elif defined(HAVE_OSF1_OS)
314    int count;
315
316    ace = acl->acl_first;
317    count = acl->acl_num;
318
319    while (count > 0) {
320       tag = ace->entry->acl_type;
321
322       /*
323        * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
324        */
325       if (tag != ACL_USER_OBJ &&
326           tag != ACL_GROUP_OBJ &&
327           tag != ACL_OTHER)
328          return false;
329
330       /*
331        * On Tru64, perm can also contain non-standard bits such as
332        * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
333        */
334       if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
335          return false;
336
337       ace = ace->next;
338       count--;
339    }
340
341    return true;
342 #endif
343 }
344 #endif
345
346 /*
347  * Generic wrapper around acl_get_file call.
348  */
349 static int generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
350 {
351    acl_t acl;
352    int len;
353    acl_type_t ostype;
354    char *acl_text;
355
356    ostype = bac_to_os_acltype(acltype);
357    acl = acl_get_file(jcr->last_fname, ostype);
358    if (acl) {
359 #if defined(HAVE_IRIX_OS)
360       /* 
361        * From observation, IRIX's acl_get_file() seems to return a
362        * non-NULL acl with a count field of -1 when a file has no ACL
363        * defined, while IRIX's acl_to_text() returns NULL when presented
364        * with such an ACL. 
365        *
366        * Checking the count in the acl structure before calling
367        * acl_to_text() lets us avoid error messages about files
368        * with no ACLs, without modifying the flow of the code used for 
369        * other operating systems, and it saves making some calls
370        * to acl_to_text() besides.
371        */
372       if (acl->acl_cnt <= 0) {
373          pm_strcpy(jcr->acl_data, "");
374          acl_free(acl);
375          return 0;
376       }
377 #endif
378
379       /*
380        * Make sure this is not just a trivial ACL.
381        */
382       if ((acltype == BACL_TYPE_ACCESS ||
383            acltype == BACL_TYPE_EXTENDED) &&
384            acl_is_trivial(acl)) {
385          /*
386           * The ACLs simply reflect the (already known) standard permissions
387           * So we don't send an ACL stream to the SD.
388           */
389          pm_strcpy(jcr->acl_data, "");
390          acl_free(acl);
391          return 0;
392       }
393
394       if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
395          len = pm_strcpy(jcr->acl_data, acl_text);
396          acl_free(acl);
397          acl_free(acl_text);
398
399          return len;
400       }
401
402       berrno be;
403       Jmsg2(jcr, M_ERROR, 0, _("acl_to_text error on file \"%s\": ERR=%s\n"),
404          jcr->last_fname, be.bstrerror());
405       Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",  
406          jcr->last_fname, be.bstrerror());
407
408       pm_strcpy(jcr->acl_data, "");
409       acl_free(acl);
410
411       return -1;
412    }
413
414    /*
415     * Handle errors gracefully.
416     */
417    switch (errno) {
418 #if defined(BACL_ENOTSUP)
419    case BACL_ENOTSUP:
420       /*
421        * Not supported, just pretend there is nothing to see
422        */
423       pm_strcpy(jcr->acl_data, "");
424       return 0;
425 #endif
426    default:
427       berrno be;
428       Jmsg2(jcr, M_ERROR, 0, _("acl_get_file error on file \"%s\": ERR=%s\n"),
429          jcr->last_fname, be.bstrerror());
430       Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",  
431          jcr->last_fname, be.bstrerror());
432
433       pm_strcpy(jcr->acl_data, "");
434       return -1;
435    }
436 }
437
438 /*
439  * Generic wrapper around acl_set_file call.
440  */
441 static bool generic_set_acl_on_os(JCR *jcr, bacl_type acltype)
442 {
443    acl_t acl;
444    acl_type_t ostype;
445
446    /*
447     * If we get empty default ACLs, clear ACLs now
448     */
449    ostype = bac_to_os_acltype(acltype);
450    if (ostype == ACL_TYPE_DEFAULT && strlen(jcr->acl_data) == 0) {
451       if (acl_delete_def_file(jcr->last_fname) == 0) {
452          return true;
453       }
454       berrno be;
455       Jmsg2(jcr, M_ERROR, 0, _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
456          jcr->last_fname, be.bstrerror());
457
458       return false;
459    }
460
461    acl = acl_from_text(jcr->acl_data);
462    if (acl == NULL) {
463       berrno be;
464       Jmsg2(jcr, M_ERROR, 0, _("acl_from_text error on file \"%s\": ERR=%s\n"),
465          jcr->last_fname, be.bstrerror());
466       Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",  
467          jcr->acl_data, jcr->last_fname, be.bstrerror());
468
469       return false;
470    }
471
472    /*
473     * FreeBSD always fails acl_valid() - at least on valid input...
474     * As it does the right thing, given valid input, just ignore acl_valid().
475     */
476 #ifndef HAVE_FREEBSD_OS
477    if (acl_valid(acl) != 0) {
478       berrno be;
479       Jmsg2(jcr, M_ERROR, 0, _("ac_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, jcr->last_fname, be.bstrerror());
483       acl_free(acl);
484
485       return false;
486    }
487 #endif
488
489    /*
490     * Restore the ACLs, but don't complain about links which really should
491     * not have attributes, and the file it is linked to may not yet be restored.
492     * This is only true for the old acl streams as in the new implementation we
493     * don't save acls of symlinks (which cannot have acls anyhow)
494     */
495    if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
496       berrno be;
497       Jmsg2(jcr, M_ERROR, 0, _("acl_set_file error on file \"%s\": ERR=%s\n"),
498          jcr->last_fname, be.bstrerror());
499       Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",  
500          jcr->acl_data, jcr->last_fname, be.bstrerror());
501       acl_free(acl);
502
503       return false;
504    }
505    acl_free(acl);
506
507    return true;
508 }
509
510 /*
511  * OS specific functions for handling different types of acl streams.
512  */
513 #if defined(HAVE_DARWIN_OS)
514 static bool darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
515 {
516    int len;
517
518 #if defined(ACL_TYPE_EXTENDED)
519    /*
520     * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
521     * and acl_get_file (name, ACL_TYPE_DEFAULT)
522     * always return NULL / EINVAL.  There is no point in making
523     * these two useless calls.  The real ACL is retrieved through
524     * acl_get_file (name, ACL_TYPE_EXTENDED).
525     *
526     * Read access ACLs for files, dirs and links
527     */
528    if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED)) < 0)
529       return false;
530 #else
531    /*
532     * Read access ACLs for files, dirs and links
533     */
534    if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
535       return false;
536 #endif
537
538    if (len > 0) {
539       if (!send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL_T, len))
540          return false;
541    }
542
543    return true;
544 }
545
546 static bool darwin_parse_acl_stream(JCR *jcr, int stream)
547 {
548    switch (stream) {
549    case STREAM_UNIX_ACCESS_ACL:
550    case STREAM_ACL_DARWIN_ACCESS_ACL_T:
551       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
552    }
553
554    return false;
555 }
556 #elif defined(HAVE_FREEBSD_OS)
557 static bool freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
558 {
559    int len;
560
561    /*
562     * Read access ACLs for files, dirs and links
563     */
564    if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
565       return false;
566
567    if (len > 0) {
568       if (!send_acl_stream(jcr, STREAM_ACL_FREEBSD_ACCESS_ACL_T, len))
569          return false;
570    }
571
572    /*
573     * Directories can have default ACLs too
574     */
575    if (ff_pkt->type == FT_DIREND) {
576       if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
577          return false;
578
579       if (len > 0) {
580          if (!send_acl_stream(jcr, STREAM_ACL_FREEBSD_DEFAULT_ACL_T, len))
581             return false;
582       }
583    }
584
585    return true;
586 }
587
588 static bool freebsd_parse_acl_stream(JCR *jcr, int stream)
589 {
590    switch (stream) {
591    case STREAM_UNIX_ACCESS_ACL:
592    case STREAM_ACL_FREEBSD_ACCESS_ACL_T:
593       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
594    case STREAM_UNIX_DEFAULT_ACL:
595    case STREAM_ACL_FREEBSD_DEFAULT_ACL_T:
596       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
597    }
598
599    return false;
600 }
601 #elif defined(HAVE_IRIX_OS)
602 static bool irix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
603 {
604    int len;
605
606    /*
607     * Read access ACLs for files, dirs and links
608     */
609    if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
610       return false;
611
612    if (len > 0) {
613       if (!send_acl_stream(jcr, STREAM_ACL_IRIX_ACCESS_ACL_T, len))
614          return false;
615    }
616
617    /*
618     * Directories can have default ACLs too
619     */
620    if (ff_pkt->type == FT_DIREND) {
621       if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
622          return false;
623
624       if (len > 0) {
625          if (!send_acl_stream(jcr, STREAM_ACL_IRIX_DEFAULT_ACL_T, len))
626             return false;
627       }
628    }
629
630    return true;
631 }
632
633 static bool irix_parse_acl_stream(JCR *jcr, int stream)
634 {
635    switch (stream) {
636    case STREAM_UNIX_ACCESS_ACL:
637    case STREAM_ACL_IRIX_ACCESS_ACL_T:
638       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
639    case STREAM_UNIX_DEFAULT_ACL:
640    case STREAM_ACL_IRIX_DEFAULT_ACL_T:
641       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
642    }
643
644    return false;
645 }
646 #elif defined(HAVE_LINUX_OS)
647 static bool linux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
648 {
649    int len;
650
651    /*
652     * Read access ACLs for files, dirs and links
653     */
654    if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
655       return false;
656
657    if (len > 0) {
658       if (!send_acl_stream(jcr, STREAM_ACL_LINUX_ACCESS_ACL_T, len))
659          return false;
660    }
661
662    /*
663     * Directories can have default ACLs too
664     */
665    if (ff_pkt->type == FT_DIREND) {
666       if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
667          return false;
668
669       if (len > 0) {
670          if (!send_acl_stream(jcr, STREAM_ACL_LINUX_DEFAULT_ACL_T, len))
671             return false;
672       }
673    }
674
675    return true;
676 }
677
678 static bool linux_parse_acl_stream(JCR *jcr, int stream)
679 {
680    switch (stream) {
681    case STREAM_UNIX_ACCESS_ACL:
682    case STREAM_ACL_LINUX_ACCESS_ACL_T:
683       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
684    case STREAM_UNIX_DEFAULT_ACL:
685    case STREAM_ACL_LINUX_DEFAULT_ACL_T:
686       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
687    }
688
689    return false;
690 }
691 #elif defined(HAVE_OSF1_OS)
692 static bool tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
693 {
694    int len;
695
696    /*
697     * Read access ACLs for files, dirs and links
698     */
699    if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
700       return false;
701
702    if (len > 0) {
703       if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL_T, len))
704          return false;
705    }
706
707    /*
708     * Directories can have default ACLs too
709     */
710    if (ff_pkt->type == FT_DIREND) {
711       if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
712          return false;
713
714       if (len > 0) {
715          if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL_T, len))
716             return false;
717       }
718
719       /*
720        * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
721        * This is an inherited acl for all subdirs.
722        * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
723        * Section 21.5 Default ACLs 
724        */
725       if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR)) < 0)
726          return false;
727
728       if (len > 0) {
729          if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL_T, len))
730             return false;
731       }
732    }
733
734    return true;
735 }
736
737 static bool tru64_parse_acl_stream(JCR *jcr, int stream)
738 {
739    switch (stream) {
740    case STREAM_UNIX_ACCESS_ACL:
741    case STREAM_ACL_TRU64_ACCESS_ACL_T:
742       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
743    case STREAM_UNIX_DEFAULT_ACL:
744    case STREAM_ACL_TRU64_DEFAULT_ACL_T:
745       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
746    case STREAM_ACL_TRU64_DEFAULT_DIR_ACL_T:
747       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR);
748 }
749 #endif
750
751 #elif defined(HAVE_HPUX_OS)
752 #ifdef HAVE_SYS_ACL_H
753 #include <sys/acl.h>
754 #else
755 #error "configure failed to detect availability of sys/acl.h"
756 #endif
757
758 #include <acllib.h>
759
760 /*
761  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
762  * There is no need to store those acls as we already store the stat bits too.
763  */
764 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
765 {
766    int n;
767    struct acl_entry ace
768
769    for (n = 0; n < count; n++) {
770       ace = entries[n];
771
772       /*
773        * See if this acl just is the stat mode in acl form.
774        */
775       if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
776             (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
777             (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
778          return false;
779    }
780
781    return true;
782 }
783
784 /*
785  * OS specific functions for handling different types of acl streams.
786  */
787 static bool hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
788 {
789    int n, len;
790    struct acl_entry acls[NACLENTRIES];
791    char *acl_text;
792
793    if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
794       switch(errno) {
795 #if defined(BACL_ENOTSUP)
796       case BACL_ENOTSUP:
797          /*
798           * Not supported, just pretend there is nothing to see
799           */
800          pm_strcpy(jcr->acl_data, "");
801          return true;
802 #endif
803       default:
804          berrno be;
805          Jmsg2(jcr, M_ERROR, 0, _("getacl error on file \"%s\": ERR=%s\n"),
806             jcr->last_fname, be.bstrerror());
807          Dmsg2(100, "getacl error file=%s ERR=%s\n",  
808             jcr->last_fname, be.bstrerror());
809
810          pm_strcpy(jcr->acl_data, "");
811          return false;
812       }
813    }
814
815    if (n == 0) {
816       pm_strcpy(jcr->acl_data, "");
817       return true;
818    }
819
820    if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
821       if (acl_is_trivial(n, acls, ff_pkt->statp)) {
822          /*
823           * The ACLs simply reflect the (already known) standard permissions
824           * So we don't send an ACL stream to the SD.
825           */
826          pm_strcpy(jcr->acl_data, "");
827          return true;
828       }
829
830       if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
831          len = pm_strcpy(jcr->acl_data, acl_text);
832          actuallyfree(acl_text);
833
834          return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY, len);
835       }
836
837       berrno be;
838       Jmsg2(jcr, M_ERROR, 0, _("acltostr error on file \"%s\": ERR=%s\n"),
839          jcr->last_fname, be.bstrerror());
840       Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",  
841          jcr->acl_data, jcr->last_fname, be.bstrerror());
842
843       return false;
844    }
845
846    return false;
847 }
848
849 static bool hpux_parse_acl_stream(JCR *jcr, int stream)
850 {
851    int n, stat;
852    struct acl_entry acls[NACLENTRIES];
853
854    n = strtoacl(jcr->acl_data, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
855    if (n <= 0) {
856       berrno be;
857       Jmsg2(jcr, M_ERROR, 0, _("strtoacl error on file \"%s\": ERR=%s\n"),
858          jcr->last_fname, be.bstrerror());
859       Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",  
860          jcr->acl_data, jcr->last_fname, be.bstrerror());
861
862       return false;
863    }
864    if (strtoacl(jcr->acl_data, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
865       berrno be;
866       Jmsg2(jcr, M_ERROR, 0, _("strtoacl error on file \"%s\": ERR=%s\n"),
867          jcr->last_fname, be.bstrerror());
868       Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",  
869          jcr->acl_data, jcr->last_fname, be.bstrerror());
870
871       return false;
872    }
873    /*
874     * Restore the ACLs, but don't complain about links which really should
875     * not have attributes, and the file it is linked to may not yet be restored.
876     * This is only true for the old acl streams as in the new implementation we
877     * don't save acls of symlinks (which cannot have acls anyhow)
878     */
879    if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
880       berrno be;
881       Jmsg2(jcr, M_ERROR, 0, _("setacl error on file \"%s\": ERR=%s\n"),
882          jcr->last_fname, be.bstrerror());
883       Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",  
884          jcr->acl_data, jcr->last_fname, be.bstrerror());
885
886       return false;
887    }
888
889    return true;
890 }
891
892 #elif defined(HAVE_SUN_OS)
893 #ifdef HAVE_SYS_ACL_H
894 #include <sys/acl.h>
895 #else
896 #error "configure failed to detect availability of sys/acl.h"
897 #endif
898
899 #if defined(HAVE_EXTENDED_ACL)
900 /*
901  * We define some internals of the Solaris acl libs here as those
902  * are not exposed yet. Probably because they want us to see the
903  * acls as opague data. But as we need to support different platforms
904  * and versions of Solaris we need to expose some data to be able
905  * to determine the type of acl used to stuff it into the correct
906  * data stream. I know this is far from portable, but maybe the
907  * propper interface is exposed later on and we can get ride of
908  * this kludge. Newer versions of Solaris include sys/acl_impl.h
909  * which has implementation details of acls, if thats included we
910  * don't have to define it ourself.
911  */
912 #if !defined(_SYS_ACL_IMPL_H)
913 typedef enum acl_type {
914    ACLENT_T = 0,
915    ACE_T = 1
916 } acl_type_t;
917 #endif
918
919 /*
920  * Two external references to functions in the libsec library function not in current include files.
921  */
922 extern "C" {
923 int acl_type(acl_t *);
924 char *acl_strerror(int);
925 }
926
927 /*
928  * As the new libsec interface with acl_totext and acl_fromtext also handles
929  * the old format from acltotext we can use the new functions even
930  * for acls retrieved and stored in the database with older fd versions. If the
931  * new interface is not defined (Solaris 9 and older we fall back to the old code)
932  */
933 static bool solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
934 {
935    int len, flags;
936    acl_t *aclp;
937    char *acl_text;
938    bool stream_status = false;
939
940    /*
941     * Get ACL info: don't bother allocating space if there is only a trivial ACL.
942     */
943    if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
944       switch (errno) {
945 #if defined(BACL_ENOTSUP)
946       case BACL_ENOTSUP:
947          /*
948           * Not supported, just pretend there is nothing to see
949           */
950          pm_strcpy(jcr->acl_data, "");
951          return true;
952 #endif
953       default:
954          Jmsg2(jcr, M_ERROR, 0, _("acl_get error on file \"%s\": ERR=%s\n"),
955             jcr->last_fname, acl_strerror(errno));
956          Dmsg2(100, "acl_get error file=%s ERR=%s\n",  
957             jcr->last_fname, acl_strerror(errno));
958
959          return false;
960       }
961    }
962
963    if (aclp == NULL) {
964       /*
965        * The ACLs simply reflect the (already known) standard permissions
966        * So we don't send an ACL stream to the SD.
967        */
968       pm_strcpy(jcr->acl_data, "");
969       return true;
970    }
971
972 #if defined(ACL_SID_FMT)
973    /*
974     * New format flag added in newer Solaris versions.
975     */
976    flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
977 #else
978    flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
979 #endif /* ACL_SID_FMT */
980
981    if ((acl_text = acl_totext(aclp, flags)) != NULL) {
982       len = pm_strcpy(jcr->acl_data, acl_text);
983       actuallyfree(acl_text);
984
985       switch (acl_type(aclp)) {
986       case ACLENT_T:
987          stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT_T, len);
988          break;
989       case ACE_T:
990          stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE_T, len);
991          break;
992       default:
993          break;
994       }
995
996       acl_free(aclp);
997    }
998
999    return stream_status;
1000 }
1001
1002 static bool solaris_parse_acl_stream(JCR *jcr, int stream)
1003 {
1004    acl_t *aclp;
1005    int error;
1006
1007    switch (stream) {
1008    case STREAM_UNIX_ACCESS_ACL:
1009    case STREAM_ACL_SOLARIS_ACLENT_T:
1010    case STREAM_ACL_SOLARIS_ACE_T:
1011       if ((error = acl_fromtext(jcr->acl_data, &aclp)) != 0) {
1012          Jmsg2(jcr, M_ERROR, 0, _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1013             jcr->last_fname, acl_strerror(error));
1014          Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",  
1015             jcr->acl_data, jcr->last_fname, acl_strerror(error));
1016          return false;
1017       }
1018
1019       /*
1020        * Validate that the conversion gave us the correct acl type.
1021        */
1022       switch (stream) {
1023       case STREAM_ACL_SOLARIS_ACLENT_T:
1024          if (acl_type(aclp) != ACLENT_T) {
1025             Jmsg1(jcr, M_ERROR, 0, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1026                jcr->last_fname);
1027             return false;
1028          }
1029       case STREAM_ACL_SOLARIS_ACE_T:
1030          if (acl_type(aclp) != ACE_T) {
1031             Jmsg1(jcr, M_ERROR, 0, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1032                jcr->last_fname);
1033             return false;
1034          }
1035       default:
1036          /*
1037           * Stream id which doesn't describe the type of acl which is encoded.
1038           */
1039          break;
1040       }
1041
1042       /*
1043        * Restore the ACLs, but don't complain about links which really should
1044        * not have attributes, and the file it is linked to may not yet be restored.
1045        * This is only true for the old acl streams as in the new implementation we
1046        * don't save acls of symlinks (which cannot have acls anyhow)
1047        */
1048       if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1049          Jmsg2(jcr, M_ERROR, 0, _("acl_set error on file \"%s\": ERR=%s\n"),
1050             jcr->last_fname, acl_strerror(error));
1051          Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",  
1052             jcr->acl_data, jcr->last_fname, acl_strerror(error));
1053
1054          acl_free(aclp);
1055          return false;
1056       }
1057
1058       acl_free(aclp);
1059       return true;
1060    default:
1061       return false;
1062    } /* end switch (stream) */
1063 }
1064
1065 #else /* HAVE_EXTENDED_ACL */
1066
1067 /*
1068  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1069  * There is no need to store those acls as we already store the stat bits too.
1070  */
1071 static bool acl_is_trivial(int count, aclent_t *entries)
1072 {
1073    int n;
1074    aclent_t *ace;
1075
1076    for (n = 0; n < count; n++) {
1077       ace = &entries[n];
1078
1079       if (!(ace->a_type == USER_OBJ ||
1080             ace->a_type == GROUP_OBJ ||
1081             ace->a_type == OTHER_OBJ ||
1082             ace->a_type == CLASS_OBJ))
1083         return false;
1084    }
1085
1086    return true;
1087 }
1088
1089 /*
1090  * OS specific functions for handling different types of acl streams.
1091  */
1092 static bool solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt);
1093 {
1094    int n, len;
1095    aclent_t *acls;
1096    char *acl_text;
1097
1098    n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1099    if (n < MIN_ACL_ENTRIES) {
1100       return false;
1101
1102    acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1103    if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1104       if (acl_is_trivial(n, acls)) {
1105          /*
1106           * The ACLs simply reflect the (already known) standard permissions
1107           * So we don't send an ACL stream to the SD.
1108           */
1109          free(acls);
1110          pm_strcpy(jcr->acl_data, "");
1111          return true;
1112       }
1113
1114       if ((acl_text = acltotext(acls, n)) != NULL) {
1115          len = pm_strcpy(jcr->acl_data, acl_text);
1116          actuallyfree(acl_text);
1117          free(acls);
1118
1119          return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT_T, len);
1120       }
1121
1122       berrno be;
1123       Jmsg2(jcr, M_ERROR, 0, _("acltotext error on file \"%s\": ERR=%s\n"),
1124          jcr->last_fname, be.bstrerror());
1125       Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",  
1126          jcr->acl_data, jcr->last_fname, be.bstrerror());
1127    }
1128
1129    free(acls);
1130    return false;
1131 }
1132
1133 static bool solaris_parse_acl_stream(JCR *jcr, int stream)
1134 {
1135    int n;
1136    aclent_t *acls;
1137
1138    acls = aclfromtext(jcr->acl_data, &n);
1139    if (!acls) {
1140       berrno be;
1141       Jmsg2(jcr, M_ERROR, 0, _("aclfromtext error on file \"%s\": ERR=%s\n"),
1142          jcr->last_fname, be.bstrerror());
1143       Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",  
1144          jcr->acl_data, jcr->last_fname, be.bstrerror());
1145
1146       return false;
1147    }
1148
1149    /*
1150     * Restore the ACLs, but don't complain about links which really should
1151     * not have attributes, and the file it is linked to may not yet be restored.
1152     */
1153    if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
1154       berrno be;
1155       Jmsg2(jcr, M_ERROR, 0, _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
1156          jcr->last_fname, be.bstrerror());
1157       Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",  
1158          jcr->acl_data, jcr->last_fname, be.bstrerror());
1159       actuallyfree(acls);
1160
1161       return false;
1162    }
1163
1164    actuallyfree(acls);
1165    return true;
1166 }
1167
1168 #endif /* HAVE_EXTENDED_ACL */
1169 #endif /* HAVE_SUN_OS */
1170
1171 /*
1172  * Entry points when compiled with support for ACLs on a supported platform.
1173  */
1174
1175 /*
1176  * Read and send an ACL for the last encountered file.
1177  */
1178 bool build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1179 {
1180    /*
1181     * Call the appropriate function, the ifdefs make sure the proper code is compiled.
1182     */
1183 #if defined(HAVE_AIX_OS)
1184    return aix_build_acl_streams(jcr, ff_pkt);
1185 #elif defined(HAVE_DARWIN_OS)
1186    return darwin_build_acl_streams(jcr, ff_pkt);
1187 #elif defined(HAVE_FREEBSD_OS)
1188    return freebsd_build_acl_streams(jcr, ff_pkt);
1189 #elif defined(HAVE_HPUX_OS)
1190    return hpux_build_acl_streams(jcr, ff_pkt);
1191 #elif defined(HAVE_IRIX_OS)
1192    return irix_build_acl_streams(jcr, ff_pkt);
1193 #elif defined(HAVE_LINUX_OS)
1194    return linux_build_acl_streams(jcr, ff_pkt);
1195 #elif defined(HAVE_OSF1_OS)
1196    return tru64_build_acl_streams(jcr, ff_pkt);
1197 #elif defined(HAVE_SUN_OS)
1198    return solaris_build_acl_streams(jcr, ff_pkt);
1199 #endif
1200 }
1201
1202 bool parse_acl_stream(JCR *jcr, int stream)
1203 {
1204    /*
1205     * Based on the stream being passed in dispatch to the right function
1206     * for parsing and restoring a specific acl. The platform determines
1207     * which streams are recognized and parsed and which are handled by
1208     * the default case and ignored. The old STREAM_UNIX_ACCESS_ACL and
1209     * STREAM_UNIX_DEFAULT_ACL is handled as a legacy stream by each function.
1210     * As only one of the platform defines is true per compile we never end
1211     * up with duplicate switch values.
1212     */
1213    switch (stream) {
1214 #if defined(HAVE_AIX_OS)
1215    case STREAM_UNIX_ACCESS_ACL:
1216    case STREAM_UNIX_DEFAULT_ACL:
1217    case STREAM_ACL_AIX_TEXT:
1218       return aix_parse_acl_stream(jcr, stream);
1219 #elif defined(HAVE_DARWIN_OS)
1220    case STREAM_UNIX_ACCESS_ACL:
1221    case STREAM_ACL_DARWIN_ACCESS_ACL_T:
1222       return darwin_parse_acl_stream(jcr, stream);
1223 #elif defined(HAVE_FREEBSD_OS)
1224    case STREAM_UNIX_ACCESS_ACL:
1225    case STREAM_UNIX_DEFAULT_ACL:
1226    case STREAM_ACL_FREEBSD_DEFAULT_ACL_T:
1227    case STREAM_ACL_FREEBSD_ACCESS_ACL_T:
1228       return freebsd_parse_acl_stream(jcr, stream);
1229 #elif defined(HAVE_HPUX_OS)
1230    case STREAM_UNIX_ACCESS_ACL:
1231    case STREAM_ACL_HPUX_ACL_ENTRY:
1232       return hpux_parse_acl_stream(jcr, stream);
1233 #elif defined(HAVE_IRIX_OS)
1234    case STREAM_UNIX_ACCESS_ACL:
1235    case STREAM_UNIX_DEFAULT_ACL:
1236    case STREAM_ACL_IRIX_DEFAULT_ACL_T:
1237    case STREAM_ACL_IRIX_ACCESS_ACL_T:
1238       return irix_parse_acl_stream(jcr, stream);
1239 #elif defined(HAVE_LINUX_OS)
1240    case STREAM_UNIX_ACCESS_ACL:
1241    case STREAM_UNIX_DEFAULT_ACL:
1242    case STREAM_ACL_LINUX_DEFAULT_ACL_T:
1243    case STREAM_ACL_LINUX_ACCESS_ACL_T:
1244       return linux_parse_acl_stream(jcr, stream);
1245 #elif defined(HAVE_OSF1_OS)
1246    case STREAM_UNIX_ACCESS_ACL:
1247    case STREAM_UNIX_DEFAULT_ACL:
1248    case STREAM_ACL_TRU64_DEFAULT_ACL_T:
1249    case STREAM_ACL_TRU64_ACCESS_ACL_T:
1250    case STREAM_ACL_TRU64_DEFAULT_DIR_ACL_T:
1251       return tru64_parse_acl_stream(jcr, stream);
1252 #elif defined(HAVE_SUN_OS)
1253    case STREAM_UNIX_ACCESS_ACL:
1254    case STREAM_ACL_SOLARIS_ACLENT_T:
1255 #if defined(HAVE_EXTENDED_ACL)
1256    case STREAM_ACL_SOLARIS_ACE_T:
1257 #endif
1258       return solaris_parse_acl_stream(jcr, stream);
1259 #endif
1260    default:
1261       /*
1262        * Issue a warning and discard the message. But pretend the restore was ok.
1263        */
1264       Qmsg2(jcr, M_WARNING, 0,
1265          _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
1266          jcr->last_fname, stream);
1267       return true;
1268    } /* end switch (stream) */
1269 }
1270 #endif