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