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