]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/acl.c
update configure
[bacula/bacula] / bacula / src / filed / acl.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2004-2010 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 three of the GNU Affero 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 Affero General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
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  * Currently we support the following OSes:
32  *   - AIX (pre-5.3 and post 5.3 acls, acl_get and aclx_get interface)
33  *   - Darwin
34  *   - FreeBSD (POSIX and NFSv4/ZFS acls)
35  *   - HPUX
36  *   - IRIX
37  *   - Linux
38  *   - Solaris (POSIX and NFSv4/ZFS acls)
39  *   - Tru64
40  *
41  * We handle two different types of ACLs: access and default ACLS.
42  * On most systems that support default ACLs they only apply to directories.
43  *
44  * On some systems (eg. linux and FreeBSD) we must obtain the two ACLs
45  * independently, while others (eg. Solaris) provide both in one call.
46  *
47  * The Filed saves ACLs in their native format and uses different streams
48  * for all different platforms. Currently we only allow ACLs to be restored
49  * which were saved in the native format of the platform they are extracted
50  * on. Later on we might add conversion functions for mapping from one
51  * platform to an other or allow restores of systems that use the same
52  * native format.
53  *
54  * Its also interesting to see what the exact format of acl text is on
55  * certain platforms and if they use they same encoding we might allow
56  * different platform streams to be decoded on an other similar platform.
57  *
58  *   Original written by Preben 'Peppe' Guldberg, December MMIV
59  *   Major rewrite by Marco van Wieringen, November MMVIII
60  */
61   
62 #include "bacula.h"
63 #include "filed.h"
64   
65 #if !defined(HAVE_ACL)
66 /**
67  * Entry points when compiled without support for ACLs or on an unsupported platform.
68  */
69 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
70 {
71    return bacl_exit_fatal;
72 }
73
74 bacl_exit_code parse_acl_streams(JCR *jcr, int stream)
75 {
76    return bacl_exit_fatal;
77 }
78 #else
79 /**
80  * Send an ACL stream to the SD.
81  */
82 static bacl_exit_code send_acl_stream(JCR *jcr, int stream)
83 {
84    BSOCK *sd = jcr->store_bsock;
85    POOLMEM *msgsave;
86 #ifdef FD_NO_SEND_TEST
87    return bacl_exit_ok;
88 #endif
89
90    /**
91     * Sanity check
92     */
93    if (jcr->acl_data->content_length <= 0) {
94       return bacl_exit_ok;
95    }
96
97    /**
98     * Send header
99     */
100    if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
101       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
102             sd->bstrerror());
103       return bacl_exit_fatal;
104    }
105
106    /**
107     * Send the buffer to the storage deamon
108     */
109    Dmsg1(400, "Backing up ACL <%s>\n", jcr->acl_data->content);
110    msgsave = sd->msg;
111    sd->msg = jcr->acl_data->content;
112    sd->msglen = jcr->acl_data->content_length + 1;
113    if (!sd->send()) {
114       sd->msg = msgsave;
115       sd->msglen = 0;
116       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
117             sd->bstrerror());
118       return bacl_exit_fatal;
119    }
120
121    jcr->JobBytes += sd->msglen;
122    sd->msg = msgsave;
123    if (!sd->signal(BNET_EOD)) {
124       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
125             sd->bstrerror());
126       return bacl_exit_fatal;
127    }
128
129    Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
130    return bacl_exit_ok;
131 }
132
133 /**
134  * First the native ACLs.
135  */
136 #if defined(HAVE_ACL)
137 #if defined(HAVE_AIX_OS)
138
139 #if defined(HAVE_EXTENDED_ACL)
140
141 #include <sys/access.h>
142 #include <sys/acl.h>
143
144 static bool acl_is_trivial(struct acl *acl)
145 {
146    return (acl_last(acl) != acl->acl_ext ? false : true);
147 }
148
149 static bool acl_nfs4_is_trivial(nfs4_acl_int_t *acl)
150 {
151    return (acl->aclEntryN > 0 ? false : true);
152 }
153
154 /**
155  * Define the supported ACL streams for this OS
156  */
157 static int os_access_acl_streams[3] = { STREAM_ACL_AIX_TEXT, STREAM_ACL_AIX_AIXC, STREAM_ACL_AIX_NFS4 };
158 static int os_default_acl_streams[1] = { -1 };
159
160 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
161 {
162    berrno be;
163    mode_t mode;
164    acl_type_t type;
165    size_t aclsize, acltxtsize;
166    bacl_exit_code retval = bacl_exit_error;
167    POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
168
169    /**
170     * First see how big the buffers should be.
171     */
172    type.u64 = ACL_ANY;
173    if (aclx_get(jcr->last_fname, GET_ACLINFO_ONLY, &type, NULL, &aclsize, NULL) < 0) {
174       switch (errno) {
175       case ENOENT:
176          retval = bacl_exit_ok;
177          goto bail_out;
178       default:
179          Mmsg2(jcr->errmsg, _("aclx_get error on file \"%s\": ERR=%s\n"),
180                jcr->last_fname, be.bstrerror());
181          Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
182                jcr->last_fname, be.bstrerror());
183          goto bail_out;
184       }
185    }
186
187    /**
188     * Make sure the buffers are big enough.
189     */
190    aclbuf = check_pool_memory_size(aclbuf, aclsize + 1);
191
192    /**
193     * Retrieve the ACL info.
194     */
195    if (aclx_get(jcr->last_fname, 0, &type, aclbuf, &aclsize, &mode) < 0) {
196       switch (errno) {
197       case ENOENT:
198          retval = bacl_exit_ok;
199          goto bail_out;
200       default:
201          Mmsg2(jcr->errmsg, _("aclx_get error on file \"%s\": ERR=%s\n"),
202                jcr->last_fname, be.bstrerror());
203          Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
204                jcr->last_fname, be.bstrerror());
205          goto bail_out;
206       }
207    }
208
209    /**
210     * See if the acl is non trivial.
211     */
212    switch (type.u64) {
213    case ACL_AIXC:
214       if (acl_is_trivial((struct acl *)aclbuf)) {
215          retval = bacl_exit_ok;
216          goto bail_out;
217       }
218       break;
219    case ACL_NFS4:
220       if (acl_nfs4_is_trivial((nfs4_acl_int_t *)aclbuf)) {
221          retval = bacl_exit_ok;
222          goto bail_out;
223       }
224       break;
225    default:
226       Mmsg2(jcr->errmsg, _("Unknown acl type encountered on file \"%s\": %ld\n"),
227             jcr->last_fname, type.u64);
228       Dmsg2(100, "Unknown acl type encountered on file \"%s\": %ld\n",
229             jcr->last_fname, type.u64);
230       goto bail_out;
231    }
232
233    /**
234     * We have a non-trivial acl lets convert it into some ASCII form.
235     */
236    acltxtsize = sizeof_pool_memory(jcr->acl_data->content);
237    if (aclx_printStr(jcr->acl_data->content, &acltxtsize, aclbuf,
238                      aclsize, type, jcr->last_fname, 0) < 0) {
239       switch (errno) {
240       case ENOSPC:
241          /**
242           * Our buffer is not big enough, acltxtsize should be updated with the value
243           * the aclx_printStr really need. So we increase the buffer and try again.
244           */
245          jcr->acl_data->content = check_pool_memory_size(jcr->acl_data->content, acltxtsize + 1);
246          if (aclx_printStr(jcr->acl_data->content, &acltxtsize, aclbuf,
247                            aclsize, type, jcr->last_fname, 0) < 0) {
248             Mmsg1(jcr->errmsg, _("Failed to convert acl into text on file \"%s\"\n"),
249                   jcr->last_fname);
250             Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
251                   jcr->last_fname, type.u64);
252             goto bail_out;
253          }
254          break;
255       default:
256          Mmsg1(jcr->errmsg, _("Failed to convert acl into text on file \"%s\"\n"),
257                jcr->last_fname);
258          Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
259                jcr->last_fname, type.u64);
260          goto bail_out;
261       }
262    }
263
264    jcr->acl_data->content_length = strlen(jcr->acl_data->content) + 1;
265    switch (type.u64) {
266    case ACL_AIXC:
267       retval = send_acl_stream(jcr, STREAM_ACL_AIX_AIXC);
268    case ACL_NFS4:
269       retval = send_acl_stream(jcr, STREAM_ACL_AIX_NFS4);
270    }
271
272 bail_out:
273    free_pool_memory(aclbuf);
274
275    return retval;
276 }
277
278 static bacl_exit_code aix_parse_acl_streams(JCR *jcr, int stream)
279 {
280    int cnt;
281    berrno be;
282    acl_type_t type;
283    size_t aclsize;
284    bacl_exit_code retval = bacl_exit_error;
285    POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
286
287    switch (stream) {
288    case STREAM_ACL_AIX_TEXT:
289       /**
290        * Handle the old stream using the old system call for now.
291        */
292       if (acl_put(jcr->last_fname, jcr->acl_data->content, 0) != 0) {
293          retval = bacl_exit_error;
294          goto bail_out;
295       }
296       retval = bacl_exit_ok;
297       goto bail_out;
298    case STREAM_ACL_AIX_AIXC:
299       type.u64 = ACL_AIXC;
300       break;
301    case STREAM_ACL_AIX_NFS4:
302       type.u64 = ACL_NFS4;
303       break;
304    default:
305       goto bail_out;
306    } /* end switch (stream) */
307
308    /**
309     * Set the acl buffer to an initial size. For now we set it
310     * to the same size as the ASCII representation.
311     */
312    aclbuf = check_pool_memory_size(aclbuf, jcr->acl_data->content_length);
313    aclsize = jcr->acl_data->content_length;
314    if (aclx_scanStr(jcr->acl_data->content, aclbuf, &aclsize, type) < 0) {
315       switch (errno) {
316       case ENOSPC:
317          /**
318           * The buffer isn't big enough. The man page doesn't say that aclsize
319           * is updated to the needed size as what is done with aclx_printStr.
320           * So for now we try to increase the buffer a maximum of 3 times
321           * and retry the conversion.
322           */
323          for (cnt = 0; cnt < 3; cnt++) {
324             aclsize = 2 * aclsize;
325             aclbuf = check_pool_memory_size(aclbuf, aclsize);
326
327             if (aclx_scanStr(jcr->acl_data->content, aclbuf, &aclsize, type) == 0) {
328                break;
329             }
330
331             /**
332              * See why we failed this time, ENOSPC retry if max retries not met,
333              * otherwise abort.
334              */
335             switch (errno) {
336             case ENOSPC:
337                if (cnt < 3) {
338                   continue;
339                }
340                /* FALL THROUGH */
341             default:
342                Mmsg2(jcr->errmsg, _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
343                      jcr->last_fname, be.bstrerror());
344                Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
345                      jcr->last_fname, be.bstrerror());
346                goto bail_out;
347             }
348          }
349          break;
350       default:
351          Mmsg2(jcr->errmsg, _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
352                jcr->last_fname, be.bstrerror());
353          Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
354                jcr->last_fname, be.bstrerror());
355       }
356    }
357
358    if (aclx_put(jcr->last_fname, SET_ACL, type, aclbuf, aclsize, 0) < 0) {
359       switch (errno) {
360       case ENOENT:
361          retval = bacl_exit_ok;
362          goto bail_out;
363       default:
364          Mmsg2(jcr->errmsg, _("aclx_put error on file \"%s\": ERR=%s\n"),
365                jcr->last_fname, be.bstrerror());
366          Dmsg2(100, "aclx_put error file=%s ERR=%s\n",
367                jcr->last_fname, be.bstrerror());
368          goto bail_out;
369       }
370    }
371
372    retval = bacl_exit_ok;
373
374 bail_out:
375    free_pool_memory(aclbuf);
376
377    return retval;
378 }
379
380 #else /* HAVE_EXTENDED_ACL */
381
382 #include <sys/access.h>
383
384 /**
385  * Define the supported ACL streams for this OS
386  */
387 static int os_access_acl_streams[1] = { STREAM_ACL_AIX_TEXT };
388 static int os_default_acl_streams[1] = { -1 };
389
390 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
391 {
392    char *acl_text;
393
394    if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
395       jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
396       actuallyfree(acl_text);
397       return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT);
398    }
399    return bacl_exit_error;
400 }
401
402 static bacl_exit_code aix_parse_acl_streams(JCR *jcr, int stream)
403 {
404    if (acl_put(jcr->last_fname, jcr->acl_data->content, 0) != 0) {
405       return bacl_exit_error;
406    }
407    return bacl_exit_ok;
408 }
409 #endif /* HAVE_EXTENDED_ACL */
410
411 /**
412  * For this OS setup the build and parse function pointer to the OS specific functions.
413  */
414 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = aix_build_acl_streams;
415 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = aix_parse_acl_streams;
416
417 #elif defined(HAVE_DARWIN_OS) || \
418       defined(HAVE_FREEBSD_OS) || \
419       defined(HAVE_IRIX_OS) || \
420       defined(HAVE_OSF1_OS) || \
421       defined(HAVE_LINUX_OS)
422
423 #include <sys/types.h>
424
425 #ifdef HAVE_SYS_ACL_H
426 #include <sys/acl.h>
427 #else
428 #error "configure failed to detect availability of sys/acl.h"
429 #endif
430
431 /**
432  * On IRIX we can get shortened ACLs
433  */
434 #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
435 #define acl_to_text(acl,len)     acl_to_short_text((acl), (len))
436 #endif
437
438 /**
439  * On Linux we can get numeric and/or shorted ACLs
440  */
441 #if defined(HAVE_LINUX_OS)
442 #if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
443 #define BACL_ALTERNATE_TEXT            (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
444 #elif defined(BACL_WANT_SHORT_ACLS)
445 #define BACL_ALTERNATE_TEXT            TEXT_ABBREVIATE
446 #elif defined(BACL_WANT_NUMERIC_IDS)
447 #define BACL_ALTERNATE_TEXT            TEXT_NUMERIC_IDS
448 #endif
449 #ifdef BACL_ALTERNATE_TEXT
450 #include <acl/libacl.h>
451 #define acl_to_text(acl,len)     (acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
452 #endif
453 #endif
454
455 /**
456  * On FreeBSD we can get numeric ACLs
457  */
458 #if defined(HAVE_FREEBSD_OS)
459 #if defined(BACL_WANT_NUMERIC_IDS)
460 #define BACL_ALTERNATE_TEXT            ACL_TEXT_NUMERIC_IDS
461 #endif
462 #ifdef BACL_ALTERNATE_TEXT
463 #define acl_to_text(acl,len)     (acl_to_text_np((acl), (len), BACL_ALTERNATE_TEXT))
464 #endif
465 #endif
466
467 /**
468  * Some generic functions used by multiple OSes.
469  */
470 static acl_type_t bac_to_os_acltype(bacl_type acltype)
471 {
472    acl_type_t ostype;
473
474    switch (acltype) {
475    case BACL_TYPE_ACCESS:
476       ostype = ACL_TYPE_ACCESS;
477       break;
478    case BACL_TYPE_DEFAULT:
479       ostype = ACL_TYPE_DEFAULT;
480       break;
481 #ifdef HAVE_ACL_TYPE_NFS4
482       /**
483        * FreeBSD has an additional acl type named ACL_TYPE_NFS4.
484        */
485    case BACL_TYPE_NFS4:
486       ostype = ACL_TYPE_NFS4;
487       break;
488 #endif
489 #ifdef HAVE_ACL_TYPE_DEFAULT_DIR
490    case BACL_TYPE_DEFAULT_DIR:
491       /**
492        * TRU64 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
493        */
494       ostype = ACL_TYPE_DEFAULT_DIR;
495       break;
496 #endif
497 #ifdef HAVE_ACL_TYPE_EXTENDED
498    case BACL_TYPE_EXTENDED:
499       /**
500        * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
501        */
502       ostype = ACL_TYPE_EXTENDED;
503       break;
504 #endif
505    default:
506       /**
507        * This should never happen, as the per OS version function only tries acl
508        * types supported on a certain platform.
509        */
510       ostype = (acl_type_t)ACL_TYPE_NONE;
511       break;
512    }
513    return ostype;
514 }
515
516 static int acl_count_entries(acl_t acl)
517 {
518    int count = 0;
519 #if defined(HAVE_FREEBSD_OS) || \
520     defined(HAVE_LINUX_OS)
521    acl_entry_t ace;
522    int entry_available;
523
524    entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
525    while (entry_available == 1) {
526       count++;
527       entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
528    }
529 #elif defined(HAVE_IRIX_OS)
530    count = acl->acl_cnt;
531 #elif defined(HAVE_OSF1_OS)
532    count = acl->acl_num;
533 #elif defined(HAVE_DARWIN_OS)
534    acl_entry_t ace;
535    int entry_available;
536
537    entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
538    while (entry_available == 0) {
539       count++;
540       entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
541    }
542 #endif
543    return count;
544 }
545
546 #if !defined(HAVE_DARWIN_OS)
547 /**
548  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
549  * There is no need to store those acls as we already store the stat bits too.
550  */
551 static bool acl_is_trivial(acl_t acl)
552 {
553   /**
554    * acl is trivial if it has only the following entries:
555    * "user::",
556    * "group::",
557    * "other::"
558    */
559    acl_entry_t ace;
560    acl_tag_t tag;
561 #if defined(HAVE_FREEBSD_OS) || \
562     defined(HAVE_LINUX_OS)
563    int entry_available;
564
565    entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
566    while (entry_available == 1) {
567       /**
568        * Get the tag type of this acl entry.
569        * If we fail to get the tagtype we call the acl non-trivial.
570        */
571       if (acl_get_tag_type(ace, &tag) < 0)
572          return true;
573       /**
574        * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
575        */
576       if (tag != ACL_USER_OBJ &&
577           tag != ACL_GROUP_OBJ &&
578           tag != ACL_OTHER)
579          return false;
580       entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
581    }
582    return true;
583 #elif defined(HAVE_IRIX_OS)
584    int n;
585
586    for (n = 0; n < acl->acl_cnt; n++) {
587       ace = &acl->acl_entry[n];
588       tag = ace->ae_tag;
589
590       /**
591        * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
592        */
593       if (tag != ACL_USER_OBJ &&
594           tag != ACL_GROUP_OBJ &&
595           tag != ACL_OTHER_OBJ)
596          return false;
597    }
598    return true;
599 #elif defined(HAVE_OSF1_OS)
600    int count;
601
602    ace = acl->acl_first;
603    count = acl->acl_num;
604
605    while (count > 0) {
606       tag = ace->entry->acl_type;
607       /**
608        * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
609        */
610       if (tag != ACL_USER_OBJ &&
611           tag != ACL_GROUP_OBJ &&
612           tag != ACL_OTHER)
613          return false;
614       /**
615        * On Tru64, perm can also contain non-standard bits such as
616        * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
617        */
618       if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
619          return false;
620       ace = ace->next;
621       count--;
622    }
623    return true;
624 #endif
625 }
626 #endif
627
628 /**
629  * Generic wrapper around acl_get_file call.
630  */
631 static bacl_exit_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
632 {
633    acl_t acl;
634    acl_type_t ostype;
635    char *acl_text;
636    berrno be;
637    bacl_exit_code retval = bacl_exit_ok;
638
639    ostype = bac_to_os_acltype(acltype);
640    acl = acl_get_file(jcr->last_fname, ostype);
641    if (acl) {
642       /**
643        * From observation, IRIX's acl_get_file() seems to return a
644        * non-NULL acl with a count field of -1 when a file has no ACL
645        * defined, while IRIX's acl_to_text() returns NULL when presented
646        * with such an ACL. 
647        *
648        * For all other implmentations we check if there are more then
649        * zero entries in the acl returned.
650        */
651       if (acl_count_entries(acl) <= 0) {
652          goto bail_out;
653       }
654
655       /**
656        * Make sure this is not just a trivial ACL.
657        */
658 #if !defined(HAVE_DARWIN_OS)
659       if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
660          /**
661           * The ACLs simply reflect the (already known) standard permissions
662           * So we don't send an ACL stream to the SD.
663           */
664          goto bail_out;
665       }
666 #endif
667 #if defined(HAVE_FREEBSD_OS) && defined(_PC_ACL_NFS4)
668       if (acltype == BACL_TYPE_NFS4) {
669          int trivial;
670          if (acl_is_trivial_np(acl, &trivial) == 0) {
671             if (trivial == 1) {
672                /**
673                 * The ACLs simply reflect the (already known) standard permissions
674                 * So we don't send an ACL stream to the SD.
675                 */
676                goto bail_out;
677             }
678          }
679       }
680 #endif
681
682       /**
683        * Convert the internal acl representation into a text representation.
684        */
685       if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
686          jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
687          acl_free(acl);
688          acl_free(acl_text);
689          return bacl_exit_ok;
690       }
691
692       Mmsg2(jcr->errmsg, _("acl_to_text error on file \"%s\": ERR=%s\n"),
693             jcr->last_fname, be.bstrerror());
694       Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",  
695             jcr->last_fname, be.bstrerror());
696
697       retval = bacl_exit_error;
698       goto bail_out;
699    } else {
700       /**
701        * Handle errors gracefully.
702        */
703       switch (errno) {
704 #if defined(BACL_ENOTSUP)
705       case BACL_ENOTSUP:
706          /**
707           * If the filesystem reports it doesn't support ACLs we clear the
708           * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
709           * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
710           * when we change from one filesystem to an other.
711           */
712          jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
713          goto bail_out;
714 #endif
715       case ENOENT:
716          goto bail_out;
717       default:
718          /* Some real error */
719          Mmsg2(jcr->errmsg, _("acl_get_file error on file \"%s\": ERR=%s\n"),
720                jcr->last_fname, be.bstrerror());
721          Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",  
722                jcr->last_fname, be.bstrerror());
723
724          retval = bacl_exit_error;
725          goto bail_out;
726       }
727    }
728
729 bail_out:
730    if (acl) {
731       acl_free(acl);
732    }
733    pm_strcpy(jcr->acl_data->content, "");
734    jcr->acl_data->content_length = 0;
735    return retval;
736 }
737
738 /**
739  * Generic wrapper around acl_set_file call.
740  */
741 static bacl_exit_code generic_set_acl_on_os(JCR *jcr, bacl_type acltype)
742 {
743    acl_t acl;
744    acl_type_t ostype;
745    berrno be;
746
747    /**
748     * If we get empty default ACLs, clear ACLs now
749     */
750    ostype = bac_to_os_acltype(acltype);
751    if (ostype == ACL_TYPE_DEFAULT && strlen(jcr->acl_data->content) == 0) {
752       if (acl_delete_def_file(jcr->last_fname) == 0) {
753          return bacl_exit_ok;
754       }
755       switch (errno) {
756       case ENOENT:
757          return bacl_exit_ok;
758       default:
759          Mmsg2(jcr->errmsg, _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
760                jcr->last_fname, be.bstrerror());
761          return bacl_exit_error;
762       }
763    }
764
765    acl = acl_from_text(jcr->acl_data->content);
766    if (acl == NULL) {
767       Mmsg2(jcr->errmsg, _("acl_from_text error on file \"%s\": ERR=%s\n"),
768             jcr->last_fname, be.bstrerror());
769       Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",  
770          jcr->acl_data->content, jcr->last_fname, be.bstrerror());
771       return bacl_exit_error;
772    }
773
774 #ifndef HAVE_FREEBSD_OS
775    /**
776     * FreeBSD always fails acl_valid() - at least on valid input...
777     * As it does the right thing, given valid input, just ignore acl_valid().
778     */
779    if (acl_valid(acl) != 0) {
780       Mmsg2(jcr->errmsg, _("acl_valid error on file \"%s\": ERR=%s\n"),
781             jcr->last_fname, be.bstrerror());
782       Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",  
783          jcr->acl_data->content, jcr->last_fname, be.bstrerror());
784       acl_free(acl);
785       return bacl_exit_error;
786    }
787 #endif
788
789    /**
790     * Restore the ACLs, but don't complain about links which really should
791     * not have attributes, and the file it is linked to may not yet be restored.
792     * This is only true for the old acl streams as in the new implementation we
793     * don't save acls of symlinks (which cannot have acls anyhow)
794     */
795    if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
796       switch (errno) {
797       case ENOENT:
798          acl_free(acl);
799          return bacl_exit_ok;
800       default:
801          Mmsg2(jcr->errmsg, _("acl_set_file error on file \"%s\": ERR=%s\n"),
802                jcr->last_fname, be.bstrerror());
803          Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
804                jcr->acl_data->content, jcr->last_fname, be.bstrerror());
805          acl_free(acl);
806          return bacl_exit_error;
807       }
808    }
809    acl_free(acl);
810    return bacl_exit_ok;
811 }
812
813 /**
814  * OS specific functions for handling different types of acl streams.
815  */
816 #if defined(HAVE_DARWIN_OS)
817 /**
818  * Define the supported ACL streams for this OS
819  */
820 static int os_access_acl_streams[1] = { STREAM_ACL_DARWIN_ACCESS_ACL };
821 static int os_default_acl_streams[1] = { -1 };
822
823 static bacl_exit_code darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
824 {
825 #if defined(HAVE_ACL_TYPE_EXTENDED)
826    /**
827     * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
828     * and acl_get_file (name, ACL_TYPE_DEFAULT)
829     * always return NULL / EINVAL.  There is no point in making
830     * these two useless calls.  The real ACL is retrieved through
831     * acl_get_file (name, ACL_TYPE_EXTENDED).
832     *
833     * Read access ACLs for files, dirs and links
834     */
835    if (generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED) == bacl_exit_fatal)
836       return bacl_exit_fatal;
837 #else
838    /**
839     * Read access ACLs for files, dirs and links
840     */
841    if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
842       return bacl_exit_fatal;
843 #endif
844
845    if (jcr->acl_data->content_length > 0) {
846       return send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL);
847    }
848    return bacl_exit_ok;
849 }
850
851 static bacl_exit_code darwin_parse_acl_streams(JCR *jcr, int stream)
852 {
853 #if defined(HAVE_ACL_TYPE_EXTENDED)
854       return generic_set_acl_on_os(jcr, BACL_TYPE_EXTENDED);
855 #else
856       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
857 #endif
858 }
859
860 /**
861  * For this OS setup the build and parse function pointer to the OS specific functions.
862  */
863 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = darwin_build_acl_streams;
864 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = darwin_parse_acl_streams;
865
866 #elif defined(HAVE_FREEBSD_OS)
867 /**
868  * Define the supported ACL streams for these OSes
869  */
870 static int os_access_acl_streams[2] = { STREAM_ACL_FREEBSD_ACCESS_ACL, STREAM_ACL_FREEBSD_NFS4_ACL };
871 static int os_default_acl_streams[1] = { STREAM_ACL_FREEBSD_DEFAULT_ACL };
872
873 static bacl_exit_code freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
874 {
875    int acl_enabled = 0;
876    bacl_type acltype = BACL_TYPE_NONE;
877    berrno be;
878
879 #if defined(_PC_ACL_NFS4)
880    /**
881     * See if filesystem supports NFS4 acls.
882     */
883    acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
884    switch (acl_enabled) {
885    case -1:
886       switch (errno) {
887       case ENOENT:
888          return bacl_exit_ok;
889       default:
890          Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
891                jcr->last_fname, be.bstrerror());
892          Dmsg2(100, "pathconf error file=%s ERR=%s\n",
893                jcr->last_fname, be.bstrerror());
894          return bacl_exit_error;
895       }
896    case 0:
897       break;
898    default:
899       acltype = BACL_TYPE_NFS4;
900       break;
901    }
902 #endif
903
904    if (acl_enabled == 0) {
905       /**
906        * See if filesystem supports POSIX acls.
907        */
908       acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
909       switch (acl_enabled) {
910       case -1:
911          switch (errno) {
912          case ENOENT:
913             return bacl_exit_ok;
914          default:
915             Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
916                   jcr->last_fname, be.bstrerror());
917             Dmsg2(100, "pathconf error file=%s ERR=%s\n",
918                   jcr->last_fname, be.bstrerror());
919             return bacl_exit_error;
920          }
921       case 0:
922          break;
923       default:
924          acltype = BACL_TYPE_ACCESS;
925          break;
926       }
927    }
928
929    /**
930     * If the filesystem reports it doesn't support ACLs we clear the
931     * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
932     * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
933     * when we change from one filesystem to an other.
934     */
935    if (acl_enabled == 0) {
936       jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
937       pm_strcpy(jcr->acl_data->content, "");
938       jcr->acl_data->content_length = 0;
939       return bacl_exit_ok;
940    }
941
942    /**
943     * Based on the supported ACLs retrieve and store them.
944     */
945    switch (acltype) {
946    case BACL_TYPE_NFS4:
947       /**
948        * Read NFS4 ACLs for files, dirs and links
949        */
950       if (generic_get_acl_from_os(jcr, BACL_TYPE_NFS4) == bacl_exit_fatal)
951          return bacl_exit_fatal;
952
953       if (jcr->acl_data->content_length > 0) {
954          if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_NFS4_ACL) == bacl_exit_fatal)
955             return bacl_exit_fatal;
956       }
957       break;
958    case BACL_TYPE_ACCESS:
959       /**
960        * Read access ACLs for files, dirs and links
961        */
962       if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
963          return bacl_exit_fatal;
964
965       if (jcr->acl_data->content_length > 0) {
966          if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_ACCESS_ACL) == bacl_exit_fatal)
967             return bacl_exit_fatal;
968       }
969
970       /**
971        * Directories can have default ACLs too
972        */
973       if (ff_pkt->type == FT_DIREND) {
974          if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
975             return bacl_exit_fatal;
976          if (jcr->acl_data->content_length > 0) {
977             if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_DEFAULT_ACL) == bacl_exit_fatal)
978                return bacl_exit_fatal;
979          }
980       }
981       break;
982    default:
983       break;
984    }
985
986    return bacl_exit_ok;
987 }
988
989 static bacl_exit_code freebsd_parse_acl_streams(JCR *jcr, int stream)
990 {
991    int acl_enabled = 0;
992    const char *acl_type_name;
993    berrno be;
994
995    /**
996     * First make sure the filesystem supports acls.
997     */
998    switch (stream) {
999    case STREAM_UNIX_ACCESS_ACL:
1000    case STREAM_ACL_FREEBSD_ACCESS_ACL:
1001    case STREAM_UNIX_DEFAULT_ACL:
1002    case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1003       acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
1004       acl_type_name = "POSIX";
1005       break;
1006    case STREAM_ACL_FREEBSD_NFS4_ACL:
1007 #if defined(_PC_ACL_NFS4)
1008       acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
1009 #endif
1010       acl_type_name = "NFS4";
1011       break;
1012    default:
1013       acl_type_name = "unknown";
1014       break;
1015    }
1016
1017    switch (acl_enabled) {
1018    case -1:
1019       switch (errno) {
1020       case ENOENT:
1021          return bacl_exit_ok;
1022       default:
1023          Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1024                jcr->last_fname, be.bstrerror());
1025          Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1026                jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1027          return bacl_exit_error;
1028       }
1029    case 0:
1030       Mmsg2(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without %s acl support\n"),
1031             jcr->last_fname, acl_type_name);
1032       return bacl_exit_error;
1033    default:
1034       break;
1035    }
1036
1037    /**
1038     * Restore the ACLs.
1039     */
1040    switch (stream) {
1041    case STREAM_UNIX_ACCESS_ACL:
1042    case STREAM_ACL_FREEBSD_ACCESS_ACL:
1043       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
1044    case STREAM_UNIX_DEFAULT_ACL:
1045    case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1046       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
1047    case STREAM_ACL_FREEBSD_NFS4_ACL:
1048       return generic_set_acl_on_os(jcr, BACL_TYPE_NFS4);
1049    default:
1050       break;
1051    }
1052    return bacl_exit_error;
1053 }
1054
1055 /**
1056  * For this OSes setup the build and parse function pointer to the OS specific functions.
1057  */
1058 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = freebsd_build_acl_streams;
1059 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = freebsd_parse_acl_streams;
1060
1061 #elif defined(HAVE_IRIX_OS) || \
1062       defined(HAVE_LINUX_OS)
1063 /**
1064  * Define the supported ACL streams for these OSes
1065  */
1066 #if defined(HAVE_IRIX_OS)
1067 static int os_access_acl_streams[1] = { STREAM_ACL_IRIX_ACCESS_ACL };
1068 static int os_default_acl_streams[1] = { STREAM_ACL_IRIX_DEFAULT_ACL };
1069 #elif defined(HAVE_LINUX_OS)
1070 static int os_access_acl_streams[1] = { STREAM_ACL_LINUX_ACCESS_ACL };
1071 static int os_default_acl_streams[1] = { STREAM_ACL_LINUX_DEFAULT_ACL };
1072 #endif
1073
1074 static bacl_exit_code generic_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1075 {
1076    /**
1077     * Read access ACLs for files, dirs and links
1078     */
1079    if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1080       return bacl_exit_fatal;
1081
1082    if (jcr->acl_data->content_length > 0) {
1083       if (send_acl_stream(jcr, os_access_acl_streams[0]) == bacl_exit_fatal)
1084          return bacl_exit_fatal;
1085    }
1086
1087    /**
1088     * Directories can have default ACLs too
1089     */
1090    if (ff_pkt->type == FT_DIREND) {
1091       if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
1092          return bacl_exit_fatal;
1093       if (jcr->acl_data->content_length > 0) {
1094          if (send_acl_stream(jcr, os_default_acl_streams[0]) == bacl_exit_fatal)
1095             return bacl_exit_fatal;
1096       }
1097    }
1098    return bacl_exit_ok;
1099 }
1100
1101 static bacl_exit_code generic_parse_acl_streams(JCR *jcr, int stream)
1102 {
1103    unsigned int cnt;
1104
1105    switch (stream) {
1106    case STREAM_UNIX_ACCESS_ACL:
1107       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
1108    case STREAM_UNIX_DEFAULT_ACL:
1109       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
1110    default:
1111       /**
1112        * See what type of acl it is.
1113        */
1114       for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1115          if (os_access_acl_streams[cnt] == stream) {
1116             return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
1117          }
1118       }
1119       for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1120          if (os_default_acl_streams[cnt] == stream) {
1121             return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
1122          }
1123       }
1124       break;
1125    }
1126    return bacl_exit_error;
1127 }
1128
1129 /**
1130  * For this OSes setup the build and parse function pointer to the OS specific functions.
1131  */
1132 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_build_acl_streams;
1133 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = generic_parse_acl_streams;
1134
1135 #elif defined(HAVE_OSF1_OS)
1136
1137 /**
1138  * Define the supported ACL streams for this OS
1139  */
1140 static int os_access_acl_streams[1] = { STREAM_ACL_TRU64_ACCESS_ACL };
1141 static int os_default_acl_streams[2] = { STREAM_ACL_TRU64_DEFAULT_ACL, STREAM_ACL_TRU64_DEFAULT_DIR_ACL };
1142
1143 static bacl_exit_code tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1144 {
1145    /**
1146     * Read access ACLs for files, dirs and links
1147     */
1148    if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
1149       return bacl_exit_error;
1150    if (jcr->acl_data->content_length > 0) {
1151       if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL))
1152          return bacl_exit_error;
1153    }
1154    /**
1155     * Directories can have default ACLs too
1156     */
1157    if (ff_pkt->type == FT_DIREND) {
1158       if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
1159          return bacl_exit_error;
1160       if (jcr->acl_data->content_length > 0) {
1161          if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL))
1162             return bacl_exit_error;
1163       }
1164       /**
1165        * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
1166        * This is an inherited acl for all subdirs.
1167        * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
1168        * Section 21.5 Default ACLs 
1169        */
1170       if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR)) < 0)
1171          return bacl_exit_error;
1172       if (jcr->acl_data->content_length > 0) {
1173          if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL))
1174             return bacl_exit_error;
1175       }
1176    }
1177    return bacl_exit_ok;
1178 }
1179
1180 static bacl_exit_code tru64_parse_acl_streams(JCR *jcr, int stream)
1181 {
1182    switch (stream) {
1183    case STREAM_UNIX_ACCESS_ACL:
1184    case STREAM_ACL_TRU64_ACCESS_ACL:
1185       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
1186    case STREAM_UNIX_DEFAULT_ACL:
1187    case STREAM_ACL_TRU64_DEFAULT_ACL:
1188       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
1189    case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
1190       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR);
1191 }
1192
1193 /**
1194  * For this OS setup the build and parse function pointer to the OS specific functions.
1195  */
1196 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = tru64_build_acl_streams;
1197 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = tru64_parse_acl_streams;
1198
1199 #endif
1200
1201 #elif defined(HAVE_HPUX_OS)
1202 #ifdef HAVE_SYS_ACL_H
1203 #include <sys/acl.h>
1204 #else
1205 #error "configure failed to detect availability of sys/acl.h"
1206 #endif
1207
1208 #include <acllib.h>
1209
1210 /**
1211  * Define the supported ACL streams for this OS
1212  */
1213 static int os_access_acl_streams[1] = { STREAM_ACL_HPUX_ACL_ENTRY };
1214 static int os_default_acl_streams[1] = { -1 };
1215
1216 /**
1217  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1218  * There is no need to store those acls as we already store the stat bits too.
1219  */
1220 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
1221 {
1222    int n;
1223    struct acl_entry ace
1224
1225    for (n = 0; n < count; n++) {
1226       ace = entries[n];
1227       /**
1228        * See if this acl just is the stat mode in acl form.
1229        */
1230       if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
1231             (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
1232             (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
1233          return false;
1234    }
1235    return true;
1236 }
1237
1238 /**
1239  * OS specific functions for handling different types of acl streams.
1240  */
1241 static bacl_exit_code hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1242 {
1243    int n;
1244    struct acl_entry acls[NACLENTRIES];
1245    char *acl_text;
1246    berrno be;
1247
1248    if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
1249       switch (errno) {
1250 #if defined(BACL_ENOTSUP)
1251       case BACL_ENOTSUP:
1252          /**
1253           * Not supported, just pretend there is nothing to see
1254           *
1255           * If the filesystem reports it doesn't support ACLs we clear the
1256           * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1257           * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1258           * when we change from one filesystem to an other.
1259           */
1260          jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1261          pm_strcpy(jcr->acl_data->content, "");
1262          jcr->acl_data->content_length = 0;
1263          return bacl_exit_ok;
1264 #endif
1265       case ENOENT:
1266          pm_strcpy(jcr->acl_data->content, "");
1267          jcr->acl_data->content_length = 0;
1268          return bacl_exit_ok;
1269       default:
1270          Mmsg2(jcr->errmsg, _("getacl error on file \"%s\": ERR=%s\n"),
1271                jcr->last_fname, be.bstrerror());
1272          Dmsg2(100, "getacl error file=%s ERR=%s\n",  
1273                jcr->last_fname, be.bstrerror());
1274
1275          pm_strcpy(jcr->acl_data->content, "");
1276          jcr->acl_data->content_length = 0;
1277          return bacl_exit_error;
1278       }
1279    }
1280    if (n == 0) {
1281       pm_strcpy(jcr->acl_data->content, "");
1282       jcr->acl_data->content_length = 0;
1283       return bacl_exit_ok;
1284    }
1285    if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
1286       if (acl_is_trivial(n, acls, ff_pkt->statp)) {
1287          /**
1288           * The ACLs simply reflect the (already known) standard permissions
1289           * So we don't send an ACL stream to the SD.
1290           */
1291          pm_strcpy(jcr->acl_data->content, "");
1292          jcr->acl_data->content_length = 0;
1293          return bacl_exit_ok;
1294       }
1295       if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
1296          jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1297          actuallyfree(acl_text);
1298
1299          return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
1300       }
1301       Mmsg2(jcr->errmsg, _("acltostr error on file \"%s\": ERR=%s\n"),
1302             jcr->last_fname, be.bstrerror());
1303       Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",  
1304             jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1305       return bacl_exit_error;
1306    }
1307    return bacl_exit_error;
1308 }
1309
1310 static bacl_exit_code hpux_parse_acl_streams(JCR *jcr, int stream)
1311 {
1312    int n, stat;
1313    struct acl_entry acls[NACLENTRIES];
1314    berrno be;
1315
1316    n = strtoacl(jcr->acl_data->content, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
1317    if (n <= 0) {
1318       Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
1319             jcr->last_fname, be.bstrerror());
1320       Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",  
1321             jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1322       return bacl_exit_error;
1323    }
1324    if (strtoacl(jcr->acl_data->content, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
1325       Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
1326             jcr->last_fname, be.bstrerror());
1327       Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",  
1328             jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1329
1330       return bacl_exit_error;
1331    }
1332    /**
1333     * Restore the ACLs, but don't complain about links which really should
1334     * not have attributes, and the file it is linked to may not yet be restored.
1335     * This is only true for the old acl streams as in the new implementation we
1336     * don't save acls of symlinks (which cannot have acls anyhow)
1337     */
1338    if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
1339       switch (errno) {
1340       case ENOENT:
1341          return bacl_exit_ok;
1342       default:
1343          Mmsg2(jcr->errmsg, _("setacl error on file \"%s\": ERR=%s\n"),
1344                jcr->last_fname, be.bstrerror());
1345          Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
1346                jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1347          return bacl_exit_error;
1348       }
1349    }
1350    return bacl_exit_ok;
1351 }
1352
1353 /**
1354  * For this OS setup the build and parse function pointer to the OS specific functions.
1355  */
1356 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = hpux_build_acl_streams;
1357 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = hpux_parse_acl_streams;
1358
1359 #elif defined(HAVE_SUN_OS)
1360 #ifdef HAVE_SYS_ACL_H
1361 #include <sys/acl.h>
1362 #else
1363 #error "configure failed to detect availability of sys/acl.h"
1364 #endif
1365
1366 #if defined(HAVE_EXTENDED_ACL)
1367 /**
1368  * We define some internals of the Solaris acl libs here as those
1369  * are not exposed yet. Probably because they want us to see the
1370  * acls as opague data. But as we need to support different platforms
1371  * and versions of Solaris we need to expose some data to be able
1372  * to determine the type of acl used to stuff it into the correct
1373  * data stream. I know this is far from portable, but maybe the
1374  * proper interface is exposed later on and we can get ride of
1375  * this kludge. Newer versions of Solaris include sys/acl_impl.h
1376  * which has implementation details of acls, if thats included we
1377  * don't have to define it ourself.
1378  */
1379 #if !defined(_SYS_ACL_IMPL_H)
1380 typedef enum acl_type {
1381    ACLENT_T = 0,
1382    ACE_T = 1
1383 } acl_type_t;
1384 #endif
1385
1386 /**
1387  * Two external references to functions in the libsec library function not in current include files.
1388  */
1389 extern "C" {
1390 int acl_type(acl_t *);
1391 char *acl_strerror(int);
1392 }
1393
1394 /**
1395  * Define the supported ACL streams for this OS
1396  */
1397 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT, STREAM_ACL_SOLARIS_ACE };
1398 static int os_default_acl_streams[1] = { -1 };
1399
1400 /**
1401  * As the new libsec interface with acl_totext and acl_fromtext also handles
1402  * the old format from acltotext we can use the new functions even
1403  * for acls retrieved and stored in the database with older fd versions. If the
1404  * new interface is not defined (Solaris 9 and older we fall back to the old code)
1405  */
1406 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1407 {
1408    int acl_enabled, flags;
1409    acl_t *aclp;
1410    char *acl_text;
1411    bacl_exit_code stream_status = bacl_exit_error;
1412    berrno be;
1413
1414    /**
1415     * See if filesystem supports acls.
1416     */
1417    acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1418    switch (acl_enabled) {
1419    case 0:
1420       /**
1421        * If the filesystem reports it doesn't support ACLs we clear the
1422        * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1423        * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1424        * when we change from one filesystem to an other.
1425        */
1426       jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1427       pm_strcpy(jcr->acl_data->content, "");
1428       jcr->acl_data->content_length = 0;
1429       return bacl_exit_ok;
1430    case -1:
1431       switch (errno) {
1432       case ENOENT:
1433          return bacl_exit_ok;
1434       default:
1435          Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1436                jcr->last_fname, be.bstrerror());
1437          Dmsg2(100, "pathconf error file=%s ERR=%s\n",  
1438                jcr->last_fname, be.bstrerror());
1439          return bacl_exit_error;
1440       }
1441    default:
1442       break;
1443    }
1444
1445    /**
1446     * Get ACL info: don't bother allocating space if there is only a trivial ACL.
1447     */
1448    if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
1449       switch (errno) {
1450       case ENOENT:
1451          return bacl_exit_ok;
1452       default:
1453          Mmsg2(jcr->errmsg, _("acl_get error on file \"%s\": ERR=%s\n"),
1454                jcr->last_fname, acl_strerror(errno));
1455          Dmsg2(100, "acl_get error file=%s ERR=%s\n",  
1456                jcr->last_fname, acl_strerror(errno));
1457          return bacl_exit_error;
1458       }
1459    }
1460
1461    if (!aclp) {
1462       /**
1463        * The ACLs simply reflect the (already known) standard permissions
1464        * So we don't send an ACL stream to the SD.
1465        */
1466       pm_strcpy(jcr->acl_data->content, "");
1467       jcr->acl_data->content_length = 0;
1468       return bacl_exit_ok;
1469    }
1470
1471 #if defined(ACL_SID_FMT)
1472    /**
1473     * New format flag added in newer Solaris versions.
1474     */
1475    flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
1476 #else
1477    flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
1478 #endif /* ACL_SID_FMT */
1479
1480    if ((acl_text = acl_totext(aclp, flags)) != NULL) {
1481       jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1482       actuallyfree(acl_text);
1483
1484       switch (acl_type(aclp)) {
1485       case ACLENT_T:
1486          stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1487          break;
1488       case ACE_T:
1489          stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE);
1490          break;
1491       default:
1492          break;
1493       }
1494
1495       acl_free(aclp);
1496    }
1497    return stream_status;
1498 }
1499
1500 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
1501 {
1502    acl_t *aclp;
1503    int acl_enabled, error;
1504    berrno be;
1505
1506    switch (stream) {
1507    case STREAM_UNIX_ACCESS_ACL:
1508    case STREAM_ACL_SOLARIS_ACLENT:
1509    case STREAM_ACL_SOLARIS_ACE:
1510       /**
1511        * First make sure the filesystem supports acls.
1512        */
1513       acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1514       switch (acl_enabled) {
1515       case 0:
1516          Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
1517                jcr->last_fname);
1518          return bacl_exit_error;
1519       case -1:
1520          switch (errno) {
1521          case ENOENT:
1522             return bacl_exit_ok;
1523          default:
1524             Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1525                   jcr->last_fname, be.bstrerror());
1526             Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",  
1527                   jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1528             return bacl_exit_error;
1529          }
1530       default:
1531          /**
1532           * On a filesystem with ACL support make sure this particular ACL type can be restored.
1533           */
1534          switch (stream) {
1535          case STREAM_ACL_SOLARIS_ACLENT:
1536             /**
1537              * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
1538              */
1539             if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
1540                Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without aclent acl support\n"),
1541                      jcr->last_fname);
1542                return bacl_exit_error;
1543             }
1544             break;
1545          case STREAM_ACL_SOLARIS_ACE:
1546             /**
1547              * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
1548              */
1549             if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
1550                Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without ace acl support\n"),
1551                      jcr->last_fname);
1552                return bacl_exit_error;
1553             }
1554             break;
1555          default:
1556             /**
1557              * Stream id which doesn't describe the type of acl which is encoded.
1558              */
1559             break;
1560          }
1561          break;
1562       }
1563
1564       if ((error = acl_fromtext(jcr->acl_data->content, &aclp)) != 0) {
1565          Mmsg2(jcr->errmsg, _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1566                jcr->last_fname, acl_strerror(error));
1567          Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",  
1568                jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1569          return bacl_exit_error;
1570       }
1571
1572       /**
1573        * Validate that the conversion gave us the correct acl type.
1574        */
1575       switch (stream) {
1576       case STREAM_ACL_SOLARIS_ACLENT:
1577          if (acl_type(aclp) != ACLENT_T) {
1578             Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1579                   jcr->last_fname);
1580             return bacl_exit_error;
1581          }
1582          break;
1583       case STREAM_ACL_SOLARIS_ACE:
1584          if (acl_type(aclp) != ACE_T) {
1585             Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1586                   jcr->last_fname);
1587             return bacl_exit_error;
1588          }
1589          break;
1590       default:
1591          /**
1592           * Stream id which doesn't describe the type of acl which is encoded.
1593           */
1594          break;
1595       }
1596
1597       /**
1598        * Restore the ACLs, but don't complain about links which really should
1599        * not have attributes, and the file it is linked to may not yet be restored.
1600        * This is only true for the old acl streams as in the new implementation we
1601        * don't save acls of symlinks (which cannot have acls anyhow)
1602        */
1603       if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1604          switch (errno) {
1605          case ENOENT:
1606             acl_free(aclp);
1607             return bacl_exit_ok;
1608          default:
1609             Mmsg2(jcr->errmsg, _("acl_set error on file \"%s\": ERR=%s\n"),
1610                   jcr->last_fname, acl_strerror(error));
1611             Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",  
1612                   jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1613             acl_free(aclp);
1614             return bacl_exit_error;
1615          }
1616       }
1617
1618       acl_free(aclp);
1619       return bacl_exit_ok;
1620    default:
1621       return bacl_exit_error;
1622    } /* end switch (stream) */
1623 }
1624
1625 #else /* HAVE_EXTENDED_ACL */
1626
1627 /**
1628  * Define the supported ACL streams for this OS
1629  */
1630 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT };
1631 static int os_default_acl_streams[1] = { -1 };
1632
1633 /**
1634  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1635  * There is no need to store those acls as we already store the stat bits too.
1636  */
1637 static bool acl_is_trivial(int count, aclent_t *entries)
1638 {
1639    int n;
1640    aclent_t *ace;
1641
1642    for (n = 0; n < count; n++) {
1643       ace = &entries[n];
1644
1645       if (!(ace->a_type == USER_OBJ ||
1646             ace->a_type == GROUP_OBJ ||
1647             ace->a_type == OTHER_OBJ ||
1648             ace->a_type == CLASS_OBJ))
1649         return false;
1650    }
1651    return true;
1652 }
1653
1654 /**
1655  * OS specific functions for handling different types of acl streams.
1656  */
1657 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1658 {
1659    int n;
1660    aclent_t *acls;
1661    char *acl_text;
1662    berrno be;
1663
1664    n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1665    if (n < MIN_ACL_ENTRIES)
1666       return bacl_exit_error;
1667
1668    acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1669    if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1670       if (acl_is_trivial(n, acls)) {
1671          /**
1672           * The ACLs simply reflect the (already known) standard permissions
1673           * So we don't send an ACL stream to the SD.
1674           */
1675          free(acls);
1676          pm_strcpy(jcr->acl_data->content, "");
1677          jcr->acl_data->content_length = 0;
1678          return bacl_exit_ok;
1679       }
1680
1681       if ((acl_text = acltotext(acls, n)) != NULL) {
1682          jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1683          actuallyfree(acl_text);
1684          free(acls);
1685          return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1686       }
1687
1688       Mmsg2(jcr->errmsg, _("acltotext error on file \"%s\": ERR=%s\n"),
1689             jcr->last_fname, be.bstrerror());
1690       Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",  
1691             jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1692    }
1693
1694    free(acls);
1695    return bacl_exit_error;
1696 }
1697
1698 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
1699 {
1700    int n;
1701    aclent_t *acls;
1702    berrno be;
1703
1704    acls = aclfromtext(jcr->acl_data->content, &n);
1705    if (!acls) {
1706       Mmsg2(jcr->errmsg, _("aclfromtext error on file \"%s\": ERR=%s\n"),
1707             jcr->last_fname, be.bstrerror());
1708       Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",  
1709             jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1710       return bacl_exit_error;
1711    }
1712
1713    /**
1714     * Restore the ACLs, but don't complain about links which really should
1715     * not have attributes, and the file it is linked to may not yet be restored.
1716     */
1717    if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
1718       switch (errno) {
1719       case ENOENT:
1720          actuallyfree(acls);
1721          return bacl_exit_ok;
1722       default:
1723          Mmsg2(jcr->errmsg, _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
1724                jcr->last_fname, be.bstrerror());
1725          Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
1726                jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1727          actuallyfree(acls);
1728          return bacl_exit_error;
1729       }
1730    }
1731    actuallyfree(acls);
1732    return bacl_exit_ok;
1733 }
1734 #endif /* HAVE_EXTENDED_ACL */
1735
1736 /**
1737  * For this OS setup the build and parse function pointer to the OS specific functions.
1738  */
1739 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_acl_streams;
1740 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = solaris_parse_acl_streams;
1741
1742 #endif /* HAVE_SUN_OS */
1743 #endif /* HAVE_ACL */
1744
1745 /*
1746  * Entry points when compiled with support for ACLs on a supported platform.
1747  */
1748
1749 /**
1750  * Read and send an ACL for the last encountered file.
1751  */
1752 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1753 {
1754    /**
1755     * See if we are changing from one device to an other.
1756     * We save the current device we are scanning and compare
1757     * it with the current st_dev in the last stat performed on
1758     * the file we are currently storing.
1759     */
1760    if (jcr->acl_data->current_dev != ff_pkt->statp.st_dev) {
1761       /**
1762        * Reset the acl save flags.
1763        */
1764       jcr->acl_data->flags = 0;
1765
1766       jcr->acl_data->flags |= BACL_FLAG_SAVE_NATIVE;
1767
1768       /**
1769        * Save that we started scanning a new filesystem.
1770        */
1771       jcr->acl_data->current_dev = ff_pkt->statp.st_dev;
1772    }
1773
1774 #if defined(HAVE_ACL)
1775    /**
1776     * See if the BACL_FLAG_SAVE_NATIVE flag is set which lets us know if we should
1777     * save native ACLs.
1778     */
1779    if (jcr->acl_data->flags & BACL_FLAG_SAVE_NATIVE) {
1780       /**
1781        * Call the appropriate function.
1782        */
1783       if (os_build_acl_streams) {
1784          return (*os_build_acl_streams)(jcr, ff_pkt);
1785       }
1786    } else {
1787       return bacl_exit_ok;
1788    }
1789 #endif
1790    return bacl_exit_error;
1791 }
1792
1793 bacl_exit_code parse_acl_streams(JCR *jcr, int stream)
1794 {
1795    unsigned int cnt;
1796
1797    switch (stream) {
1798 #if defined(HAVE_ACL)
1799    case STREAM_UNIX_ACCESS_ACL:
1800    case STREAM_UNIX_DEFAULT_ACL:
1801       /**
1802        * Handle legacy ACL streams.
1803        */
1804       if (os_parse_acl_streams) {
1805          return (*os_parse_acl_streams)(jcr, stream);
1806       }
1807       break;
1808    default:
1809       if (os_parse_acl_streams) {
1810          /**
1811           * Walk the os_access_acl_streams array with the supported Access ACL streams for this OS.
1812           */
1813          for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1814             if (os_access_acl_streams[cnt] == stream) {
1815                return (*os_parse_acl_streams)(jcr, stream);
1816             }
1817          }
1818          /**
1819           * Walk the os_default_acl_streams array with the supported Default ACL streams for this OS.
1820           */
1821          for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1822             if (os_default_acl_streams[cnt] == stream) {
1823                return (*os_parse_acl_streams)(jcr, stream);
1824             }
1825          }
1826       }
1827       break;
1828 #else
1829    default:
1830       break;
1831 #endif
1832    }
1833    Qmsg2(jcr, M_WARNING, 0,
1834       _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
1835       jcr->last_fname, stream);
1836    return bacl_exit_error;
1837 }
1838 #endif