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