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