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