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