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