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