]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/acl.c
Implement feature request #1939
[bacula/bacula] / bacula / src / filed / acl.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2004-2012 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  *   - GNU Hurd
36  *   - HPUX
37  *   - IRIX
38  *   - Linux
39  *   - Solaris (POSIX and NFSv4/ZFS acls)
40  *   - Tru64
41  *
42  * Next to OS specific acls we support AFS acls using the pioctl interface.
43  *
44  * We handle two different types of ACLs: access and default ACLS.
45  * On most systems that support default ACLs they only apply to directories.
46  *
47  * On some systems (eg. linux and FreeBSD) we must obtain the two ACLs
48  * independently, while others (eg. Solaris) provide both in one call.
49  *
50  * The Filed saves ACLs in their native format and uses different streams
51  * for all different platforms. Currently we only allow ACLs to be restored
52  * which were saved in the native format of the platform they are extracted
53  * on. Later on we might add conversion functions for mapping from one
54  * platform to an other or allow restores of systems that use the same
55  * native format.
56  *
57  * Its also interesting to see what the exact format of acl text is on
58  * certain platforms and if they use they same encoding we might allow
59  * different platform streams to be decoded on an other similar platform.
60  *
61  *   Original written by Preben 'Peppe' Guldberg, December 2004
62  *   Major rewrite by Marco van Wieringen, November 2008
63  *   Major overhaul by Marco van Wieringen, January 2012
64  */
65   
66 #include "bacula.h"
67 #include "filed.h"
68   
69 #if !defined(HAVE_ACL) && !defined(HAVE_AFS_ACL)
70 /**
71  * Entry points when compiled without support for ACLs or on an unsupported platform.
72  */
73 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
74 {
75    return bacl_exit_fatal;
76 }
77
78 bacl_exit_code parse_acl_streams(JCR *jcr,
79                                  int stream,
80                                  char *content,
81                                  uint32_t content_length)
82 {
83    return bacl_exit_fatal;
84 }
85 #else
86 /**
87  * Send an ACL stream to the SD.
88  */
89 static bacl_exit_code send_acl_stream(JCR *jcr, int stream)
90 {
91    BSOCK *sd = jcr->store_bsock;
92    POOLMEM *msgsave;
93 #ifdef FD_NO_SEND_TEST
94    return bacl_exit_ok;
95 #endif
96
97    /*
98     * Sanity check
99     */
100    if (jcr->acl_data->u.build->content_length <= 0) {
101       return bacl_exit_ok;
102    }
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       return bacl_exit_fatal;
111    }
112
113    /*
114     * Send the buffer to the storage deamon
115     */
116    Dmsg1(400, "Backing up ACL <%s>\n", jcr->acl_data->u.build->content);
117    msgsave = sd->msg;
118    sd->msg = jcr->acl_data->u.build->content;
119    sd->msglen = jcr->acl_data->u.build->content_length + 1;
120    if (!sd->send()) {
121       sd->msg = msgsave;
122       sd->msglen = 0;
123       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
124             sd->bstrerror());
125       return bacl_exit_fatal;
126    }
127
128    jcr->JobBytes += sd->msglen;
129    sd->msg = msgsave;
130    if (!sd->signal(BNET_EOD)) {
131       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
132             sd->bstrerror());
133       return bacl_exit_fatal;
134    }
135
136    Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
137    return bacl_exit_ok;
138 }
139
140 /*
141  * First the native ACLs.
142  */
143 #if defined(HAVE_ACL)
144 #if defined(HAVE_AIX_OS)
145
146 #if defined(HAVE_EXTENDED_ACL)
147
148 #include <sys/access.h>
149 #include <sys/acl.h>
150
151 static bool acl_is_trivial(struct acl *acl)
152 {
153    return (acl_last(acl) != acl->acl_ext ? false : true);
154 }
155
156 static bool acl_nfs4_is_trivial(nfs4_acl_int_t *acl)
157 {
158 #if 0
159    return (acl->aclEntryN > 0 ? false : true);
160 #else
161    int i;
162    int count = acl->aclEntryN;
163    nfs4_ace_int_t *ace;
164
165    for (i = 0; i < count; i++) {
166       ace = &acl->aclEntry[i];
167       if (!((ace->flags & ACE4_ID_SPECIAL) != 0 &&
168             (ace->aceWho.special_whoid == ACE4_WHO_OWNER ||
169              ace->aceWho.special_whoid == ACE4_WHO_GROUP ||
170              ace->aceWho.special_whoid == ACE4_WHO_EVERYONE) &&
171              ace->aceType == ACE4_ACCESS_ALLOWED_ACE_TYPE &&
172              ace->aceFlags == 0 &&
173             (ace->aceMask & ~(ACE4_READ_DATA |
174                               ACE4_LIST_DIRECTORY |
175                               ACE4_WRITE_DATA |
176                               ACE4_ADD_FILE |
177                               ACE4_EXECUTE)) == 0)) {
178          return false;
179       }
180    }
181    return true;
182 #endif
183 }
184
185 /*
186  * Define the supported ACL streams for this OS
187  */
188 static int os_access_acl_streams[3] = {
189    STREAM_ACL_AIX_TEXT,
190    STREAM_ACL_AIX_AIXC,
191    STREAM_ACL_AIX_NFS4
192 };
193 static int os_default_acl_streams[1] = {
194    -1
195 };
196
197 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
198 {
199    mode_t mode;
200    acl_type_t type;
201    size_t aclsize, acltxtsize;
202    bacl_exit_code retval = bacl_exit_error;
203    POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
204
205    /*
206     * First see how big the buffers should be.
207     */
208    memset(&type, 0, sizeof(acl_type_t));
209    type.u64 = ACL_ANY;
210    if (aclx_get(jcr->last_fname, GET_ACLINFO_ONLY, &type, NULL, &aclsize, &mode) < 0) {
211       berrno be;
212
213       switch (errno) {
214       case ENOENT:
215          retval = bacl_exit_ok;
216          goto bail_out;
217       case ENOSYS:
218          /*
219           * If the filesystem reports it doesn't support ACLs we clear the
220           * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
221           * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
222           * when we change from one filesystem to an other.
223           */
224          jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
225          retval = bacl_exit_ok;
226          goto bail_out;
227       default:
228          Mmsg2(jcr->errmsg,
229                _("aclx_get error on file \"%s\": ERR=%s\n"),
230                jcr->last_fname, be.bstrerror());
231          Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
232                jcr->last_fname, be.bstrerror());
233          goto bail_out;
234       }
235    }
236
237    /*
238     * Make sure the buffers are big enough.
239     */
240    aclbuf = check_pool_memory_size(aclbuf, aclsize + 1);
241
242    /*
243     * Retrieve the ACL info.
244     */
245    if (aclx_get(jcr->last_fname, 0, &type, aclbuf, &aclsize, &mode) < 0) {
246       berrno be;
247
248       switch (errno) {
249       case ENOENT:
250          retval = bacl_exit_ok;
251          goto bail_out;
252       default:
253          Mmsg2(jcr->errmsg,
254                _("aclx_get error on file \"%s\": ERR=%s\n"),
255                jcr->last_fname, be.bstrerror());
256          Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
257                jcr->last_fname, be.bstrerror());
258          goto bail_out;
259       }
260    }
261
262    /*
263     * See if the acl is non trivial.
264     */
265    switch (type.u64) {
266    case ACL_AIXC:
267       if (acl_is_trivial((struct acl *)aclbuf)) {
268          retval = bacl_exit_ok;
269          goto bail_out;
270       }
271       break;
272    case ACL_NFS4:
273       if (acl_nfs4_is_trivial((nfs4_acl_int_t *)aclbuf)) {
274          retval = bacl_exit_ok;
275          goto bail_out;
276       }
277       break;
278    default:
279       Mmsg2(jcr->errmsg,
280             _("Unknown acl type encountered on file \"%s\": %ld\n"),
281             jcr->last_fname, type.u64);
282       Dmsg2(100, "Unknown acl type encountered on file \"%s\": %ld\n",
283             jcr->last_fname, type.u64);
284       goto bail_out;
285    }
286
287    /*
288     * We have a non-trivial acl lets convert it into some ASCII form.
289     */
290    acltxtsize = sizeof_pool_memory(jcr->acl_data->u.build->content);
291    if (aclx_printStr(jcr->acl_data->u.build->content, &acltxtsize, aclbuf,
292                      aclsize, type, jcr->last_fname, 0) < 0) {
293       switch (errno) {
294       case ENOSPC:
295          /*
296           * Our buffer is not big enough, acltxtsize should be updated with the value
297           * the aclx_printStr really need. So we increase the buffer and try again.
298           */
299          jcr->acl_data->u.build->content =
300          check_pool_memory_size(jcr->acl_data->u.build->content, acltxtsize + 1);
301          if (aclx_printStr(jcr->acl_data->u.build->content, &acltxtsize, aclbuf,
302                            aclsize, type, jcr->last_fname, 0) < 0) {
303             Mmsg1(jcr->errmsg,
304                   _("Failed to convert acl into text on file \"%s\"\n"),
305                   jcr->last_fname);
306             Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
307                   jcr->last_fname, type.u64);
308             goto bail_out;
309          }
310          break;
311       default:
312          Mmsg1(jcr->errmsg,
313                _("Failed to convert acl into text on file \"%s\"\n"),
314                jcr->last_fname);
315          Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
316                jcr->last_fname, type.u64);
317          goto bail_out;
318       }
319    }
320
321    jcr->acl_data->u.build->content_length = strlen(jcr->acl_data->u.build->content) + 1;
322    switch (type.u64) {
323    case ACL_AIXC:
324       retval = send_acl_stream(jcr, STREAM_ACL_AIX_AIXC);
325    case ACL_NFS4:
326       retval = send_acl_stream(jcr, STREAM_ACL_AIX_NFS4);
327    }
328
329 bail_out:
330    free_pool_memory(aclbuf);
331
332    return retval;
333 }
334
335 /*
336  * See if a specific type of ACLs are supported on the filesystem
337  * the file is located on.
338  */
339 static inline bool aix_query_acl_support(JCR *jcr,
340                                          uint64_t aclType,
341                                          acl_type_t *pacl_type_info)
342 {
343    unsigned int i;
344    acl_types_list_t acl_type_list;
345    size_t acl_type_list_len = sizeof(acl_types_list_t);
346
347    memset(&acl_type_list, 0, sizeof(acl_type_list));
348    if (aclx_gettypes(jcr->last_fname, &acl_type_list, &acl_type_list_len)) {
349       return false;
350    }
351
352    for (i = 0; i < acl_type_list.num_entries; i++) {
353       if (acl_type_list.entries[i].u64 == aclType) {
354          memcpy(pacl_type_info, acl_type_list.entries + i, sizeof(acl_type_t));
355          return true;
356       }
357    }
358    return false;
359 }
360
361 static bacl_exit_code aix_parse_acl_streams(JCR *jcr,
362                                             int stream,
363                                             char *content,
364                                             uint32_t content_length)
365 {
366    int cnt;
367    acl_type_t type;
368    size_t aclsize;
369    bacl_exit_code retval = bacl_exit_error;
370    POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
371
372    switch (stream) {
373    case STREAM_ACL_AIX_TEXT:
374       /*
375        * Handle the old stream using the old system call for now.
376        */
377       if (acl_put(jcr->last_fname, content, 0) != 0) {
378          retval = bacl_exit_error;
379          goto bail_out;
380       }
381       retval = bacl_exit_ok;
382       goto bail_out;
383    case STREAM_ACL_AIX_AIXC:
384       if (!aix_query_acl_support(jcr, ACL_AIXC, &type)) {
385          Mmsg1(jcr->errmsg,
386                _("Trying to restore POSIX acl on file \"%s\" on filesystem without AIXC acl support\n"),
387                jcr->last_fname);
388          goto bail_out;
389       }
390       break;
391    case STREAM_ACL_AIX_NFS4:
392       if (!aix_query_acl_support(jcr, ACL_NFS4, &type)) {
393          Mmsg1(jcr->errmsg,
394                _("Trying to restore NFSv4 acl on file \"%s\" on filesystem without NFS4 acl support\n"),
395                jcr->last_fname);
396          goto bail_out;
397       }
398       break;
399    default:
400       goto bail_out;
401    } /* end switch (stream) */
402
403    /*
404     * Set the acl buffer to an initial size. For now we set it
405     * to the same size as the ASCII representation.
406     */
407    aclbuf = check_pool_memory_size(aclbuf, content_length);
408    aclsize = content_length;
409    if (aclx_scanStr(content, aclbuf, &aclsize, type) < 0) {
410       berrno be;
411
412       switch (errno) {
413       case ENOSPC:
414          /*
415           * The buffer isn't big enough. The man page doesn't say that aclsize
416           * is updated to the needed size as what is done with aclx_printStr.
417           * So for now we try to increase the buffer a maximum of 3 times
418           * and retry the conversion.
419           */
420          for (cnt = 0; cnt < 3; cnt++) {
421             aclsize = 2 * aclsize;
422             aclbuf = check_pool_memory_size(aclbuf, aclsize);
423
424             if (aclx_scanStr(content, aclbuf, &aclsize, type) == 0) {
425                break;
426             }
427
428             /*
429              * See why we failed this time, ENOSPC retry if max retries not met,
430              * otherwise abort.
431              */
432             switch (errno) {
433             case ENOSPC:
434                if (cnt < 3) {
435                   continue;
436                }
437                /*
438                 * FALLTHROUGH
439                 */
440             default:
441                Mmsg2(jcr->errmsg,
442                      _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
443                      jcr->last_fname, be.bstrerror(errno));
444                Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
445                      jcr->last_fname, be.bstrerror());
446                goto bail_out;
447             }
448          }
449          break;
450       default:
451          Mmsg2(jcr->errmsg,
452                _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
453                jcr->last_fname, be.bstrerror());
454          Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
455                jcr->last_fname, be.bstrerror());
456       }
457    }
458
459    if (aclx_put(jcr->last_fname, SET_ACL, type, aclbuf, aclsize, 0) < 0) {
460       berrno be;
461
462       switch (errno) {
463       case ENOENT:
464          retval = bacl_exit_ok;
465          goto bail_out;
466       case ENOSYS:
467          /*
468           * If the filesystem reports it doesn't support ACLs we clear the
469           * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
470           * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
471           * when we change from one filesystem to an other.
472           */
473          jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
474          retval = bacl_exit_ok;
475          goto bail_out;
476       default:
477          Mmsg2(jcr->errmsg,
478                _("aclx_put error on file \"%s\": ERR=%s\n"),
479                jcr->last_fname, be.bstrerror());
480          Dmsg2(100, "aclx_put error file=%s ERR=%s\n",
481                jcr->last_fname, be.bstrerror());
482          goto bail_out;
483       }
484    }
485
486    retval = bacl_exit_ok;
487
488 bail_out:
489    free_pool_memory(aclbuf);
490
491    return retval;
492 }
493
494 #else /* HAVE_EXTENDED_ACL */
495
496 #include <sys/access.h>
497
498 /*
499  * Define the supported ACL streams for this OS
500  */
501 static int os_access_acl_streams[1] = {
502    STREAM_ACL_AIX_TEXT
503 };
504 static int os_default_acl_streams[1] = {
505    -1
506 };
507
508 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
509 {
510    char *acl_text;
511
512    if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
513       jcr->acl_data->u.build->content_length =
514       pm_strcpy(jcr->acl_data->u.build->content, acl_text);
515       actuallyfree(acl_text);
516       return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT);
517    }
518    return bacl_exit_error;
519 }
520
521 static bacl_exit_code aix_parse_acl_streams(JCR *jcr,
522                                             int stream,
523                                             char *content,
524                                             uint32_t content_length)
525 {
526    if (acl_put(jcr->last_fname, content, 0) != 0) {
527       return bacl_exit_error;
528    }
529    return bacl_exit_ok;
530 }
531 #endif /* HAVE_EXTENDED_ACL */
532
533 /*
534  * For this OS setup the build and parse function pointer to the OS specific functions.
535  */
536 static bacl_exit_code (*os_build_acl_streams)
537                       (JCR *jcr, FF_PKT *ff_pkt) =
538                       aix_build_acl_streams;
539 static bacl_exit_code (*os_parse_acl_streams)
540                       (JCR *jcr, int stream, char *content, uint32_t content_length) =
541                       aix_parse_acl_streams;
542
543 #elif defined(HAVE_DARWIN_OS) || \
544       defined(HAVE_FREEBSD_OS) || \
545       defined(HAVE_IRIX_OS) || \
546       defined(HAVE_OSF1_OS) || \
547       defined(HAVE_LINUX_OS) || \
548       defined(HAVE_HURD_OS)
549
550 #include <sys/types.h>
551
552 #ifdef HAVE_SYS_ACL_H
553 #include <sys/acl.h>
554 #else
555 #error "configure failed to detect availability of sys/acl.h"
556 #endif
557
558 /*
559  * On IRIX we can get shortened ACLs
560  */
561 #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
562 #define acl_to_text(acl,len)     acl_to_short_text((acl), (len))
563 #endif
564
565 /*
566  * On Linux we can get numeric and/or shorted ACLs
567  */
568 #if defined(HAVE_LINUX_OS)
569 #if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
570 #define BACL_ALTERNATE_TEXT            (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
571 #elif defined(BACL_WANT_SHORT_ACLS)
572 #define BACL_ALTERNATE_TEXT            TEXT_ABBREVIATE
573 #elif defined(BACL_WANT_NUMERIC_IDS)
574 #define BACL_ALTERNATE_TEXT            TEXT_NUMERIC_IDS
575 #endif
576 #ifdef BACL_ALTERNATE_TEXT
577 #include <acl/libacl.h>
578 #define acl_to_text(acl,len)     (acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
579 #endif
580 #endif
581
582 /*
583  * On FreeBSD we can get numeric ACLs
584  */
585 #if defined(HAVE_FREEBSD_OS)
586 #if defined(BACL_WANT_NUMERIC_IDS)
587 #define BACL_ALTERNATE_TEXT            ACL_TEXT_NUMERIC_IDS
588 #endif
589 #ifdef BACL_ALTERNATE_TEXT
590 #define acl_to_text(acl,len)     (acl_to_text_np((acl), (len), BACL_ALTERNATE_TEXT))
591 #endif
592 #endif
593
594 /*
595  * Some generic functions used by multiple OSes.
596  */
597 static acl_type_t bac_to_os_acltype(bacl_type acltype)
598 {
599    acl_type_t ostype;
600
601    switch (acltype) {
602    case BACL_TYPE_ACCESS:
603       ostype = ACL_TYPE_ACCESS;
604       break;
605    case BACL_TYPE_DEFAULT:
606       ostype = ACL_TYPE_DEFAULT;
607       break;
608 #ifdef HAVE_ACL_TYPE_NFS4
609       /*
610        * FreeBSD has an additional acl type named ACL_TYPE_NFS4.
611        */
612    case BACL_TYPE_NFS4:
613       ostype = ACL_TYPE_NFS4;
614       break;
615 #endif
616 #ifdef HAVE_ACL_TYPE_DEFAULT_DIR
617    case BACL_TYPE_DEFAULT_DIR:
618       /*
619        * TRU64 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
620        */
621       ostype = ACL_TYPE_DEFAULT_DIR;
622       break;
623 #endif
624 #ifdef HAVE_ACL_TYPE_EXTENDED
625    case BACL_TYPE_EXTENDED:
626       /*
627        * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
628        */
629       ostype = ACL_TYPE_EXTENDED;
630       break;
631 #endif
632    default:
633       /*
634        * This should never happen, as the per OS version function only tries acl
635        * types supported on a certain platform.
636        */
637       ostype = (acl_type_t)ACL_TYPE_NONE;
638       break;
639    }
640    return ostype;
641 }
642
643 static int acl_count_entries(acl_t acl)
644 {
645    int count = 0;
646 #if defined(HAVE_FREEBSD_OS) || \
647     defined(HAVE_LINUX_OS) || \
648     defined(HAVE_HURD_OS)
649    acl_entry_t ace;
650    int entry_available;
651
652    entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
653    while (entry_available == 1) {
654       count++;
655       entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
656    }
657 #elif defined(HAVE_IRIX_OS)
658    count = acl->acl_cnt;
659 #elif defined(HAVE_OSF1_OS)
660    count = acl->acl_num;
661 #elif defined(HAVE_DARWIN_OS)
662    acl_entry_t ace;
663    int entry_available;
664
665    entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
666    while (entry_available == 0) {
667       count++;
668       entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
669    }
670 #endif
671    return count;
672 }
673
674 #if !defined(HAVE_DARWIN_OS)
675 /*
676  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
677  * There is no need to store those acls as we already store the stat bits too.
678  */
679 static bool acl_is_trivial(acl_t acl)
680 {
681   /*
682    * acl is trivial if it has only the following entries:
683    * "user::",
684    * "group::",
685    * "other::"
686    */
687    acl_entry_t ace;
688    acl_tag_t tag;
689 #if defined(HAVE_FREEBSD_OS) || \
690     defined(HAVE_LINUX_OS) || \
691     defined(HAVE_HURD_OS)
692    int entry_available;
693
694    entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
695    while (entry_available == 1) {
696       /*
697        * Get the tag type of this acl entry.
698        * If we fail to get the tagtype we call the acl non-trivial.
699        */
700       if (acl_get_tag_type(ace, &tag) < 0)
701          return true;
702       /*
703        * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
704        */
705       if (tag != ACL_USER_OBJ &&
706           tag != ACL_GROUP_OBJ &&
707           tag != ACL_OTHER)
708          return false;
709       entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
710    }
711    return true;
712 #elif defined(HAVE_IRIX_OS)
713    int n;
714
715    for (n = 0; n < acl->acl_cnt; n++) {
716       ace = &acl->acl_entry[n];
717       tag = ace->ae_tag;
718
719       /*
720        * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
721        */
722       if (tag != ACL_USER_OBJ &&
723           tag != ACL_GROUP_OBJ &&
724           tag != ACL_OTHER_OBJ)
725          return false;
726    }
727    return true;
728 #elif defined(HAVE_OSF1_OS)
729    int count;
730
731    ace = acl->acl_first;
732    count = acl->acl_num;
733
734    while (count > 0) {
735       tag = ace->entry->acl_type;
736       /*
737        * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
738        */
739       if (tag != ACL_USER_OBJ &&
740           tag != ACL_GROUP_OBJ &&
741           tag != ACL_OTHER)
742          return false;
743       /*
744        * On Tru64, perm can also contain non-standard bits such as
745        * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
746        */
747       if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
748          return false;
749       ace = ace->next;
750       count--;
751    }
752    return true;
753 #endif
754 }
755 #endif
756
757 /**
758  * Generic wrapper around acl_get_file call.
759  */
760 static bacl_exit_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
761 {
762    acl_t acl;
763    acl_type_t ostype;
764    char *acl_text;
765    bacl_exit_code retval = bacl_exit_ok;
766
767    ostype = bac_to_os_acltype(acltype);
768    acl = acl_get_file(jcr->last_fname, ostype);
769    if (acl) {
770       /**
771        * From observation, IRIX's acl_get_file() seems to return a
772        * non-NULL acl with a count field of -1 when a file has no ACL
773        * defined, while IRIX's acl_to_text() returns NULL when presented
774        * with such an ACL. 
775        *
776        * For all other implmentations we check if there are more then
777        * zero entries in the acl returned.
778        */
779       if (acl_count_entries(acl) <= 0) {
780          goto bail_out;
781       }
782
783       /*
784        * Make sure this is not just a trivial ACL.
785        */
786 #if !defined(HAVE_DARWIN_OS)
787       if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
788          /*
789           * The ACLs simply reflect the (already known) standard permissions
790           * So we don't send an ACL stream to the SD.
791           */
792          goto bail_out;
793       }
794 #endif
795 #if defined(HAVE_FREEBSD_OS) && defined(_PC_ACL_NFS4)
796       if (acltype == BACL_TYPE_NFS4) {
797          int trivial;
798          if (acl_is_trivial_np(acl, &trivial) == 0) {
799             if (trivial == 1) {
800                /*
801                 * The ACLs simply reflect the (already known) standard permissions
802                 * So we don't send an ACL stream to the SD.
803                 */
804                goto bail_out;
805             }
806          }
807       }
808 #endif
809
810       /*
811        * Convert the internal acl representation into a text representation.
812        */
813       if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
814          jcr->acl_data->u.build->content_length =
815          pm_strcpy(jcr->acl_data->u.build->content, acl_text);
816          acl_free(acl);
817          acl_free(acl_text);
818          return bacl_exit_ok;
819       }
820
821       berrno be;
822       Mmsg2(jcr->errmsg,
823             _("acl_to_text error on file \"%s\": ERR=%s\n"),
824             jcr->last_fname, be.bstrerror());
825       Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",  
826             jcr->last_fname, be.bstrerror());
827
828       retval = bacl_exit_error;
829       goto bail_out;
830    } else {
831       berrno be;
832
833       /*
834        * Handle errors gracefully.
835        */
836       switch (errno) {
837 #if defined(BACL_ENOTSUP)
838       case BACL_ENOTSUP:
839          /*
840           * If the filesystem reports it doesn't support ACLs we clear the
841           * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
842           * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
843           * when we change from one filesystem to an other.
844           */
845          jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
846          goto bail_out;
847 #endif
848       case ENOENT:
849          goto bail_out;
850       default:
851          /* Some real error */
852          Mmsg2(jcr->errmsg,
853                _("acl_get_file error on file \"%s\": ERR=%s\n"),
854                jcr->last_fname, be.bstrerror());
855          Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",  
856                jcr->last_fname, be.bstrerror());
857
858          retval = bacl_exit_error;
859          goto bail_out;
860       }
861    }
862
863 bail_out:
864    if (acl) {
865       acl_free(acl);
866    }
867    pm_strcpy(jcr->acl_data->u.build->content, "");
868    jcr->acl_data->u.build->content_length = 0;
869    return retval;
870 }
871
872 /**
873  * Generic wrapper around acl_set_file call.
874  */
875 static bacl_exit_code generic_set_acl_on_os(JCR *jcr,
876                                             bacl_type acltype,
877                                             char *content,
878                                             uint32_t content_length)
879 {
880    acl_t acl;
881    acl_type_t ostype;
882
883    /*
884     * If we get empty default ACLs, clear ACLs now
885     */
886    ostype = bac_to_os_acltype(acltype);
887    if (ostype == ACL_TYPE_DEFAULT && strlen(content) == 0) {
888       if (acl_delete_def_file(jcr->last_fname) == 0) {
889          return bacl_exit_ok;
890       }
891       berrno be;
892
893       switch (errno) {
894       case ENOENT:
895          return bacl_exit_ok;
896 #if defined(BACL_ENOTSUP)
897       case BACL_ENOTSUP:
898          /*
899           * If the filesystem reports it doesn't support ACLs we clear the
900           * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
901           * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
902           * when we change from one filesystem to an other.
903           */
904          jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
905          Mmsg1(jcr->errmsg,
906                _("acl_delete_def_file error on file \"%s\": filesystem doesn't support ACLs\n"),
907                jcr->last_fname);
908          return bacl_exit_error;
909 #endif
910       default:
911          Mmsg2(jcr->errmsg,
912                _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
913                jcr->last_fname, be.bstrerror());
914          return bacl_exit_error;
915       }
916    }
917
918    acl = acl_from_text(content);
919    if (acl == NULL) {
920       berrno be;
921
922       Mmsg2(jcr->errmsg,
923             _("acl_from_text error on file \"%s\": ERR=%s\n"),
924             jcr->last_fname, be.bstrerror());
925       Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",  
926             content, jcr->last_fname, be.bstrerror());
927       return bacl_exit_error;
928    }
929
930 #ifndef HAVE_FREEBSD_OS
931    /**
932     * FreeBSD always fails acl_valid() - at least on valid input...
933     * As it does the right thing, given valid input, just ignore acl_valid().
934     */
935    if (acl_valid(acl) != 0) {
936       berrno be;
937
938       Mmsg2(jcr->errmsg,
939             _("acl_valid error on file \"%s\": ERR=%s\n"),
940             jcr->last_fname, be.bstrerror());
941       Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",  
942             content, jcr->last_fname, be.bstrerror());
943       acl_free(acl);
944       return bacl_exit_error;
945    }
946 #endif
947
948    /**
949     * Restore the ACLs, but don't complain about links which really should
950     * not have attributes, and the file it is linked to may not yet be restored.
951     * This is only true for the old acl streams as in the new implementation we
952     * don't save acls of symlinks (which cannot have acls anyhow)
953     */
954    if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
955       berrno be;
956
957       switch (errno) {
958       case ENOENT:
959          acl_free(acl);
960          return bacl_exit_ok;
961 #if defined(BACL_ENOTSUP)
962       case BACL_ENOTSUP:
963          /*
964           * If the filesystem reports it doesn't support ACLs we clear the
965           * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
966           * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
967           * when we change from one filesystem to an other.
968           */
969          jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
970          Mmsg1(jcr->errmsg,
971                _("acl_set_file error on file \"%s\": filesystem doesn't support ACLs\n"),
972                jcr->last_fname);
973          Dmsg2(100, "acl_set_file error acl=%s file=%s filesystem doesn't support ACLs\n",
974                content, jcr->last_fname);
975          acl_free(acl);
976          return bacl_exit_error;
977 #endif
978       default:
979          Mmsg2(jcr->errmsg,
980                _("acl_set_file error on file \"%s\": ERR=%s\n"),
981                jcr->last_fname, be.bstrerror());
982          Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
983                content, jcr->last_fname, be.bstrerror());
984          acl_free(acl);
985          return bacl_exit_error;
986       }
987    }
988    acl_free(acl);
989    return bacl_exit_ok;
990 }
991
992 /**
993  * OS specific functions for handling different types of acl streams.
994  */
995 #if defined(HAVE_DARWIN_OS)
996 /**
997  * Define the supported ACL streams for this OS
998  */
999 static int os_access_acl_streams[1] = {
1000    STREAM_ACL_DARWIN_ACCESS_ACL
1001 };
1002 static int os_default_acl_streams[1] = {
1003    -1
1004 };
1005
1006 static bacl_exit_code darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1007 {
1008 #if defined(HAVE_ACL_TYPE_EXTENDED)
1009    /**
1010     * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
1011     * and acl_get_file (name, ACL_TYPE_DEFAULT)
1012     * always return NULL / EINVAL.  There is no point in making
1013     * these two useless calls.  The real ACL is retrieved through
1014     * acl_get_file (name, ACL_TYPE_EXTENDED).
1015     *
1016     * Read access ACLs for files, dirs and links
1017     */
1018    if (generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED) == bacl_exit_fatal)
1019       return bacl_exit_fatal;
1020 #else
1021    /**
1022     * Read access ACLs for files, dirs and links
1023     */
1024    if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1025       return bacl_exit_fatal;
1026 #endif
1027
1028    if (jcr->acl_data->u.build->content_length > 0) {
1029       return send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL);
1030    }
1031    return bacl_exit_ok;
1032 }
1033
1034 static bacl_exit_code darwin_parse_acl_streams(JCR *jcr,
1035                                                int stream,
1036                                                char *content,
1037                                                uint32_t content_length)
1038 {
1039 #if defined(HAVE_ACL_TYPE_EXTENDED)
1040       return generic_set_acl_on_os(jcr, BACL_TYPE_EXTENDED, content, content_length);
1041 #else
1042       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1043 #endif
1044 }
1045
1046 /*
1047  * For this OS setup the build and parse function pointer to the OS specific functions.
1048  */
1049 static bacl_exit_code (*os_build_acl_streams)
1050                       (JCR *jcr, FF_PKT *ff_pkt) =
1051                       darwin_build_acl_streams;
1052 static bacl_exit_code (*os_parse_acl_streams)
1053                       (JCR *jcr, int stream, char *content, uint32_t content_length) =
1054                       darwin_parse_acl_streams;
1055
1056 #elif defined(HAVE_FREEBSD_OS)
1057 /*
1058  * Define the supported ACL streams for these OSes
1059  */
1060 static int os_access_acl_streams[2] = {
1061    STREAM_ACL_FREEBSD_ACCESS_ACL,
1062    STREAM_ACL_FREEBSD_NFS4_ACL
1063 };
1064 static int os_default_acl_streams[1] = {
1065    STREAM_ACL_FREEBSD_DEFAULT_ACL
1066 };
1067
1068 static bacl_exit_code freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1069 {
1070    int acl_enabled = 0;
1071    bacl_type acltype = BACL_TYPE_NONE;
1072
1073 #if defined(_PC_ACL_NFS4)
1074    /*
1075     * See if filesystem supports NFS4 acls.
1076     */
1077    acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
1078    switch (acl_enabled) {
1079    case -1: {
1080       berrno be;
1081
1082       switch (errno) {
1083       case ENOENT:
1084          return bacl_exit_ok;
1085       default:
1086          Mmsg2(jcr->errmsg,
1087                _("pathconf error on file \"%s\": ERR=%s\n"),
1088                jcr->last_fname, be.bstrerror());
1089          Dmsg2(100, "pathconf error file=%s ERR=%s\n",
1090                jcr->last_fname, be.bstrerror());
1091          return bacl_exit_error;
1092       }
1093    }
1094    case 0:
1095       break;
1096    default:
1097       acltype = BACL_TYPE_NFS4;
1098       break;
1099    }
1100 #endif
1101
1102    if (acl_enabled == 0) {
1103       /*
1104        * See if filesystem supports POSIX acls.
1105        */
1106       acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
1107       switch (acl_enabled) {
1108       case -1: {
1109          berrno be;
1110
1111          switch (errno) {
1112          case ENOENT:
1113             return bacl_exit_ok;
1114          default:
1115             Mmsg2(jcr->errmsg,
1116                   _("pathconf error on file \"%s\": ERR=%s\n"),
1117                   jcr->last_fname, be.bstrerror());
1118             Dmsg2(100, "pathconf error file=%s ERR=%s\n",
1119                   jcr->last_fname, be.bstrerror());
1120             return bacl_exit_error;
1121          }
1122       }
1123       case 0:
1124          break;
1125       default:
1126          acltype = BACL_TYPE_ACCESS;
1127          break;
1128       }
1129    }
1130
1131    /*
1132     * If the filesystem reports it doesn't support ACLs we clear the
1133     * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1134     * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1135     * when we change from one filesystem to an other.
1136     */
1137    if (acl_enabled == 0) {
1138       jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1139       pm_strcpy(jcr->acl_data->u.build->content, "");
1140       jcr->acl_data->u.build->content_length = 0;
1141       return bacl_exit_ok;
1142    }
1143
1144    /*
1145     * Based on the supported ACLs retrieve and store them.
1146     */
1147    switch (acltype) {
1148    case BACL_TYPE_NFS4:
1149       /*
1150        * Read NFS4 ACLs for files, dirs and links
1151        */
1152       if (generic_get_acl_from_os(jcr, BACL_TYPE_NFS4) == bacl_exit_fatal)
1153          return bacl_exit_fatal;
1154
1155       if (jcr->acl_data->u.build->content_length > 0) {
1156          if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_NFS4_ACL) == bacl_exit_fatal)
1157             return bacl_exit_fatal;
1158       }
1159       break;
1160    case BACL_TYPE_ACCESS:
1161       /*
1162        * Read access ACLs for files, dirs and links
1163        */
1164       if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1165          return bacl_exit_fatal;
1166
1167       if (jcr->acl_data->u.build->content_length > 0) {
1168          if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_ACCESS_ACL) == bacl_exit_fatal)
1169             return bacl_exit_fatal;
1170       }
1171
1172       /*
1173        * Directories can have default ACLs too
1174        */
1175       if (ff_pkt->type == FT_DIREND) {
1176          if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
1177             return bacl_exit_fatal;
1178          if (jcr->acl_data->u.build->content_length > 0) {
1179             if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_DEFAULT_ACL) == bacl_exit_fatal)
1180                return bacl_exit_fatal;
1181          }
1182       }
1183       break;
1184    default:
1185       break;
1186    }
1187
1188    return bacl_exit_ok;
1189 }
1190
1191 static bacl_exit_code freebsd_parse_acl_streams(JCR *jcr,
1192                                                 int stream,
1193                                                 char *content,
1194                                                 uint32_t content_length)
1195 {
1196    int acl_enabled = 0;
1197    const char *acl_type_name;
1198
1199    /*
1200     * First make sure the filesystem supports acls.
1201     */
1202    switch (stream) {
1203    case STREAM_UNIX_ACCESS_ACL:
1204    case STREAM_ACL_FREEBSD_ACCESS_ACL:
1205    case STREAM_UNIX_DEFAULT_ACL:
1206    case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1207       acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
1208       acl_type_name = "POSIX";
1209       break;
1210    case STREAM_ACL_FREEBSD_NFS4_ACL:
1211 #if defined(_PC_ACL_NFS4)
1212       acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
1213 #endif
1214       acl_type_name = "NFS4";
1215       break;
1216    default:
1217       acl_type_name = "unknown";
1218       break;
1219    }
1220
1221    switch (acl_enabled) {
1222    case -1: {
1223       berrno be;
1224
1225       switch (errno) {
1226       case ENOENT:
1227          return bacl_exit_ok;
1228       default:
1229          Mmsg2(jcr->errmsg,
1230                _("pathconf error on file \"%s\": ERR=%s\n"),
1231                jcr->last_fname, be.bstrerror());
1232          Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1233                content, jcr->last_fname, be.bstrerror());
1234          return bacl_exit_error;
1235       }
1236    }
1237    case 0:
1238       /*
1239        * If the filesystem reports it doesn't support ACLs we clear the
1240        * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
1241        * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
1242        * when we change from one filesystem to an other.
1243        */
1244       jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1245       Mmsg2(jcr->errmsg,
1246             _("Trying to restore acl on file \"%s\" on filesystem without %s acl support\n"),
1247             jcr->last_fname, acl_type_name);
1248       return bacl_exit_error;
1249    default:
1250       break;
1251    }
1252
1253    /*
1254     * Restore the ACLs.
1255     */
1256    switch (stream) {
1257    case STREAM_UNIX_ACCESS_ACL:
1258    case STREAM_ACL_FREEBSD_ACCESS_ACL:
1259       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1260    case STREAM_UNIX_DEFAULT_ACL:
1261    case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1262       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1263    case STREAM_ACL_FREEBSD_NFS4_ACL:
1264       return generic_set_acl_on_os(jcr, BACL_TYPE_NFS4, content, content_length);
1265    default:
1266       break;
1267    }
1268    return bacl_exit_error;
1269 }
1270
1271 /*
1272  * For this OSes setup the build and parse function pointer to the OS specific functions.
1273  */
1274 static bacl_exit_code (*os_build_acl_streams)
1275                       (JCR *jcr, FF_PKT *ff_pkt) =
1276                       freebsd_build_acl_streams;
1277 static bacl_exit_code (*os_parse_acl_streams)
1278                       (JCR *jcr, int stream, char *content, uint32_t content_length) =
1279                       freebsd_parse_acl_streams;
1280
1281 #elif defined(HAVE_IRIX_OS) || \
1282       defined(HAVE_LINUX_OS) || \
1283       defined(HAVE_HURD_OS)
1284 /*
1285  * Define the supported ACL streams for these OSes
1286  */
1287 #if defined(HAVE_IRIX_OS)
1288 static int os_access_acl_streams[1] = {
1289    STREAM_ACL_IRIX_ACCESS_ACL
1290 };
1291 static int os_default_acl_streams[1] = {
1292    STREAM_ACL_IRIX_DEFAULT_ACL
1293 };
1294 #elif defined(HAVE_LINUX_OS)
1295 static int os_access_acl_streams[1] = {
1296    STREAM_ACL_LINUX_ACCESS_ACL
1297 };
1298 static int os_default_acl_streams[1] = {
1299    STREAM_ACL_LINUX_DEFAULT_ACL
1300 };
1301 #elif defined(HAVE_HURD_OS)
1302 static int os_access_acl_streams[1] = {
1303    STREAM_ACL_HURD_ACCESS_ACL
1304 };
1305 static int os_default_acl_streams[1] = {
1306    STREAM_ACL_HURD_DEFAULT_ACL
1307 };
1308 #endif
1309
1310 static bacl_exit_code generic_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1311 {
1312    /*
1313     * Read access ACLs for files, dirs and links
1314     */
1315    if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1316       return bacl_exit_fatal;
1317
1318    if (jcr->acl_data->u.build->content_length > 0) {
1319       if (send_acl_stream(jcr, os_access_acl_streams[0]) == bacl_exit_fatal)
1320          return bacl_exit_fatal;
1321    }
1322
1323    /*
1324     * Directories can have default ACLs too
1325     */
1326    if (ff_pkt->type == FT_DIREND) {
1327       if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
1328          return bacl_exit_fatal;
1329       if (jcr->acl_data->u.build->content_length > 0) {
1330          if (send_acl_stream(jcr, os_default_acl_streams[0]) == bacl_exit_fatal)
1331             return bacl_exit_fatal;
1332       }
1333    }
1334    return bacl_exit_ok;
1335 }
1336
1337 static bacl_exit_code generic_parse_acl_streams(JCR *jcr,
1338                                                 int stream,
1339                                                 char *content,
1340                                                 uint32_t content_length)
1341 {
1342    unsigned int cnt;
1343
1344    switch (stream) {
1345    case STREAM_UNIX_ACCESS_ACL:
1346       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1347    case STREAM_UNIX_DEFAULT_ACL:
1348       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1349    default:
1350       /*
1351        * See what type of acl it is.
1352        */
1353       for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1354          if (os_access_acl_streams[cnt] == stream) {
1355             return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1356          }
1357       }
1358       for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1359          if (os_default_acl_streams[cnt] == stream) {
1360             return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1361          }
1362       }
1363       break;
1364    }
1365    return bacl_exit_error;
1366 }
1367
1368 /*
1369  * For this OSes setup the build and parse function pointer to the OS specific functions.
1370  */
1371 static bacl_exit_code (*os_build_acl_streams)
1372                       (JCR *jcr, FF_PKT *ff_pkt) =
1373                       generic_build_acl_streams;
1374 static bacl_exit_code (*os_parse_acl_streams)
1375                       (JCR *jcr, int stream, char *content, uint32_t content_length) =
1376                       generic_parse_acl_streams;
1377
1378 #elif defined(HAVE_OSF1_OS)
1379
1380 /*
1381  * Define the supported ACL streams for this OS
1382  */
1383 static int os_access_acl_streams[1] = {
1384    STREAM_ACL_TRU64_ACCESS_ACL
1385 };
1386 static int os_default_acl_streams[2] = {
1387    STREAM_ACL_TRU64_DEFAULT_ACL,
1388    STREAM_ACL_TRU64_DEFAULT_DIR_ACL
1389 };
1390
1391 static bacl_exit_code tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1392 {
1393    /*
1394     * Read access ACLs for files, dirs and links
1395     */
1396    if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal) {
1397       return bacl_exit_error;
1398    if (jcr->acl_data->u.build->content_length > 0) {
1399       if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL))
1400          return bacl_exit_error;
1401    }
1402    /*
1403     * Directories can have default ACLs too
1404     */
1405    if (ff_pkt->type == FT_DIREND) {
1406       if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal) {
1407          return bacl_exit_error;
1408       if (jcr->acl_data->u.build->content_length > 0) {
1409          if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL))
1410             return bacl_exit_error;
1411       }
1412       /**
1413        * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
1414        * This is an inherited acl for all subdirs.
1415        * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
1416        * Section 21.5 Default ACLs 
1417        */
1418       if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR) == bacl_exit_fatal) {
1419          return bacl_exit_error;
1420       if (jcr->acl_data->u.build->content_length > 0) {
1421          if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL))
1422             return bacl_exit_error;
1423       }
1424    }
1425    return bacl_exit_ok;
1426 }
1427
1428 static bacl_exit_code tru64_parse_acl_streams(JCR *jcr,
1429                                               int stream,
1430                                               char *content,
1431                                               uint32_t content_length)
1432 {
1433    switch (stream) {
1434    case STREAM_UNIX_ACCESS_ACL:
1435    case STREAM_ACL_TRU64_ACCESS_ACL:
1436       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1437    case STREAM_UNIX_DEFAULT_ACL:
1438    case STREAM_ACL_TRU64_DEFAULT_ACL:
1439       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1440    case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
1441       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR, content, content_length);
1442 }
1443
1444 /*
1445  * For this OS setup the build and parse function pointer to the OS specific functions.
1446  */
1447 static bacl_exit_code (*os_build_acl_streams)
1448                       (JCR *jcr, FF_PKT *ff_pkt) =
1449                       tru64_build_acl_streams;
1450 static bacl_exit_code (*os_parse_acl_streams)
1451                       (JCR *jcr, int stream, char *content, uint32_t content_length) =
1452                       tru64_parse_acl_streams;
1453
1454 #endif
1455
1456 #elif defined(HAVE_HPUX_OS)
1457 #ifdef HAVE_SYS_ACL_H
1458 #include <sys/acl.h>
1459 #else
1460 #error "configure failed to detect availability of sys/acl.h"
1461 #endif
1462
1463 #include <acllib.h>
1464
1465 /*
1466  * Define the supported ACL streams for this OS
1467  */
1468 static int os_access_acl_streams[1] = {
1469    STREAM_ACL_HPUX_ACL_ENTRY
1470 };
1471 static int os_default_acl_streams[1] = {
1472    -1
1473 };
1474
1475 /*
1476  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1477  * There is no need to store those acls as we already store the stat bits too.
1478  */
1479 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
1480 {
1481    int n;
1482    struct acl_entry ace
1483
1484    for (n = 0; n < count; n++) {
1485       ace = entries[n];
1486       /*
1487        * See if this acl just is the stat mode in acl form.
1488        */
1489       if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
1490             (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
1491             (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
1492          return false;
1493    }
1494    return true;
1495 }
1496
1497 /*
1498  * OS specific functions for handling different types of acl streams.
1499  */
1500 static bacl_exit_code hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1501 {
1502    int n;
1503    struct acl_entry acls[NACLENTRIES];
1504    char *acl_text;
1505
1506    if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
1507       berrno be;
1508
1509       switch (errno) {
1510 #if defined(BACL_ENOTSUP)
1511       case BACL_ENOTSUP:
1512          /*
1513           * Not supported, just pretend there is nothing to see
1514           *
1515           * If the filesystem reports it doesn't support ACLs we clear the
1516           * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1517           * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1518           * when we change from one filesystem to an other.
1519           */
1520          jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1521          pm_strcpy(jcr->acl_data->u.build->content, "");
1522          jcr->acl_data->u.build->content_length = 0;
1523          return bacl_exit_ok;
1524 #endif
1525       case ENOENT:
1526          pm_strcpy(jcr->acl_data->u.build->content, "");
1527          jcr->acl_data->u.build->content_length = 0;
1528          return bacl_exit_ok;
1529       default:
1530          Mmsg2(jcr->errmsg,
1531                _("getacl error on file \"%s\": ERR=%s\n"),
1532                jcr->last_fname, be.bstrerror());
1533          Dmsg2(100, "getacl error file=%s ERR=%s\n",  
1534                jcr->last_fname, be.bstrerror());
1535
1536          pm_strcpy(jcr->acl_data->u.build->content, "");
1537          jcr->acl_data->u.build->content_length = 0;
1538          return bacl_exit_error;
1539       }
1540    }
1541    if (n == 0) {
1542       pm_strcpy(jcr->acl_data->u.build->content, "");
1543       jcr->acl_data->u.build->content_length = 0;
1544       return bacl_exit_ok;
1545    }
1546    if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
1547       if (acl_is_trivial(n, acls, ff_pkt->statp)) {
1548          /*
1549           * The ACLs simply reflect the (already known) standard permissions
1550           * So we don't send an ACL stream to the SD.
1551           */
1552          pm_strcpy(jcr->acl_data->u.build->content, "");
1553          jcr->acl_data->u.build->content_length = 0;
1554          return bacl_exit_ok;
1555       }
1556       if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
1557          jcr->acl_data->u.build->content_length =
1558          pm_strcpy(jcr->acl_data->u.build->content, acl_text);
1559          actuallyfree(acl_text);
1560
1561          return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
1562       }
1563
1564       berrno be;
1565       Mmsg2(jcr->errmsg,
1566             _("acltostr error on file \"%s\": ERR=%s\n"),
1567             jcr->last_fname, be.bstrerror());
1568       Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",  
1569             jcr->acl_data->u.build->content, jcr->last_fname, be.bstrerror());
1570       return bacl_exit_error;
1571    }
1572    return bacl_exit_error;
1573 }
1574
1575 static bacl_exit_code hpux_parse_acl_streams(JCR *jcr,
1576                                              int stream,
1577                                              char *content,
1578                                              uint32_t content_length)
1579 {
1580    int n, stat;
1581    struct acl_entry acls[NACLENTRIES];
1582
1583    n = strtoacl(content, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
1584    if (n <= 0) {
1585       berrno be;
1586
1587       Mmsg2(jcr->errmsg,
1588             _("strtoacl error on file \"%s\": ERR=%s\n"),
1589             jcr->last_fname, be.bstrerror());
1590       Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",  
1591             content, jcr->last_fname, be.bstrerror());
1592       return bacl_exit_error;
1593    }
1594    if (strtoacl(content, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
1595       berrno be;
1596
1597       Mmsg2(jcr->errmsg,
1598             _("strtoacl error on file \"%s\": ERR=%s\n"),
1599             jcr->last_fname, be.bstrerror());
1600       Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",  
1601             content, jcr->last_fname, be.bstrerror());
1602
1603       return bacl_exit_error;
1604    }
1605    /**
1606     * Restore the ACLs, but don't complain about links which really should
1607     * not have attributes, and the file it is linked to may not yet be restored.
1608     * This is only true for the old acl streams as in the new implementation we
1609     * don't save acls of symlinks (which cannot have acls anyhow)
1610     */
1611    if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
1612       berrno be;
1613
1614       switch (errno) {
1615       case ENOENT:
1616          return bacl_exit_ok;
1617 #if defined(BACL_ENOTSUP)
1618       case BACL_ENOTSUP:
1619          /*
1620           * If the filesystem reports it doesn't support ACLs we clear the
1621           * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
1622           * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
1623           * when we change from one filesystem to an other.
1624           */
1625          jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1626          Mmsg1(jcr->errmsg,
1627                _("setacl error on file \"%s\": filesystem doesn't support ACLs\n"),
1628                jcr->last_fname);
1629          Dmsg2(100, "setacl error acl=%s file=%s filesystem doesn't support ACLs\n",
1630                content, jcr->last_fname);
1631          return bacl_exit_error;
1632 #endif
1633       default:
1634          Mmsg2(jcr->errmsg,
1635                _("setacl error on file \"%s\": ERR=%s\n"),
1636                jcr->last_fname, be.bstrerror());
1637          Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
1638                content, jcr->last_fname, be.bstrerror());
1639          return bacl_exit_error;
1640       }
1641    }
1642    return bacl_exit_ok;
1643 }
1644
1645 /*
1646  * For this OS setup the build and parse function pointer to the OS specific functions.
1647  */
1648 static bacl_exit_code (*os_build_acl_streams)
1649                       (JCR *jcr, FF_PKT *ff_pkt) =
1650                       hpux_build_acl_streams;
1651 static bacl_exit_code (*os_parse_acl_streams)
1652                       (JCR *jcr, int stream, char *content, uint32_t content_length) =
1653                       hpux_parse_acl_streams;
1654
1655 #elif defined(HAVE_SUN_OS)
1656 #ifdef HAVE_SYS_ACL_H
1657 #include <sys/acl.h>
1658 #else
1659 #error "configure failed to detect availability of sys/acl.h"
1660 #endif
1661
1662 #if defined(HAVE_EXTENDED_ACL)
1663 /**
1664  * We define some internals of the Solaris acl libs here as those
1665  * are not exposed yet. Probably because they want us to see the
1666  * acls as opague data. But as we need to support different platforms
1667  * and versions of Solaris we need to expose some data to be able
1668  * to determine the type of acl used to stuff it into the correct
1669  * data stream. I know this is far from portable, but maybe the
1670  * proper interface is exposed later on and we can get ride of
1671  * this kludge. Newer versions of Solaris include sys/acl_impl.h
1672  * which has implementation details of acls, if thats included we
1673  * don't have to define it ourself.
1674  */
1675 #if !defined(_SYS_ACL_IMPL_H)
1676 typedef enum acl_type {
1677    ACLENT_T = 0,
1678    ACE_T = 1
1679 } acl_type_t;
1680 #endif
1681
1682 /**
1683  * Two external references to functions in the libsec library function not in current include files.
1684  */
1685 extern "C" {
1686 int acl_type(acl_t *);
1687 char *acl_strerror(int);
1688 }
1689
1690 /*
1691  * Define the supported ACL streams for this OS
1692  */
1693 static int os_access_acl_streams[2] = {
1694    STREAM_ACL_SOLARIS_ACLENT,
1695    STREAM_ACL_SOLARIS_ACE
1696 };
1697 static int os_default_acl_streams[1] = {
1698    -1
1699 };
1700
1701 /**
1702  * As the new libsec interface with acl_totext and acl_fromtext also handles
1703  * the old format from acltotext we can use the new functions even
1704  * for acls retrieved and stored in the database with older fd versions. If the
1705  * new interface is not defined (Solaris 9 and older we fall back to the old code)
1706  */
1707 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1708 {
1709    int acl_enabled, flags;
1710    acl_t *aclp;
1711    char *acl_text;
1712    bacl_exit_code stream_status = bacl_exit_error;
1713
1714    /*
1715     * See if filesystem supports acls.
1716     */
1717    acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1718    switch (acl_enabled) {
1719    case 0:
1720       /*
1721        * If the filesystem reports it doesn't support ACLs we clear the
1722        * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1723        * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1724        * when we change from one filesystem to an other.
1725        */
1726       jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1727       pm_strcpy(jcr->acl_data->u.build->content, "");
1728       jcr->acl_data->u.build->content_length = 0;
1729       return bacl_exit_ok;
1730    case -1: {
1731       berrno be;
1732
1733       switch (errno) {
1734       case ENOENT:
1735          return bacl_exit_ok;
1736       default:
1737          Mmsg2(jcr->errmsg,
1738                _("pathconf error on file \"%s\": ERR=%s\n"),
1739                jcr->last_fname, be.bstrerror());
1740          Dmsg2(100, "pathconf error file=%s ERR=%s\n",  
1741                jcr->last_fname, be.bstrerror());
1742          return bacl_exit_error;
1743       }
1744    }
1745    default:
1746       break;
1747    }
1748
1749    /*
1750     * Get ACL info: don't bother allocating space if there is only a trivial ACL.
1751     */
1752    if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
1753       berrno be;
1754
1755       switch (errno) {
1756       case ENOENT:
1757          return bacl_exit_ok;
1758       default:
1759          Mmsg2(jcr->errmsg,
1760                _("acl_get error on file \"%s\": ERR=%s\n"),
1761                jcr->last_fname, acl_strerror(errno));
1762          Dmsg2(100, "acl_get error file=%s ERR=%s\n",  
1763                jcr->last_fname, acl_strerror(errno));
1764          return bacl_exit_error;
1765       }
1766    }
1767
1768    if (!aclp) {
1769       /*
1770        * The ACLs simply reflect the (already known) standard permissions
1771        * So we don't send an ACL stream to the SD.
1772        */
1773       pm_strcpy(jcr->acl_data->u.build->content, "");
1774       jcr->acl_data->u.build->content_length = 0;
1775       return bacl_exit_ok;
1776    }
1777
1778 #if defined(ACL_SID_FMT)
1779    /*
1780     * New format flag added in newer Solaris versions.
1781     */
1782    flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
1783 #else
1784    flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
1785 #endif /* ACL_SID_FMT */
1786
1787    if ((acl_text = acl_totext(aclp, flags)) != NULL) {
1788       jcr->acl_data->u.build->content_length =
1789       pm_strcpy(jcr->acl_data->u.build->content, acl_text);
1790       actuallyfree(acl_text);
1791
1792       switch (acl_type(aclp)) {
1793       case ACLENT_T:
1794          stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1795          break;
1796       case ACE_T:
1797          stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE);
1798          break;
1799       default:
1800          break;
1801       }
1802
1803       acl_free(aclp);
1804    }
1805    return stream_status;
1806 }
1807
1808 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr,
1809                                                 int stream,
1810                                                 char *content,
1811                                                 uint32_t content_length)
1812 {
1813    acl_t *aclp;
1814    int acl_enabled, error;
1815
1816    switch (stream) {
1817    case STREAM_UNIX_ACCESS_ACL:
1818    case STREAM_ACL_SOLARIS_ACLENT:
1819    case STREAM_ACL_SOLARIS_ACE:
1820       /*
1821        * First make sure the filesystem supports acls.
1822        */
1823       acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1824       switch (acl_enabled) {
1825       case 0:
1826          /*
1827           * If the filesystem reports it doesn't support ACLs we clear the
1828           * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
1829           * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
1830           * when we change from one filesystem to an other.
1831           */
1832          jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
1833          Mmsg1(jcr->errmsg,
1834                _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
1835                jcr->last_fname);
1836          return bacl_exit_error;
1837       case -1: {
1838          berrno be;
1839
1840          switch (errno) {
1841          case ENOENT:
1842             return bacl_exit_ok;
1843          default:
1844             Mmsg2(jcr->errmsg,
1845                   _("pathconf error on file \"%s\": ERR=%s\n"),
1846                   jcr->last_fname, be.bstrerror());
1847             Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",  
1848                   content, jcr->last_fname, be.bstrerror());
1849             return bacl_exit_error;
1850          }
1851       }
1852       default:
1853          /*
1854           * On a filesystem with ACL support make sure this particular ACL type can be restored.
1855           */
1856          switch (stream) {
1857          case STREAM_ACL_SOLARIS_ACLENT:
1858             /*
1859              * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
1860              */
1861             if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
1862                Mmsg1(jcr->errmsg,
1863                      _("Trying to restore POSIX acl on file \"%s\" on filesystem without aclent acl support\n"),
1864                      jcr->last_fname);
1865                return bacl_exit_error;
1866             }
1867             break;
1868          case STREAM_ACL_SOLARIS_ACE:
1869             /*
1870              * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
1871              */
1872             if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
1873                Mmsg1(jcr->errmsg,
1874                      _("Trying to restore NFSv4 acl on file \"%s\" on filesystem without ace acl support\n"),
1875                      jcr->last_fname);
1876                return bacl_exit_error;
1877             }
1878             break;
1879          default:
1880             /*
1881              * Stream id which doesn't describe the type of acl which is encoded.
1882              */
1883             break;
1884          }
1885          break;
1886       }
1887
1888       if ((error = acl_fromtext(content, &aclp)) != 0) {
1889          Mmsg2(jcr->errmsg,
1890                _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1891                jcr->last_fname, acl_strerror(error));
1892          Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",  
1893                content, jcr->last_fname, acl_strerror(error));
1894          return bacl_exit_error;
1895       }
1896
1897       /*
1898        * Validate that the conversion gave us the correct acl type.
1899        */
1900       switch (stream) {
1901       case STREAM_ACL_SOLARIS_ACLENT:
1902          if (acl_type(aclp) != ACLENT_T) {
1903             Mmsg1(jcr->errmsg,
1904                   _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1905                   jcr->last_fname);
1906             return bacl_exit_error;
1907          }
1908          break;
1909       case STREAM_ACL_SOLARIS_ACE:
1910          if (acl_type(aclp) != ACE_T) {
1911             Mmsg1(jcr->errmsg,
1912                   _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1913                   jcr->last_fname);
1914             return bacl_exit_error;
1915          }
1916          break;
1917       default:
1918          /*
1919           * Stream id which doesn't describe the type of acl which is encoded.
1920           */
1921          break;
1922       }
1923
1924       /**
1925        * Restore the ACLs, but don't complain about links which really should
1926        * not have attributes, and the file it is linked to may not yet be restored.
1927        * This is only true for the old acl streams as in the new implementation we
1928        * don't save acls of symlinks (which cannot have acls anyhow)
1929        */
1930       if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1931          switch (errno) {
1932          case ENOENT:
1933             acl_free(aclp);
1934             return bacl_exit_ok;
1935          default:
1936             Mmsg2(jcr->errmsg,
1937                   _("acl_set error on file \"%s\": ERR=%s\n"),
1938                   jcr->last_fname, acl_strerror(error));
1939             Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",  
1940                   content, jcr->last_fname, acl_strerror(error));
1941             acl_free(aclp);
1942             return bacl_exit_error;
1943          }
1944       }
1945
1946       acl_free(aclp);
1947       return bacl_exit_ok;
1948    default:
1949       return bacl_exit_error;
1950    } /* end switch (stream) */
1951 }
1952
1953 #else /* HAVE_EXTENDED_ACL */
1954
1955 /*
1956  * Define the supported ACL streams for this OS
1957  */
1958 static int os_access_acl_streams[1] = {
1959    STREAM_ACL_SOLARIS_ACLENT
1960 };
1961 static int os_default_acl_streams[1] = {
1962    -1
1963 };
1964
1965 /*
1966  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1967  * There is no need to store those acls as we already store the stat bits too.
1968  */
1969 static bool acl_is_trivial(int count, aclent_t *entries)
1970 {
1971    int n;
1972    aclent_t *ace;
1973
1974    for (n = 0; n < count; n++) {
1975       ace = &entries[n];
1976
1977       if (!(ace->a_type == USER_OBJ ||
1978             ace->a_type == GROUP_OBJ ||
1979             ace->a_type == OTHER_OBJ ||
1980             ace->a_type == CLASS_OBJ))
1981         return false;
1982    }
1983    return true;
1984 }
1985
1986 /*
1987  * OS specific functions for handling different types of acl streams.
1988  */
1989 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1990 {
1991    int n;
1992    aclent_t *acls;
1993    char *acl_text;
1994
1995    n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1996    if (n < MIN_ACL_ENTRIES) {
1997       return bacl_exit_error;
1998    }
1999
2000    acls = (aclent_t *)malloc(n * sizeof(aclent_t));
2001    if (acl(jcr->last_fname, GETACL, n, acls) == n) {
2002       if (acl_is_trivial(n, acls)) {
2003          /*
2004           * The ACLs simply reflect the (already known) standard permissions
2005           * So we don't send an ACL stream to the SD.
2006           */
2007          free(acls);
2008          pm_strcpy(jcr->acl_data->u.build->content, "");
2009          jcr->acl_data->u.build->content_length = 0;
2010          return bacl_exit_ok;
2011       }
2012
2013       if ((acl_text = acltotext(acls, n)) != NULL) {
2014          jcr->acl_data->u.build->content_length =
2015          pm_strcpy(jcr->acl_data->u.build->content, acl_text);
2016          actuallyfree(acl_text);
2017          free(acls);
2018          return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
2019       }
2020
2021       berrno be;
2022       Mmsg2(jcr->errmsg,
2023             _("acltotext error on file \"%s\": ERR=%s\n"),
2024             jcr->last_fname, be.bstrerror());
2025       Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",  
2026             jcr->acl_data->u.build->content, jcr->last_fname, be.bstrerror());
2027    }
2028
2029    free(acls);
2030    return bacl_exit_error;
2031 }
2032
2033 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr,
2034                                                 int stream,
2035                                                 char *content,
2036                                                 uint32_t content_length)
2037 {
2038    int n;
2039    aclent_t *acls;
2040
2041    acls = aclfromtext(content, &n);
2042    if (!acls) {
2043       berrno be;
2044
2045       Mmsg2(jcr->errmsg,
2046             _("aclfromtext error on file \"%s\": ERR=%s\n"),
2047             jcr->last_fname, be.bstrerror());
2048       Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",  
2049             content, jcr->last_fname, be.bstrerror());
2050       return bacl_exit_error;
2051    }
2052
2053    /*
2054     * Restore the ACLs, but don't complain about links which really should
2055     * not have attributes, and the file it is linked to may not yet be restored.
2056     */
2057    if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
2058       berrno be;
2059
2060       switch (errno) {
2061       case ENOENT:
2062          actuallyfree(acls);
2063          return bacl_exit_ok;
2064       default:
2065          Mmsg2(jcr->errmsg,
2066                _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
2067                jcr->last_fname, be.bstrerror());
2068          Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
2069                content, jcr->last_fname, be.bstrerror());
2070          actuallyfree(acls);
2071          return bacl_exit_error;
2072       }
2073    }
2074    actuallyfree(acls);
2075    return bacl_exit_ok;
2076 }
2077 #endif /* HAVE_EXTENDED_ACL */
2078
2079 /*
2080  * For this OS setup the build and parse function pointer to the OS specific functions.
2081  */
2082 static bacl_exit_code (*os_build_acl_streams)
2083                       (JCR *jcr, FF_PKT *ff_pkt) =
2084                       solaris_build_acl_streams;
2085 static bacl_exit_code (*os_parse_acl_streams)
2086                       (JCR *jcr, int stream, char *content, uint32_t content_length) =
2087                       solaris_parse_acl_streams;
2088
2089 #endif /* HAVE_SUN_OS */
2090 #endif /* HAVE_ACL */
2091
2092 #if defined(HAVE_AFS_ACL)
2093
2094 #if defined(HAVE_AFS_AFSINT_H) && defined(HAVE_AFS_VENUS_H)
2095 #include <afs/afsint.h>
2096 #include <afs/venus.h>
2097 #else
2098 #error "configure failed to detect availability of afs/afsint.h and/or afs/venus.h"
2099 #endif
2100
2101 /**
2102  * External references to functions in the libsys library function not in current include files.
2103  */
2104 extern "C" {
2105 long pioctl(char *pathp, long opcode, struct ViceIoctl *blobp, int follow);
2106 }
2107
2108 static bacl_exit_code afs_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
2109 {
2110    int error;
2111    struct ViceIoctl vip;
2112    char acl_text[BUFSIZ];
2113
2114    /*
2115     * AFS ACLs can only be set on a directory, so no need to try to
2116     * request them for anything other then that.
2117     */
2118    if (ff_pkt->type != FT_DIREND) {
2119       return bacl_exit_ok;
2120    }
2121
2122    vip.in = NULL;
2123    vip.in_size = 0;
2124    vip.out = acl_text;
2125    vip.out_size = sizeof(acl_text);
2126    memset((caddr_t)acl_text, 0, sizeof(acl_text));
2127
2128    if ((error = pioctl(jcr->last_fname, VIOCGETAL, &vip, 0)) < 0) {
2129       berrno be;
2130
2131       Mmsg2(jcr->errmsg,
2132             _("pioctl VIOCGETAL error on file \"%s\": ERR=%s\n"),
2133             jcr->last_fname, be.bstrerror());
2134       Dmsg2(100, "pioctl VIOCGETAL error file=%s ERR=%s\n",
2135             jcr->last_fname, be.bstrerror());
2136       return bacl_exit_error;
2137    }
2138    jcr->acl_data->u.build->content_length =
2139    pm_strcpy(jcr->acl_data->u.build->content, acl_text);
2140    return send_acl_stream(jcr, STREAM_ACL_AFS_TEXT);
2141 }
2142
2143 static bacl_exit_code afs_parse_acl_stream(JCR *jcr,
2144                                            int stream,
2145                                            char *content,
2146                                            uint32_t content_length)
2147 {
2148    int error;
2149    struct ViceIoctl vip;
2150
2151    vip.in = content;
2152    vip.in_size = content_length;
2153    vip.out = NULL;
2154    vip.out_size = 0;
2155
2156    if ((error = pioctl(jcr->last_fname, VIOCSETAL, &vip, 0)) < 0) {
2157       berrno be;
2158
2159       Mmsg2(jcr->errmsg,
2160             _("pioctl VIOCSETAL error on file \"%s\": ERR=%s\n"),
2161             jcr->last_fname, be.bstrerror());
2162       Dmsg2(100, "pioctl VIOCSETAL error file=%s ERR=%s\n",
2163             jcr->last_fname, be.bstrerror());
2164
2165       return bacl_exit_error;
2166    }
2167    return bacl_exit_ok;
2168 }
2169 #endif /* HAVE_AFS_ACL */
2170
2171 /**
2172  * Entry points when compiled with support for ACLs on a supported platform.
2173  */
2174
2175 /**
2176  * Read and send an ACL for the last encountered file.
2177  */
2178 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
2179 {
2180    /*
2181     * See if we are changing from one device to an other.
2182     * We save the current device we are scanning and compare
2183     * it with the current st_dev in the last stat performed on
2184     * the file we are currently storing.
2185     */
2186    if (jcr->acl_data->current_dev != ff_pkt->statp.st_dev) {
2187       /*
2188        * Reset the acl save flags.
2189        */
2190       jcr->acl_data->flags = 0;
2191
2192 #if defined(HAVE_AFS_ACL)
2193       /*
2194        * AFS is a non OS specific filesystem so see if this path is on an AFS filesystem
2195        * Set the BACL_FLAG_SAVE_AFS flag if it is. If not set the BACL_FLAG_SAVE_NATIVE flag.
2196        */
2197       if (fstype_equals(jcr->last_fname, "afs")) {
2198          jcr->acl_data->flags |= BACL_FLAG_SAVE_AFS;
2199       } else {
2200          jcr->acl_data->flags |= BACL_FLAG_SAVE_NATIVE;
2201       }
2202 #else
2203       jcr->acl_data->flags |= BACL_FLAG_SAVE_NATIVE;
2204 #endif
2205
2206       /*
2207        * Save that we started scanning a new filesystem.
2208        */
2209       jcr->acl_data->current_dev = ff_pkt->statp.st_dev;
2210    }
2211
2212 #if defined(HAVE_AFS_ACL)
2213    /*
2214     * See if the BACL_FLAG_SAVE_AFS flag is set which lets us know if we should
2215     * save AFS ACLs.
2216     */
2217    if (jcr->acl_data->flags & BACL_FLAG_SAVE_AFS) {
2218       return afs_build_acl_streams(jcr, ff_pkt);
2219    }
2220 #endif
2221 #if defined(HAVE_ACL)
2222    /*
2223     * See if the BACL_FLAG_SAVE_NATIVE flag is set which lets us know if we should
2224     * save native ACLs.
2225     */
2226    if (jcr->acl_data->flags & BACL_FLAG_SAVE_NATIVE) {
2227       /*
2228        * Call the appropriate function.
2229        */
2230       if (os_build_acl_streams) {
2231          return os_build_acl_streams(jcr, ff_pkt);
2232       }
2233    } else {
2234       return bacl_exit_ok;
2235    }
2236 #endif
2237    return bacl_exit_error;
2238 }
2239
2240 bacl_exit_code parse_acl_streams(JCR *jcr,
2241                                  int stream,
2242                                  char *content,
2243                                  uint32_t content_length)
2244 {
2245    int ret;
2246    struct stat st;
2247    unsigned int cnt;
2248
2249    /*
2250     * See if we are changing from one device to an other.
2251     * We save the current device we are restoring to and compare
2252     * it with the current st_dev in the last stat performed on
2253     * the file we are currently restoring.
2254     */
2255    ret = lstat(jcr->last_fname, &st);
2256    switch (ret) {
2257    case -1: {
2258       berrno be;
2259
2260       switch (errno) {
2261       case ENOENT:
2262          return bacl_exit_ok;
2263       default:
2264          Mmsg2(jcr->errmsg,
2265                _("Unable to stat file \"%s\": ERR=%s\n"),
2266                jcr->last_fname, be.bstrerror());
2267          Dmsg2(100, "Unable to stat file \"%s\": ERR=%s\n",
2268                jcr->last_fname, be.bstrerror());
2269          return bacl_exit_error;
2270       }
2271       break;
2272    }
2273    case 0:
2274       break;
2275    }
2276    if (jcr->acl_data->current_dev != st.st_dev) {
2277       /*
2278        * Reset the acl save flags.
2279        */
2280       jcr->acl_data->flags = 0;
2281
2282 #if defined(HAVE_AFS_ACL)
2283       /*
2284        * AFS is a non OS specific filesystem so see if this path is on an AFS filesystem
2285        * Set the BACL_FLAG_RESTORE_AFS flag if it is. If not set the BACL_FLAG_RETORE_NATIVE flag.
2286        */
2287       if (fstype_equals(jcr->last_fname, "afs")) {
2288          jcr->acl_data->flags |= BACL_FLAG_RESTORE_AFS;
2289       } else {
2290          jcr->acl_data->flags |= BACL_FLAG_RESTORE_NATIVE;
2291       }
2292 #else
2293       jcr->acl_data->flags |= BACL_FLAG_RESTORE_NATIVE;
2294 #endif
2295
2296       /*
2297        * Save that we started restoring to a new filesystem.
2298        */
2299       jcr->acl_data->current_dev = st.st_dev;
2300    }
2301
2302    switch (stream) {
2303 #if defined(HAVE_AFS_ACL)
2304    case STREAM_ACL_AFS_TEXT:
2305       if (jcr->acl_data->flags & BACL_FLAG_RESTORE_AFS) {
2306          return afs_parse_acl_stream(jcr, stream, content, content_length);
2307       } else {
2308          /*
2309           * Increment error count but don't log an error again for the same filesystem.
2310           */
2311          jcr->acl_data->u.parse->nr_errors++;
2312          return bacl_exit_ok;
2313       }
2314 #endif
2315 #if defined(HAVE_ACL)
2316    case STREAM_UNIX_ACCESS_ACL:
2317    case STREAM_UNIX_DEFAULT_ACL:
2318       /*
2319        * Handle legacy ACL streams.
2320        */
2321       if ((jcr->acl_data->flags & BACL_FLAG_RESTORE_NATIVE) && os_parse_acl_streams) {
2322          return os_parse_acl_streams(jcr, stream, content, content_length);
2323       } else {
2324          /*
2325           * Increment error count but don't log an error again for the same filesystem.
2326           */
2327          jcr->acl_data->u.parse->nr_errors++;
2328          return bacl_exit_ok;
2329       }
2330       break;
2331    default:
2332       if ((jcr->acl_data->flags & BACL_FLAG_RESTORE_NATIVE) && os_parse_acl_streams) {
2333          /*
2334           * Walk the os_access_acl_streams array with the supported Access ACL streams for this OS.
2335           */
2336          for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
2337             if (os_access_acl_streams[cnt] == stream) {
2338                return os_parse_acl_streams(jcr, stream, content, content_length);
2339             }
2340          }
2341          /*
2342           * Walk the os_default_acl_streams array with the supported Default ACL streams for this OS.
2343           */
2344          for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
2345             if (os_default_acl_streams[cnt] == stream) {
2346                return os_parse_acl_streams(jcr, stream, content, content_length);
2347             }
2348          }
2349       } else {
2350          /*
2351           * Increment error count but don't log an error again for the same filesystem.
2352           */
2353          jcr->acl_data->u.parse->nr_errors++;
2354          return bacl_exit_ok;
2355       }
2356       break;
2357 #else
2358    default:
2359       break;
2360 #endif
2361    }
2362    Qmsg2(jcr, M_WARNING, 0,
2363       _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
2364       jcr->last_fname, stream);
2365    return bacl_exit_error;
2366 }
2367 #endif