]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/acl.c
Add rudimentary support for saving AFS acls.
[bacula/bacula] / bacula / src / filed / acl.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2004-2012 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version three of the GNU Affero General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU Affero General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /**
29  * Functions to handle ACLs for bacula.
30  *
31  * Currently we support the following OSes:
32  *   - AIX (pre-5.3 and post 5.3 acls, acl_get and aclx_get interface)
33  *   - Darwin
34  *   - FreeBSD (POSIX and NFSv4/ZFS acls)
35  *   - HPUX
36  *   - IRIX
37  *   - Linux
38  *   - Solaris (POSIX and NFSv4/ZFS acls)
39  *   - Tru64
40  *
41  * Next to OS specific acls we support AFS acls using the pioctl interface.
42  *
43  * We handle two different types of ACLs: access and default ACLS.
44  * On most systems that support default ACLs they only apply to directories.
45  *
46  * On some systems (eg. linux and FreeBSD) we must obtain the two ACLs
47  * independently, while others (eg. Solaris) provide both in one call.
48  *
49  * The Filed saves ACLs in their native format and uses different streams
50  * for all different platforms. Currently we only allow ACLs to be restored
51  * which were saved in the native format of the platform they are extracted
52  * on. Later on we might add conversion functions for mapping from one
53  * platform to an other or allow restores of systems that use the same
54  * native format.
55  *
56  * Its also interesting to see what the exact format of acl text is on
57  * certain platforms and if they use they same encoding we might allow
58  * different platform streams to be decoded on an other similar platform.
59  *
60  *   Original written by Preben 'Peppe' Guldberg, December 2004
61  *   Major rewrite by Marco van Wieringen, November 2008
62  *   Major overhaul by Marco van Wieringen, January 2012
63  */
64   
65 #include "bacula.h"
66 #include "filed.h"
67   
68 #if !defined(HAVE_ACL) && !defined(HAVE_AFS_ACL)
69 /**
70  * Entry points when compiled without support for ACLs or on an unsupported platform.
71  */
72 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
73 {
74    return bacl_exit_fatal;
75 }
76
77 bacl_exit_code parse_acl_streams(JCR *jcr,
78                                  int stream,
79                                  char *content,
80                                  uint32_t content_length)
81 {
82    return bacl_exit_fatal;
83 }
84 #else
85 /**
86  * Send an ACL stream to the SD.
87  */
88 static bacl_exit_code send_acl_stream(JCR *jcr, int stream)
89 {
90    BSOCK *sd = jcr->store_bsock;
91    POOLMEM *msgsave;
92 #ifdef FD_NO_SEND_TEST
93    return bacl_exit_ok;
94 #endif
95
96    /*
97     * Sanity check
98     */
99    if (jcr->acl_data->u.build->content_length <= 0) {
100       return bacl_exit_ok;
101    }
102
103    /*
104     * Send header
105     */
106    if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
107       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
108             sd->bstrerror());
109       return bacl_exit_fatal;
110    }
111
112    /*
113     * Send the buffer to the storage deamon
114     */
115    Dmsg1(400, "Backing up ACL <%s>\n", jcr->acl_data->u.build->content);
116    msgsave = sd->msg;
117    sd->msg = jcr->acl_data->u.build->content;
118    sd->msglen = jcr->acl_data->u.build->content_length + 1;
119    if (!sd->send()) {
120       sd->msg = msgsave;
121       sd->msglen = 0;
122       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
123             sd->bstrerror());
124       return bacl_exit_fatal;
125    }
126
127    jcr->JobBytes += sd->msglen;
128    sd->msg = msgsave;
129    if (!sd->signal(BNET_EOD)) {
130       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
131             sd->bstrerror());
132       return bacl_exit_fatal;
133    }
134
135    Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
136    return bacl_exit_ok;
137 }
138
139 /*
140  * First the native ACLs.
141  */
142 #if defined(HAVE_ACL)
143 #if defined(HAVE_AIX_OS)
144
145 #if defined(HAVE_EXTENDED_ACL)
146
147 #include <sys/access.h>
148 #include <sys/acl.h>
149
150 static bool acl_is_trivial(struct acl *acl)
151 {
152    return (acl_last(acl) != acl->acl_ext ? false : true);
153 }
154
155 static bool acl_nfs4_is_trivial(nfs4_acl_int_t *acl)
156 {
157 #if 0
158    return (acl->aclEntryN > 0 ? false : true);
159 #else
160    int i;
161    int count = acl->aclEntryN;
162    nfs4_ace_int_t *ace;
163
164    for (i = 0; i < count; i++) {
165       ace = &acl->aclEntry[i];
166       if (!((ace->flags & ACE4_ID_SPECIAL) != 0 &&
167             (ace->aceWho.special_whoid == ACE4_WHO_OWNER ||
168              ace->aceWho.special_whoid == ACE4_WHO_GROUP ||
169              ace->aceWho.special_whoid == ACE4_WHO_EVERYONE) &&
170              ace->aceType == ACE4_ACCESS_ALLOWED_ACE_TYPE &&
171              ace->aceFlags == 0 &&
172             (ace->aceMask & ~(ACE4_READ_DATA |
173                               ACE4_LIST_DIRECTORY |
174                               ACE4_WRITE_DATA |
175                               ACE4_ADD_FILE |
176                               ACE4_EXECUTE)) == 0)) {
177          return false;
178       }
179    }
180    return true;
181 #endif
182 }
183
184 /*
185  * Define the supported ACL streams for this OS
186  */
187 static int os_access_acl_streams[3] = {
188    STREAM_ACL_AIX_TEXT,
189    STREAM_ACL_AIX_AIXC,
190    STREAM_ACL_AIX_NFS4
191 };
192 static int os_default_acl_streams[1] = {
193    -1
194 };
195
196 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
197 {
198    mode_t mode;
199    acl_type_t type;
200    size_t aclsize, acltxtsize;
201    bacl_exit_code retval = bacl_exit_error;
202    POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
203
204    /*
205     * First see how big the buffers should be.
206     */
207    memset(&type, 0, sizeof(acl_type_t));
208    type.u64 = ACL_ANY;
209    if (aclx_get(jcr->last_fname, GET_ACLINFO_ONLY, &type, NULL, &aclsize, &mode) < 0) {
210       berrno be;
211
212       switch (errno) {
213       case ENOENT:
214          retval = bacl_exit_ok;
215          goto bail_out;
216       case ENOSYS:
217          /*
218           * If the filesystem reports it doesn't support ACLs we clear the
219           * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
220           * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
221           * when we change from one filesystem to an other.
222           */
223          jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
224          retval = bacl_exit_ok;
225          goto bail_out;
226       default:
227          Mmsg2(jcr->errmsg,
228                _("aclx_get error on file \"%s\": ERR=%s\n"),
229                jcr->last_fname, be.bstrerror());
230          Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
231                jcr->last_fname, be.bstrerror());
232          goto bail_out;
233       }
234    }
235
236    /*
237     * Make sure the buffers are big enough.
238     */
239    aclbuf = check_pool_memory_size(aclbuf, aclsize + 1);
240
241    /*
242     * Retrieve the ACL info.
243     */
244    if (aclx_get(jcr->last_fname, 0, &type, aclbuf, &aclsize, &mode) < 0) {
245       berrno be;
246
247       switch (errno) {
248       case ENOENT:
249          retval = bacl_exit_ok;
250          goto bail_out;
251       default:
252          Mmsg2(jcr->errmsg,
253                _("aclx_get error on file \"%s\": ERR=%s\n"),
254                jcr->last_fname, be.bstrerror());
255          Dmsg2(100, "aclx_get error file=%s ERR=%s\n",
256                jcr->last_fname, be.bstrerror());
257          goto bail_out;
258       }
259    }
260
261    /*
262     * See if the acl is non trivial.
263     */
264    switch (type.u64) {
265    case ACL_AIXC:
266       if (acl_is_trivial((struct acl *)aclbuf)) {
267          retval = bacl_exit_ok;
268          goto bail_out;
269       }
270       break;
271    case ACL_NFS4:
272       if (acl_nfs4_is_trivial((nfs4_acl_int_t *)aclbuf)) {
273          retval = bacl_exit_ok;
274          goto bail_out;
275       }
276       break;
277    default:
278       Mmsg2(jcr->errmsg,
279             _("Unknown acl type encountered on file \"%s\": %ld\n"),
280             jcr->last_fname, type.u64);
281       Dmsg2(100, "Unknown acl type encountered on file \"%s\": %ld\n",
282             jcr->last_fname, type.u64);
283       goto bail_out;
284    }
285
286    /*
287     * We have a non-trivial acl lets convert it into some ASCII form.
288     */
289    acltxtsize = sizeof_pool_memory(jcr->acl_data->u.build->content);
290    if (aclx_printStr(jcr->acl_data->u.build->content, &acltxtsize, aclbuf,
291                      aclsize, type, jcr->last_fname, 0) < 0) {
292       switch (errno) {
293       case ENOSPC:
294          /*
295           * Our buffer is not big enough, acltxtsize should be updated with the value
296           * the aclx_printStr really need. So we increase the buffer and try again.
297           */
298          jcr->acl_data->u.build->content =
299          check_pool_memory_size(jcr->acl_data->u.build->content, acltxtsize + 1);
300          if (aclx_printStr(jcr->acl_data->u.build->content, &acltxtsize, aclbuf,
301                            aclsize, type, jcr->last_fname, 0) < 0) {
302             Mmsg1(jcr->errmsg,
303                   _("Failed to convert acl into text on file \"%s\"\n"),
304                   jcr->last_fname);
305             Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
306                   jcr->last_fname, type.u64);
307             goto bail_out;
308          }
309          break;
310       default:
311          Mmsg1(jcr->errmsg,
312                _("Failed to convert acl into text on file \"%s\"\n"),
313                jcr->last_fname);
314          Dmsg2(100, "Failed to convert acl into text on file \"%s\": %ld\n",
315                jcr->last_fname, type.u64);
316          goto bail_out;
317       }
318    }
319
320    jcr->acl_data->u.build->content_length = strlen(jcr->acl_data->u.build->content) + 1;
321    switch (type.u64) {
322    case ACL_AIXC:
323       retval = send_acl_stream(jcr, STREAM_ACL_AIX_AIXC);
324    case ACL_NFS4:
325       retval = send_acl_stream(jcr, STREAM_ACL_AIX_NFS4);
326    }
327
328 bail_out:
329    free_pool_memory(aclbuf);
330
331    return retval;
332 }
333
334 /*
335  * See if a specific type of ACLs are supported on the filesystem
336  * the file is located on.
337  */
338 static inline bool aix_query_acl_support(JCR *jcr,
339                                          uint64_t aclType,
340                                          acl_type_t *pacl_type_info)
341 {
342    unsigned int i;
343    acl_types_list_t acl_type_list;
344    size_t acl_type_list_len = sizeof(acl_types_list_t);
345
346    memset(&acl_type_list, 0, sizeof(acl_type_list));
347    if (aclx_gettypes(jcr->last_fname, &acl_type_list, &acl_type_list_len)) {
348       return false;
349    }
350
351    for (i = 0; i < acl_type_list.num_entries; i++) {
352       if (acl_type_list.entries[i].u64 == aclType) {
353          memcpy(pacl_type_info, acl_type_list.entries + i, sizeof(acl_type_t));
354          return true;
355       }
356    }
357    return false;
358 }
359
360 static bacl_exit_code aix_parse_acl_streams(JCR *jcr,
361                                             int stream,
362                                             char *content,
363                                             uint32_t content_length)
364 {
365    int cnt;
366    acl_type_t type;
367    size_t aclsize;
368    bacl_exit_code retval = bacl_exit_error;
369    POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
370
371    switch (stream) {
372    case STREAM_ACL_AIX_TEXT:
373       /*
374        * Handle the old stream using the old system call for now.
375        */
376       if (acl_put(jcr->last_fname, content, 0) != 0) {
377          retval = bacl_exit_error;
378          goto bail_out;
379       }
380       retval = bacl_exit_ok;
381       goto bail_out;
382    case STREAM_ACL_AIX_AIXC:
383       if (!aix_query_acl_support(jcr, ACL_AIXC, &type)) {
384          Mmsg1(jcr->errmsg,
385                _("Trying to restore POSIX acl on file \"%s\" on filesystem without AIXC acl support\n"),
386                jcr->last_fname);
387          goto bail_out;
388       }
389       break;
390    case STREAM_ACL_AIX_NFS4:
391       if (!aix_query_acl_support(jcr, ACL_NFS4, &type)) {
392          Mmsg1(jcr->errmsg,
393                _("Trying to restore NFSv4 acl on file \"%s\" on filesystem without NFS4 acl support\n"),
394                jcr->last_fname);
395          goto bail_out;
396       }
397       break;
398    default:
399       goto bail_out;
400    } /* end switch (stream) */
401
402    /*
403     * Set the acl buffer to an initial size. For now we set it
404     * to the same size as the ASCII representation.
405     */
406    aclbuf = check_pool_memory_size(aclbuf, content_length);
407    aclsize = content_length;
408    if (aclx_scanStr(content, aclbuf, &aclsize, type) < 0) {
409       berrno be;
410
411       switch (errno) {
412       case ENOSPC:
413          /*
414           * The buffer isn't big enough. The man page doesn't say that aclsize
415           * is updated to the needed size as what is done with aclx_printStr.
416           * So for now we try to increase the buffer a maximum of 3 times
417           * and retry the conversion.
418           */
419          for (cnt = 0; cnt < 3; cnt++) {
420             aclsize = 2 * aclsize;
421             aclbuf = check_pool_memory_size(aclbuf, aclsize);
422
423             if (aclx_scanStr(content, aclbuf, &aclsize, type) == 0) {
424                break;
425             }
426
427             /*
428              * See why we failed this time, ENOSPC retry if max retries not met,
429              * otherwise abort.
430              */
431             switch (errno) {
432             case ENOSPC:
433                if (cnt < 3) {
434                   continue;
435                }
436                /*
437                 * FALLTHROUGH
438                 */
439             default:
440                Mmsg2(jcr->errmsg,
441                      _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
442                      jcr->last_fname, be.bstrerror(errno));
443                Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
444                      jcr->last_fname, be.bstrerror());
445                goto bail_out;
446             }
447          }
448          break;
449       default:
450          Mmsg2(jcr->errmsg,
451                _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
452                jcr->last_fname, be.bstrerror());
453          Dmsg2(100, "aclx_scanStr error file=%s ERR=%s\n",
454                jcr->last_fname, be.bstrerror());
455       }
456    }
457
458    if (aclx_put(jcr->last_fname, SET_ACL, type, aclbuf, aclsize, 0) < 0) {
459       berrno be;
460
461       switch (errno) {
462       case ENOENT:
463          retval = bacl_exit_ok;
464          goto bail_out;
465       case ENOSYS:
466          /*
467           * If the filesystem reports it doesn't support ACLs we clear the
468           * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
469           * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
470           * when we change from one filesystem to an other.
471           */
472          jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
473          retval = bacl_exit_ok;
474          goto bail_out;
475       default:
476          Mmsg2(jcr->errmsg,
477                _("aclx_put error on file \"%s\": ERR=%s\n"),
478                jcr->last_fname, be.bstrerror());
479          Dmsg2(100, "aclx_put error file=%s ERR=%s\n",
480                jcr->last_fname, be.bstrerror());
481          goto bail_out;
482       }
483    }
484
485    retval = bacl_exit_ok;
486
487 bail_out:
488    free_pool_memory(aclbuf);
489
490    return retval;
491 }
492
493 #else /* HAVE_EXTENDED_ACL */
494
495 #include <sys/access.h>
496
497 /*
498  * Define the supported ACL streams for this OS
499  */
500 static int os_access_acl_streams[1] = {
501    STREAM_ACL_AIX_TEXT
502 };
503 static int os_default_acl_streams[1] = {
504    -1
505 };
506
507 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
508 {
509    char *acl_text;
510
511    if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
512       jcr->acl_data->u.build->content_length =
513       pm_strcpy(jcr->acl_data->u.build->content, acl_text);
514       actuallyfree(acl_text);
515       return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT);
516    }
517    return bacl_exit_error;
518 }
519
520 static bacl_exit_code aix_parse_acl_streams(JCR *jcr,
521                                             int stream,
522                                             char *content,
523                                             uint32_t content_length)
524 {
525    if (acl_put(jcr->last_fname, content, 0) != 0) {
526       return bacl_exit_error;
527    }
528    return bacl_exit_ok;
529 }
530 #endif /* HAVE_EXTENDED_ACL */
531
532 /*
533  * For this OS setup the build and parse function pointer to the OS specific functions.
534  */
535 static bacl_exit_code (*os_build_acl_streams)
536                       (JCR *jcr, FF_PKT *ff_pkt) =
537                       aix_build_acl_streams;
538 static bacl_exit_code (*os_parse_acl_streams)
539                       (JCR *jcr, int stream, char *content, uint32_t content_length) =
540                       aix_parse_acl_streams;
541
542 #elif defined(HAVE_DARWIN_OS) || \
543       defined(HAVE_FREEBSD_OS) || \
544       defined(HAVE_IRIX_OS) || \
545       defined(HAVE_OSF1_OS) || \
546       defined(HAVE_LINUX_OS)
547
548 #include <sys/types.h>
549
550 #ifdef HAVE_SYS_ACL_H
551 #include <sys/acl.h>
552 #else
553 #error "configure failed to detect availability of sys/acl.h"
554 #endif
555
556 /*
557  * On IRIX we can get shortened ACLs
558  */
559 #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
560 #define acl_to_text(acl,len)     acl_to_short_text((acl), (len))
561 #endif
562
563 /*
564  * On Linux we can get numeric and/or shorted ACLs
565  */
566 #if defined(HAVE_LINUX_OS)
567 #if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
568 #define BACL_ALTERNATE_TEXT            (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
569 #elif defined(BACL_WANT_SHORT_ACLS)
570 #define BACL_ALTERNATE_TEXT            TEXT_ABBREVIATE
571 #elif defined(BACL_WANT_NUMERIC_IDS)
572 #define BACL_ALTERNATE_TEXT            TEXT_NUMERIC_IDS
573 #endif
574 #ifdef BACL_ALTERNATE_TEXT
575 #include <acl/libacl.h>
576 #define acl_to_text(acl,len)     (acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
577 #endif
578 #endif
579
580 /*
581  * On FreeBSD we can get numeric ACLs
582  */
583 #if defined(HAVE_FREEBSD_OS)
584 #if defined(BACL_WANT_NUMERIC_IDS)
585 #define BACL_ALTERNATE_TEXT            ACL_TEXT_NUMERIC_IDS
586 #endif
587 #ifdef BACL_ALTERNATE_TEXT
588 #define acl_to_text(acl,len)     (acl_to_text_np((acl), (len), BACL_ALTERNATE_TEXT))
589 #endif
590 #endif
591
592 /*
593  * Some generic functions used by multiple OSes.
594  */
595 static acl_type_t bac_to_os_acltype(bacl_type acltype)
596 {
597    acl_type_t ostype;
598
599    switch (acltype) {
600    case BACL_TYPE_ACCESS:
601       ostype = ACL_TYPE_ACCESS;
602       break;
603    case BACL_TYPE_DEFAULT:
604       ostype = ACL_TYPE_DEFAULT;
605       break;
606 #ifdef HAVE_ACL_TYPE_NFS4
607       /*
608        * FreeBSD has an additional acl type named ACL_TYPE_NFS4.
609        */
610    case BACL_TYPE_NFS4:
611       ostype = ACL_TYPE_NFS4;
612       break;
613 #endif
614 #ifdef HAVE_ACL_TYPE_DEFAULT_DIR
615    case BACL_TYPE_DEFAULT_DIR:
616       /*
617        * TRU64 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
618        */
619       ostype = ACL_TYPE_DEFAULT_DIR;
620       break;
621 #endif
622 #ifdef HAVE_ACL_TYPE_EXTENDED
623    case BACL_TYPE_EXTENDED:
624       /*
625        * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
626        */
627       ostype = ACL_TYPE_EXTENDED;
628       break;
629 #endif
630    default:
631       /*
632        * This should never happen, as the per OS version function only tries acl
633        * types supported on a certain platform.
634        */
635       ostype = (acl_type_t)ACL_TYPE_NONE;
636       break;
637    }
638    return ostype;
639 }
640
641 static int acl_count_entries(acl_t acl)
642 {
643    int count = 0;
644 #if defined(HAVE_FREEBSD_OS) || \
645     defined(HAVE_LINUX_OS)
646    acl_entry_t ace;
647    int entry_available;
648
649    entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
650    while (entry_available == 1) {
651       count++;
652       entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
653    }
654 #elif defined(HAVE_IRIX_OS)
655    count = acl->acl_cnt;
656 #elif defined(HAVE_OSF1_OS)
657    count = acl->acl_num;
658 #elif defined(HAVE_DARWIN_OS)
659    acl_entry_t ace;
660    int entry_available;
661
662    entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
663    while (entry_available == 0) {
664       count++;
665       entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
666    }
667 #endif
668    return count;
669 }
670
671 #if !defined(HAVE_DARWIN_OS)
672 /*
673  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
674  * There is no need to store those acls as we already store the stat bits too.
675  */
676 static bool acl_is_trivial(acl_t acl)
677 {
678   /*
679    * acl is trivial if it has only the following entries:
680    * "user::",
681    * "group::",
682    * "other::"
683    */
684    acl_entry_t ace;
685    acl_tag_t tag;
686 #if defined(HAVE_FREEBSD_OS) || \
687     defined(HAVE_LINUX_OS)
688    int entry_available;
689
690    entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
691    while (entry_available == 1) {
692       /*
693        * Get the tag type of this acl entry.
694        * If we fail to get the tagtype we call the acl non-trivial.
695        */
696       if (acl_get_tag_type(ace, &tag) < 0)
697          return true;
698       /*
699        * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
700        */
701       if (tag != ACL_USER_OBJ &&
702           tag != ACL_GROUP_OBJ &&
703           tag != ACL_OTHER)
704          return false;
705       entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
706    }
707    return true;
708 #elif defined(HAVE_IRIX_OS)
709    int n;
710
711    for (n = 0; n < acl->acl_cnt; n++) {
712       ace = &acl->acl_entry[n];
713       tag = ace->ae_tag;
714
715       /*
716        * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
717        */
718       if (tag != ACL_USER_OBJ &&
719           tag != ACL_GROUP_OBJ &&
720           tag != ACL_OTHER_OBJ)
721          return false;
722    }
723    return true;
724 #elif defined(HAVE_OSF1_OS)
725    int count;
726
727    ace = acl->acl_first;
728    count = acl->acl_num;
729
730    while (count > 0) {
731       tag = ace->entry->acl_type;
732       /*
733        * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
734        */
735       if (tag != ACL_USER_OBJ &&
736           tag != ACL_GROUP_OBJ &&
737           tag != ACL_OTHER)
738          return false;
739       /*
740        * On Tru64, perm can also contain non-standard bits such as
741        * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
742        */
743       if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
744          return false;
745       ace = ace->next;
746       count--;
747    }
748    return true;
749 #endif
750 }
751 #endif
752
753 /**
754  * Generic wrapper around acl_get_file call.
755  */
756 static bacl_exit_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
757 {
758    acl_t acl;
759    acl_type_t ostype;
760    char *acl_text;
761    bacl_exit_code retval = bacl_exit_ok;
762
763    ostype = bac_to_os_acltype(acltype);
764    acl = acl_get_file(jcr->last_fname, ostype);
765    if (acl) {
766       /**
767        * From observation, IRIX's acl_get_file() seems to return a
768        * non-NULL acl with a count field of -1 when a file has no ACL
769        * defined, while IRIX's acl_to_text() returns NULL when presented
770        * with such an ACL. 
771        *
772        * For all other implmentations we check if there are more then
773        * zero entries in the acl returned.
774        */
775       if (acl_count_entries(acl) <= 0) {
776          goto bail_out;
777       }
778
779       /*
780        * Make sure this is not just a trivial ACL.
781        */
782 #if !defined(HAVE_DARWIN_OS)
783       if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
784          /*
785           * The ACLs simply reflect the (already known) standard permissions
786           * So we don't send an ACL stream to the SD.
787           */
788          goto bail_out;
789       }
790 #endif
791 #if defined(HAVE_FREEBSD_OS) && defined(_PC_ACL_NFS4)
792       if (acltype == BACL_TYPE_NFS4) {
793          int trivial;
794          if (acl_is_trivial_np(acl, &trivial) == 0) {
795             if (trivial == 1) {
796                /*
797                 * The ACLs simply reflect the (already known) standard permissions
798                 * So we don't send an ACL stream to the SD.
799                 */
800                goto bail_out;
801             }
802          }
803       }
804 #endif
805
806       /*
807        * Convert the internal acl representation into a text representation.
808        */
809       if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
810          jcr->acl_data->u.build->content_length =
811          pm_strcpy(jcr->acl_data->u.build->content, acl_text);
812          acl_free(acl);
813          acl_free(acl_text);
814          return bacl_exit_ok;
815       }
816
817       berrno be;
818       Mmsg2(jcr->errmsg,
819             _("acl_to_text error on file \"%s\": ERR=%s\n"),
820             jcr->last_fname, be.bstrerror());
821       Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",  
822             jcr->last_fname, be.bstrerror());
823
824       retval = bacl_exit_error;
825       goto bail_out;
826    } else {
827       berrno be;
828
829       /*
830        * Handle errors gracefully.
831        */
832       switch (errno) {
833 #if defined(BACL_ENOTSUP)
834       case BACL_ENOTSUP:
835          /*
836           * If the filesystem reports it doesn't support ACLs we clear the
837           * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
838           * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
839           * when we change from one filesystem to an other.
840           */
841          jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
842          goto bail_out;
843 #endif
844       case ENOENT:
845          goto bail_out;
846       default:
847          /* Some real error */
848          Mmsg2(jcr->errmsg,
849                _("acl_get_file error on file \"%s\": ERR=%s\n"),
850                jcr->last_fname, be.bstrerror());
851          Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",  
852                jcr->last_fname, be.bstrerror());
853
854          retval = bacl_exit_error;
855          goto bail_out;
856       }
857    }
858
859 bail_out:
860    if (acl) {
861       acl_free(acl);
862    }
863    pm_strcpy(jcr->acl_data->u.build->content, "");
864    jcr->acl_data->u.build->content_length = 0;
865    return retval;
866 }
867
868 /**
869  * Generic wrapper around acl_set_file call.
870  */
871 static bacl_exit_code generic_set_acl_on_os(JCR *jcr,
872                                             bacl_type acltype,
873                                             char *content,
874                                             uint32_t content_length)
875 {
876    acl_t acl;
877    acl_type_t ostype;
878
879    /*
880     * If we get empty default ACLs, clear ACLs now
881     */
882    ostype = bac_to_os_acltype(acltype);
883    if (ostype == ACL_TYPE_DEFAULT && strlen(content) == 0) {
884       if (acl_delete_def_file(jcr->last_fname) == 0) {
885          return bacl_exit_ok;
886       }
887       berrno be;
888
889       switch (errno) {
890       case ENOENT:
891          return bacl_exit_ok;
892 #if defined(BACL_ENOTSUP)
893       case BACL_ENOTSUP:
894          /*
895           * If the filesystem reports it doesn't support ACLs we clear the
896           * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
897           * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
898           * when we change from one filesystem to an other.
899           */
900          jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
901          Mmsg1(jcr->errmsg,
902                _("acl_delete_def_file error on file \"%s\": filesystem doesn't support ACLs\n"),
903                jcr->last_fname);
904          return bacl_exit_error;
905 #endif
906       default:
907          Mmsg2(jcr->errmsg,
908                _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
909                jcr->last_fname, be.bstrerror());
910          return bacl_exit_error;
911       }
912    }
913
914    acl = acl_from_text(content);
915    if (acl == NULL) {
916       berrno be;
917
918       Mmsg2(jcr->errmsg,
919             _("acl_from_text error on file \"%s\": ERR=%s\n"),
920             jcr->last_fname, be.bstrerror());
921       Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",  
922             content, jcr->last_fname, be.bstrerror());
923       return bacl_exit_error;
924    }
925
926 #ifndef HAVE_FREEBSD_OS
927    /**
928     * FreeBSD always fails acl_valid() - at least on valid input...
929     * As it does the right thing, given valid input, just ignore acl_valid().
930     */
931    if (acl_valid(acl) != 0) {
932       berrno be;
933
934       Mmsg2(jcr->errmsg,
935             _("acl_valid error on file \"%s\": ERR=%s\n"),
936             jcr->last_fname, be.bstrerror());
937       Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",  
938             content, jcr->last_fname, be.bstrerror());
939       acl_free(acl);
940       return bacl_exit_error;
941    }
942 #endif
943
944    /**
945     * Restore the ACLs, but don't complain about links which really should
946     * not have attributes, and the file it is linked to may not yet be restored.
947     * This is only true for the old acl streams as in the new implementation we
948     * don't save acls of symlinks (which cannot have acls anyhow)
949     */
950    if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
951       berrno be;
952
953       switch (errno) {
954       case ENOENT:
955          acl_free(acl);
956          return bacl_exit_ok;
957 #if defined(BACL_ENOTSUP)
958       case BACL_ENOTSUP:
959          /*
960           * If the filesystem reports it doesn't support ACLs we clear the
961           * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
962           * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
963           * when we change from one filesystem to an other.
964           */
965          jcr->acl_data->flags &= ~BACL_FLAG_RESTORE_NATIVE;
966          Mmsg1(jcr->errmsg,
967                _("acl_set_file error on file \"%s\": filesystem doesn't support ACLs\n"),
968                jcr->last_fname);
969          Dmsg2(100, "acl_set_file error acl=%s file=%s filesystem doesn't support ACLs\n",
970                content, jcr->last_fname);
971          acl_free(acl);
972          return bacl_exit_error;
973 #endif
974       default:
975          Mmsg2(jcr->errmsg,
976                _("acl_set_file error on file \"%s\": ERR=%s\n"),
977                jcr->last_fname, be.bstrerror());
978          Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
979                content, jcr->last_fname, be.bstrerror());
980          acl_free(acl);
981          return bacl_exit_error;
982       }
983    }
984    acl_free(acl);
985    return bacl_exit_ok;
986 }
987
988 /**
989  * OS specific functions for handling different types of acl streams.
990  */
991 #if defined(HAVE_DARWIN_OS)
992 /**
993  * Define the supported ACL streams for this OS
994  */
995 static int os_access_acl_streams[1] = {
996    STREAM_ACL_DARWIN_ACCESS_ACL
997 };
998 static int os_default_acl_streams[1] = {
999    -1
1000 };
1001
1002 static bacl_exit_code darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1003 {
1004 #if defined(HAVE_ACL_TYPE_EXTENDED)
1005    /**
1006     * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
1007     * and acl_get_file (name, ACL_TYPE_DEFAULT)
1008     * always return NULL / EINVAL.  There is no point in making
1009     * these two useless calls.  The real ACL is retrieved through
1010     * acl_get_file (name, ACL_TYPE_EXTENDED).
1011     *
1012     * Read access ACLs for files, dirs and links
1013     */
1014    if (generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED) == bacl_exit_fatal)
1015       return bacl_exit_fatal;
1016 #else
1017    /**
1018     * Read access ACLs for files, dirs and links
1019     */
1020    if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1021       return bacl_exit_fatal;
1022 #endif
1023
1024    if (jcr->acl_data->u.build->content_length > 0) {
1025       return send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL);
1026    }
1027    return bacl_exit_ok;
1028 }
1029
1030 static bacl_exit_code darwin_parse_acl_streams(JCR *jcr,
1031                                                int stream,
1032                                                char *content,
1033                                                uint32_t content_length)
1034 {
1035 #if defined(HAVE_ACL_TYPE_EXTENDED)
1036       return generic_set_acl_on_os(jcr, BACL_TYPE_EXTENDED, content, content_length);
1037 #else
1038       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1039 #endif
1040 }
1041
1042 /*
1043  * For this OS setup the build and parse function pointer to the OS specific functions.
1044  */
1045 static bacl_exit_code (*os_build_acl_streams)
1046                       (JCR *jcr, FF_PKT *ff_pkt) =
1047                       darwin_build_acl_streams;
1048 static bacl_exit_code (*os_parse_acl_streams)
1049                       (JCR *jcr, int stream, char *content, uint32_t content_length) =
1050                       darwin_parse_acl_streams;
1051
1052 #elif defined(HAVE_FREEBSD_OS)
1053 /*
1054  * Define the supported ACL streams for these OSes
1055  */
1056 static int os_access_acl_streams[2] = {
1057    STREAM_ACL_FREEBSD_ACCESS_ACL,
1058    STREAM_ACL_FREEBSD_NFS4_ACL
1059 };
1060 static int os_default_acl_streams[1] = {
1061    STREAM_ACL_FREEBSD_DEFAULT_ACL
1062 };
1063
1064 static bacl_exit_code freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1065 {
1066    int acl_enabled = 0;
1067    bacl_type acltype = BACL_TYPE_NONE;
1068
1069 #if defined(_PC_ACL_NFS4)
1070    /*
1071     * See if filesystem supports NFS4 acls.
1072     */
1073    acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
1074    switch (acl_enabled) {
1075    case -1: {
1076       berrno be;
1077
1078       switch (errno) {
1079       case ENOENT:
1080          return bacl_exit_ok;
1081       default:
1082          Mmsg2(jcr->errmsg,
1083                _("pathconf error on file \"%s\": ERR=%s\n"),
1084                jcr->last_fname, be.bstrerror());
1085          Dmsg2(100, "pathconf error file=%s ERR=%s\n",
1086                jcr->last_fname, be.bstrerror());
1087          return bacl_exit_error;
1088       }
1089    }
1090    case 0:
1091       break;
1092    default:
1093       acltype = BACL_TYPE_NFS4;
1094       break;
1095    }
1096 #endif
1097
1098    if (acl_enabled == 0) {
1099       /*
1100        * See if filesystem supports POSIX acls.
1101        */
1102       acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
1103       switch (acl_enabled) {
1104       case -1: {
1105          berrno be;
1106
1107          switch (errno) {
1108          case ENOENT:
1109             return bacl_exit_ok;
1110          default:
1111             Mmsg2(jcr->errmsg,
1112                   _("pathconf error on file \"%s\": ERR=%s\n"),
1113                   jcr->last_fname, be.bstrerror());
1114             Dmsg2(100, "pathconf error file=%s ERR=%s\n",
1115                   jcr->last_fname, be.bstrerror());
1116             return bacl_exit_error;
1117          }
1118       }
1119       case 0:
1120          break;
1121       default:
1122          acltype = BACL_TYPE_ACCESS;
1123          break;
1124       }
1125    }
1126
1127    /*
1128     * If the filesystem reports it doesn't support ACLs we clear the
1129     * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1130     * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1131     * when we change from one filesystem to an other.
1132     */
1133    if (acl_enabled == 0) {
1134       jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1135       pm_strcpy(jcr->acl_data->u.build->content, "");
1136       jcr->acl_data->u.build->content_length = 0;
1137       return bacl_exit_ok;
1138    }
1139
1140    /*
1141     * Based on the supported ACLs retrieve and store them.
1142     */
1143    switch (acltype) {
1144    case BACL_TYPE_NFS4:
1145       /*
1146        * Read NFS4 ACLs for files, dirs and links
1147        */
1148       if (generic_get_acl_from_os(jcr, BACL_TYPE_NFS4) == bacl_exit_fatal)
1149          return bacl_exit_fatal;
1150
1151       if (jcr->acl_data->u.build->content_length > 0) {
1152          if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_NFS4_ACL) == bacl_exit_fatal)
1153             return bacl_exit_fatal;
1154       }
1155       break;
1156    case BACL_TYPE_ACCESS:
1157       /*
1158        * Read access ACLs for files, dirs and links
1159        */
1160       if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1161          return bacl_exit_fatal;
1162
1163       if (jcr->acl_data->u.build->content_length > 0) {
1164          if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_ACCESS_ACL) == bacl_exit_fatal)
1165             return bacl_exit_fatal;
1166       }
1167
1168       /*
1169        * Directories can have default ACLs too
1170        */
1171       if (ff_pkt->type == FT_DIREND) {
1172          if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
1173             return bacl_exit_fatal;
1174          if (jcr->acl_data->u.build->content_length > 0) {
1175             if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_DEFAULT_ACL) == bacl_exit_fatal)
1176                return bacl_exit_fatal;
1177          }
1178       }
1179       break;
1180    default:
1181       break;
1182    }
1183
1184    return bacl_exit_ok;
1185 }
1186
1187 static bacl_exit_code freebsd_parse_acl_streams(JCR *jcr,
1188                                                 int stream,
1189                                                 char *content,
1190                                                 uint32_t content_length)
1191 {
1192    int acl_enabled = 0;
1193    const char *acl_type_name;
1194
1195    /*
1196     * First make sure the filesystem supports acls.
1197     */
1198    switch (stream) {
1199    case STREAM_UNIX_ACCESS_ACL:
1200    case STREAM_ACL_FREEBSD_ACCESS_ACL:
1201    case STREAM_UNIX_DEFAULT_ACL:
1202    case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1203       acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
1204       acl_type_name = "POSIX";
1205       break;
1206    case STREAM_ACL_FREEBSD_NFS4_ACL:
1207 #if defined(_PC_ACL_NFS4)
1208       acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
1209 #endif
1210       acl_type_name = "NFS4";
1211       break;
1212    default:
1213       acl_type_name = "unknown";
1214       break;
1215    }
1216
1217    switch (acl_enabled) {
1218    case -1: {
1219       berrno be;
1220
1221       switch (errno) {
1222       case ENOENT:
1223          return bacl_exit_ok;
1224       default:
1225          Mmsg2(jcr->errmsg,
1226                _("pathconf error on file \"%s\": ERR=%s\n"),
1227                jcr->last_fname, be.bstrerror());
1228          Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1229                content, jcr->last_fname, be.bstrerror());
1230          return bacl_exit_error;
1231       }
1232    }
1233    case 0:
1234       /*
1235        * If the filesystem reports it doesn't support ACLs we clear the
1236        * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
1237        * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
1238        * when we change from one filesystem to an other.
1239        */
1240       jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1241       Mmsg2(jcr->errmsg,
1242             _("Trying to restore acl on file \"%s\" on filesystem without %s acl support\n"),
1243             jcr->last_fname, acl_type_name);
1244       return bacl_exit_error;
1245    default:
1246       break;
1247    }
1248
1249    /*
1250     * Restore the ACLs.
1251     */
1252    switch (stream) {
1253    case STREAM_UNIX_ACCESS_ACL:
1254    case STREAM_ACL_FREEBSD_ACCESS_ACL:
1255       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
1256    case STREAM_UNIX_DEFAULT_ACL:
1257    case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1258       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
1259    case STREAM_ACL_FREEBSD_NFS4_ACL:
1260       return generic_set_acl_on_os(jcr, BACL_TYPE_NFS4, content, content_length);
1261    default:
1262       break;
1263    }
1264    return bacl_exit_error;
1265 }
1266
1267 /*
1268  * For this OSes setup the build and parse function pointer to the OS specific functions.
1269  */
1270 static bacl_exit_code (*os_build_acl_streams)
1271                       (JCR *jcr, FF_PKT *ff_pkt) =
1272                       freebsd_build_acl_streams;
1273 static bacl_exit_code (*os_parse_acl_streams)
1274                       (JCR *jcr, int stream, char *content, uint32_t content_length) =
1275                       freebsd_parse_acl_streams;
1276
1277 #elif defined(HAVE_IRIX_OS) || \
1278       defined(HAVE_LINUX_OS)
1279 /*
1280  * Define the supported ACL streams for these OSes
1281  */
1282 #if defined(HAVE_IRIX_OS)
1283 static int os_access_acl_streams[1] = {
1284    STREAM_ACL_IRIX_ACCESS_ACL
1285 };
1286 static int os_default_acl_streams[1] = {
1287    STREAM_ACL_IRIX_DEFAULT_ACL
1288 };
1289 #elif defined(HAVE_LINUX_OS)
1290 static int os_access_acl_streams[1] = {
1291    STREAM_ACL_LINUX_ACCESS_ACL
1292 };
1293 static int os_default_acl_streams[1] = {
1294    STREAM_ACL_LINUX_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