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