]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/acl.c
First attempt at fixing bug #1735 where acls on OSX doesn't seem to reach the backup.
[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 #if !defined(HAVE_DARWIN_OS)
519 /**
520  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
521  * There is no need to store those acls as we already store the stat bits too.
522  */
523 static bool acl_is_trivial(acl_t acl)
524 {
525   /**
526    * acl is trivial if it has only the following entries:
527    * "user::",
528    * "group::",
529    * "other::"
530    */
531    acl_entry_t ace;
532    acl_tag_t tag;
533 #if defined(HAVE_FREEBSD_OS) || \
534     defined(HAVE_LINUX_OS)
535    int entry_available;
536
537    entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
538    while (entry_available == 1) {
539       /**
540        * Get the tag type of this acl entry.
541        * If we fail to get the tagtype we call the acl non-trivial.
542        */
543       if (acl_get_tag_type(ace, &tag) < 0)
544          return true;
545       /**
546        * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
547        */
548       if (tag != ACL_USER_OBJ &&
549           tag != ACL_GROUP_OBJ &&
550           tag != ACL_OTHER)
551          return false;
552       entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
553    }
554    return true;
555 #elif defined(HAVE_IRIX_OS)
556    int n;
557
558    for (n = 0; n < acl->acl_cnt; n++) {
559       ace = &acl->acl_entry[n];
560       tag = ace->ae_tag;
561
562       /**
563        * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
564        */
565       if (tag != ACL_USER_OBJ &&
566           tag != ACL_GROUP_OBJ &&
567           tag != ACL_OTHER_OBJ)
568          return false;
569    }
570    return true;
571 #elif defined(HAVE_OSF1_OS)
572    int count;
573
574    ace = acl->acl_first;
575    count = acl->acl_num;
576
577    while (count > 0) {
578       tag = ace->entry->acl_type;
579       /**
580        * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
581        */
582       if (tag != ACL_USER_OBJ &&
583           tag != ACL_GROUP_OBJ &&
584           tag != ACL_OTHER)
585          return false;
586       /**
587        * On Tru64, perm can also contain non-standard bits such as
588        * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
589        */
590       if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
591          return false;
592       ace = ace->next;
593       count--;
594    }
595    return true;
596 #endif
597 }
598 #endif
599
600 /**
601  * Generic wrapper around acl_get_file call.
602  */
603 static bacl_exit_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
604 {
605    acl_t acl;
606    acl_type_t ostype;
607    char *acl_text;
608    berrno be;
609
610    ostype = bac_to_os_acltype(acltype);
611    acl = acl_get_file(jcr->last_fname, ostype);
612    if (acl) {
613 #if defined(HAVE_IRIX_OS)
614       /**
615        * From observation, IRIX's acl_get_file() seems to return a
616        * non-NULL acl with a count field of -1 when a file has no ACL
617        * defined, while IRIX's acl_to_text() returns NULL when presented
618        * with such an ACL. 
619        *
620        * Checking the count in the acl structure before calling
621        * acl_to_text() lets us avoid error messages about files
622        * with no ACLs, without modifying the flow of the code used for 
623        * other operating systems, and it saves making some calls
624        * to acl_to_text() besides.
625        */
626       if (acl->acl_cnt <= 0) {
627          pm_strcpy(jcr->acl_data->content, "");
628          jcr->acl_data->content_length = 0;
629          acl_free(acl);
630          return bacl_exit_ok;
631       }
632 #endif
633
634       /**
635        * Make sure this is not just a trivial ACL.
636        */
637 #if !defined(HAVE_DARWIN_OS)
638       if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
639          /**
640           * The ACLs simply reflect the (already known) standard permissions
641           * So we don't send an ACL stream to the SD.
642           */
643          pm_strcpy(jcr->acl_data->content, "");
644          jcr->acl_data->content_length = 0;
645          acl_free(acl);
646          return bacl_exit_ok;
647       }
648 #endif
649 #if defined(HAVE_FREEBSD_OS) && defined(_PC_ACL_NFS4)
650       if (acltype == BACL_TYPE_NFS4) {
651          int trivial;
652          if (acl_is_trivial_np(acl, &trivial) == 0) {
653             if (trivial == 1) {
654                /**
655                 * The ACLs simply reflect the (already known) standard permissions
656                 * So we don't send an ACL stream to the SD.
657                 */
658                pm_strcpy(jcr->acl_data->content, "");
659                jcr->acl_data->content_length = 0;
660                acl_free(acl);
661                return bacl_exit_ok;
662             }
663          }
664       }
665 #endif
666
667       if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
668          jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
669          acl_free(acl);
670          acl_free(acl_text);
671          return bacl_exit_ok;
672       }
673
674       Mmsg2(jcr->errmsg, _("acl_to_text error on file \"%s\": ERR=%s\n"),
675             jcr->last_fname, be.bstrerror());
676       Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",  
677             jcr->last_fname, be.bstrerror());
678
679       pm_strcpy(jcr->acl_data->content, "");
680       jcr->acl_data->content_length = 0;
681       acl_free(acl);
682       return bacl_exit_error;
683    } else {
684       /**
685        * Handle errors gracefully.
686        */
687       switch (errno) {
688 #if defined(BACL_ENOTSUP)
689       case BACL_ENOTSUP:
690          /**
691           * If the filesystem reports it doesn't support ACLs we clear the
692           * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
693           * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
694           * when we change from one filesystem to an other.
695           */
696          jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
697          pm_strcpy(jcr->acl_data->content, "");
698          jcr->acl_data->content_length = 0;
699          return bacl_exit_ok;
700 #endif
701       case ENOENT:
702          pm_strcpy(jcr->acl_data->content, "");
703          jcr->acl_data->content_length = 0;
704          return bacl_exit_ok;
705       default:
706          /* Some real error */
707          Mmsg2(jcr->errmsg, _("acl_get_file error on file \"%s\": ERR=%s\n"),
708                jcr->last_fname, be.bstrerror());
709          Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",  
710                jcr->last_fname, be.bstrerror());
711
712          pm_strcpy(jcr->acl_data->content, "");
713          jcr->acl_data->content_length = 0;
714          return bacl_exit_error;
715       }
716    }
717 }
718
719 /**
720  * Generic wrapper around acl_set_file call.
721  */
722 static bacl_exit_code generic_set_acl_on_os(JCR *jcr, bacl_type acltype)
723 {
724    acl_t acl;
725    acl_type_t ostype;
726    berrno be;
727
728    /**
729     * If we get empty default ACLs, clear ACLs now
730     */
731    ostype = bac_to_os_acltype(acltype);
732    if (ostype == ACL_TYPE_DEFAULT && strlen(jcr->acl_data->content) == 0) {
733       if (acl_delete_def_file(jcr->last_fname) == 0) {
734          return bacl_exit_ok;
735       }
736       switch (errno) {
737       case ENOENT:
738          return bacl_exit_ok;
739       default:
740          Mmsg2(jcr->errmsg, _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
741                jcr->last_fname, be.bstrerror());
742          return bacl_exit_error;
743       }
744    }
745
746    acl = acl_from_text(jcr->acl_data->content);
747    if (acl == NULL) {
748       Mmsg2(jcr->errmsg, _("acl_from_text error on file \"%s\": ERR=%s\n"),
749             jcr->last_fname, be.bstrerror());
750       Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",  
751          jcr->acl_data->content, jcr->last_fname, be.bstrerror());
752       return bacl_exit_error;
753    }
754
755 #ifndef HAVE_FREEBSD_OS
756    /**
757     * FreeBSD always fails acl_valid() - at least on valid input...
758     * As it does the right thing, given valid input, just ignore acl_valid().
759     */
760    if (acl_valid(acl) != 0) {
761       Mmsg2(jcr->errmsg, _("acl_valid error on file \"%s\": ERR=%s\n"),
762             jcr->last_fname, be.bstrerror());
763       Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",  
764          jcr->acl_data->content, jcr->last_fname, be.bstrerror());
765       acl_free(acl);
766       return bacl_exit_error;
767    }
768 #endif
769
770    /**
771     * Restore the ACLs, but don't complain about links which really should
772     * not have attributes, and the file it is linked to may not yet be restored.
773     * This is only true for the old acl streams as in the new implementation we
774     * don't save acls of symlinks (which cannot have acls anyhow)
775     */
776    if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
777       switch (errno) {
778       case ENOENT:
779          acl_free(acl);
780          return bacl_exit_ok;
781       default:
782          Mmsg2(jcr->errmsg, _("acl_set_file error on file \"%s\": ERR=%s\n"),
783                jcr->last_fname, be.bstrerror());
784          Dmsg3(100, "acl_set_file 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    }
790    acl_free(acl);
791    return bacl_exit_ok;
792 }
793
794 /**
795  * OS specific functions for handling different types of acl streams.
796  */
797 #if defined(HAVE_DARWIN_OS)
798 /**
799  * Define the supported ACL streams for this OS
800  */
801 static int os_access_acl_streams[1] = { STREAM_ACL_DARWIN_ACCESS_ACL };
802 static int os_default_acl_streams[1] = { -1 };
803
804 static bacl_exit_code darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
805 {
806 #if defined(HAVE_ACL_TYPE_EXTENDED)
807    /**
808     * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
809     * and acl_get_file (name, ACL_TYPE_DEFAULT)
810     * always return NULL / EINVAL.  There is no point in making
811     * these two useless calls.  The real ACL is retrieved through
812     * acl_get_file (name, ACL_TYPE_EXTENDED).
813     *
814     * Read access ACLs for files, dirs and links
815     */
816    if (generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED) == bacl_exit_fatal)
817       return bacl_exit_fatal;
818 #else
819    /**
820     * Read access ACLs for files, dirs and links
821     */
822    if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
823       return bacl_exit_fatal;
824 #endif
825
826    if (jcr->acl_data->content_length > 0) {
827       return send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL);
828    }
829    return bacl_exit_ok;
830 }
831
832 static bacl_exit_code darwin_parse_acl_streams(JCR *jcr, int stream)
833 {
834 #if defined(HAVE_ACL_TYPE_EXTENDED)
835       return generic_set_acl_on_os(jcr, BACL_TYPE_EXTENDED);
836 #else
837       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
838 #endif
839 }
840
841 /**
842  * For this OS setup the build and parse function pointer to the OS specific functions.
843  */
844 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = darwin_build_acl_streams;
845 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = darwin_parse_acl_streams;
846
847 #elif defined(HAVE_FREEBSD_OS)
848 /**
849  * Define the supported ACL streams for these OSes
850  */
851 static int os_access_acl_streams[2] = { STREAM_ACL_FREEBSD_ACCESS_ACL, STREAM_ACL_FREEBSD_NFS4_ACL };
852 static int os_default_acl_streams[1] = { STREAM_ACL_FREEBSD_DEFAULT_ACL };
853
854 static bacl_exit_code freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
855 {
856    int acl_enabled = 0;
857    bacl_type acltype = BACL_TYPE_NONE;
858    berrno be;
859
860 #if defined(_PC_ACL_NFS4)
861    /**
862     * See if filesystem supports NFS4 acls.
863     */
864    acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
865    switch (acl_enabled) {
866    case -1:
867       switch (errno) {
868       case ENOENT:
869          return bacl_exit_ok;
870       default:
871          Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
872                jcr->last_fname, be.bstrerror());
873          Dmsg2(100, "pathconf error file=%s ERR=%s\n",
874                jcr->last_fname, be.bstrerror());
875          return bacl_exit_error;
876       }
877    case 0:
878       break;
879    default:
880       acltype = BACL_TYPE_NFS4;
881       break;
882    }
883 #endif
884
885    if (acl_enabled == 0) {
886       /**
887        * See if filesystem supports POSIX acls.
888        */
889       acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
890       switch (acl_enabled) {
891       case -1:
892          switch (errno) {
893          case ENOENT:
894             return bacl_exit_ok;
895          default:
896             Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
897                   jcr->last_fname, be.bstrerror());
898             Dmsg2(100, "pathconf error file=%s ERR=%s\n",
899                   jcr->last_fname, be.bstrerror());
900             return bacl_exit_error;
901          }
902       case 0:
903          break;
904       default:
905          acltype = BACL_TYPE_ACCESS;
906          break;
907       }
908    }
909
910    /**
911     * If the filesystem reports it doesn't support ACLs we clear the
912     * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
913     * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
914     * when we change from one filesystem to an other.
915     */
916    if (acl_enabled == 0) {
917       jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
918       pm_strcpy(jcr->acl_data->content, "");
919       jcr->acl_data->content_length = 0;
920       return bacl_exit_ok;
921    }
922
923    /**
924     * Based on the supported ACLs retrieve and store them.
925     */
926    switch (acltype) {
927    case BACL_TYPE_NFS4:
928       /**
929        * Read NFS4 ACLs for files, dirs and links
930        */
931       if (generic_get_acl_from_os(jcr, BACL_TYPE_NFS4) == bacl_exit_fatal)
932          return bacl_exit_fatal;
933
934       if (jcr->acl_data->content_length > 0) {
935          if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_NFS4_ACL) == bacl_exit_fatal)
936             return bacl_exit_fatal;
937       }
938       break;
939    case BACL_TYPE_ACCESS:
940       /**
941        * Read access ACLs for files, dirs and links
942        */
943       if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
944          return bacl_exit_fatal;
945
946       if (jcr->acl_data->content_length > 0) {
947          if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_ACCESS_ACL) == bacl_exit_fatal)
948             return bacl_exit_fatal;
949       }
950
951       /**
952        * Directories can have default ACLs too
953        */
954       if (ff_pkt->type == FT_DIREND) {
955          if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
956             return bacl_exit_fatal;
957          if (jcr->acl_data->content_length > 0) {
958             if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_DEFAULT_ACL) == bacl_exit_fatal)
959                return bacl_exit_fatal;
960          }
961       }
962       break;
963    default:
964       break;
965    }
966
967    return bacl_exit_ok;
968 }
969
970 static bacl_exit_code freebsd_parse_acl_streams(JCR *jcr, int stream)
971 {
972    int acl_enabled = 0;
973    const char *acl_type_name;
974    berrno be;
975
976    /**
977     * First make sure the filesystem supports acls.
978     */
979    switch (stream) {
980    case STREAM_UNIX_ACCESS_ACL:
981    case STREAM_ACL_FREEBSD_ACCESS_ACL:
982    case STREAM_UNIX_DEFAULT_ACL:
983    case STREAM_ACL_FREEBSD_DEFAULT_ACL:
984       acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
985       acl_type_name = "POSIX";
986       break;
987    case STREAM_ACL_FREEBSD_NFS4_ACL:
988 #if defined(_PC_ACL_NFS4)
989       acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
990 #endif
991       acl_type_name = "NFS4";
992       break;
993    default:
994       acl_type_name = "unknown";
995       break;
996    }
997
998    switch (acl_enabled) {
999    case -1:
1000       switch (errno) {
1001       case ENOENT:
1002          return bacl_exit_ok;
1003       default:
1004          Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1005                jcr->last_fname, be.bstrerror());
1006          Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1007                jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1008          return bacl_exit_error;
1009       }
1010    case 0:
1011       Mmsg2(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without %s acl support\n"),
1012             jcr->last_fname, acl_type_name);
1013       return bacl_exit_error;
1014    default:
1015       break;
1016    }
1017
1018    /**
1019     * Restore the ACLs.
1020     */
1021    switch (stream) {
1022    case STREAM_UNIX_ACCESS_ACL:
1023    case STREAM_ACL_FREEBSD_ACCESS_ACL:
1024       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
1025    case STREAM_UNIX_DEFAULT_ACL:
1026    case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1027       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
1028    case STREAM_ACL_FREEBSD_NFS4_ACL:
1029       return generic_set_acl_on_os(jcr, BACL_TYPE_NFS4);
1030    default:
1031       break;
1032    }
1033    return bacl_exit_error;
1034 }
1035
1036 /**
1037  * For this OSes setup the build and parse function pointer to the OS specific functions.
1038  */
1039 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = freebsd_build_acl_streams;
1040 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = freebsd_parse_acl_streams;
1041
1042 #elif defined(HAVE_IRIX_OS) || \
1043       defined(HAVE_LINUX_OS)
1044 /**
1045  * Define the supported ACL streams for these OSes
1046  */
1047 #if defined(HAVE_IRIX_OS)
1048 static int os_access_acl_streams[1] = { STREAM_ACL_IRIX_ACCESS_ACL };
1049 static int os_default_acl_streams[1] = { STREAM_ACL_IRIX_DEFAULT_ACL };
1050 #elif defined(HAVE_LINUX_OS)
1051 static int os_access_acl_streams[1] = { STREAM_ACL_LINUX_ACCESS_ACL };
1052 static int os_default_acl_streams[1] = { STREAM_ACL_LINUX_DEFAULT_ACL };
1053 #endif
1054
1055 static bacl_exit_code generic_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1056 {
1057    /**
1058     * Read access ACLs for files, dirs and links
1059     */
1060    if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1061       return bacl_exit_fatal;
1062
1063    if (jcr->acl_data->content_length > 0) {
1064       if (send_acl_stream(jcr, os_access_acl_streams[0]) == bacl_exit_fatal)
1065          return bacl_exit_fatal;
1066    }
1067
1068    /**
1069     * Directories can have default ACLs too
1070     */
1071    if (ff_pkt->type == FT_DIREND) {
1072       if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
1073          return bacl_exit_fatal;
1074       if (jcr->acl_data->content_length > 0) {
1075          if (send_acl_stream(jcr, os_default_acl_streams[0]) == bacl_exit_fatal)
1076             return bacl_exit_fatal;
1077       }
1078    }
1079    return bacl_exit_ok;
1080 }
1081
1082 static bacl_exit_code generic_parse_acl_streams(JCR *jcr, int stream)
1083 {
1084    unsigned int cnt;
1085
1086    switch (stream) {
1087    case STREAM_UNIX_ACCESS_ACL:
1088       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
1089    case STREAM_UNIX_DEFAULT_ACL:
1090       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
1091    default:
1092       /**
1093        * See what type of acl it is.
1094        */
1095       for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1096          if (os_access_acl_streams[cnt] == stream) {
1097             return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
1098          }
1099       }
1100       for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1101          if (os_default_acl_streams[cnt] == stream) {
1102             return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
1103          }
1104       }
1105       break;
1106    }
1107    return bacl_exit_error;
1108 }
1109
1110 /**
1111  * For this OSes setup the build and parse function pointer to the OS specific functions.
1112  */
1113 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_build_acl_streams;
1114 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = generic_parse_acl_streams;
1115
1116 #elif defined(HAVE_OSF1_OS)
1117
1118 /**
1119  * Define the supported ACL streams for this OS
1120  */
1121 static int os_access_acl_streams[1] = { STREAM_ACL_TRU64_ACCESS_ACL };
1122 static int os_default_acl_streams[2] = { STREAM_ACL_TRU64_DEFAULT_ACL, STREAM_ACL_TRU64_DEFAULT_DIR_ACL };
1123
1124 static bacl_exit_code tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1125 {
1126    /**
1127     * Read access ACLs for files, dirs and links
1128     */
1129    if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
1130       return bacl_exit_error;
1131    if (jcr->acl_data->content_length > 0) {
1132       if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL))
1133          return bacl_exit_error;
1134    }
1135    /**
1136     * Directories can have default ACLs too
1137     */
1138    if (ff_pkt->type == FT_DIREND) {
1139       if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
1140          return bacl_exit_error;
1141       if (jcr->acl_data->content_length > 0) {
1142          if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL))
1143             return bacl_exit_error;
1144       }
1145       /**
1146        * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
1147        * This is an inherited acl for all subdirs.
1148        * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
1149        * Section 21.5 Default ACLs 
1150        */
1151       if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR)) < 0)
1152          return bacl_exit_error;
1153       if (jcr->acl_data->content_length > 0) {
1154          if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL))
1155             return bacl_exit_error;
1156       }
1157    }
1158    return bacl_exit_ok;
1159 }
1160
1161 static bacl_exit_code tru64_parse_acl_streams(JCR *jcr, int stream)
1162 {
1163    switch (stream) {
1164    case STREAM_UNIX_ACCESS_ACL:
1165    case STREAM_ACL_TRU64_ACCESS_ACL:
1166       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
1167    case STREAM_UNIX_DEFAULT_ACL:
1168    case STREAM_ACL_TRU64_DEFAULT_ACL:
1169       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
1170    case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
1171       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR);
1172 }
1173
1174 /**
1175  * For this OS setup the build and parse function pointer to the OS specific functions.
1176  */
1177 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = tru64_build_acl_streams;
1178 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = tru64_parse_acl_streams;
1179
1180 #endif
1181
1182 #elif defined(HAVE_HPUX_OS)
1183 #ifdef HAVE_SYS_ACL_H
1184 #include <sys/acl.h>
1185 #else
1186 #error "configure failed to detect availability of sys/acl.h"
1187 #endif
1188
1189 #include <acllib.h>
1190
1191 /**
1192  * Define the supported ACL streams for this OS
1193  */
1194 static int os_access_acl_streams[1] = { STREAM_ACL_HPUX_ACL_ENTRY };
1195 static int os_default_acl_streams[1] = { -1 };
1196
1197 /**
1198  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1199  * There is no need to store those acls as we already store the stat bits too.
1200  */
1201 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
1202 {
1203    int n;
1204    struct acl_entry ace
1205
1206    for (n = 0; n < count; n++) {
1207       ace = entries[n];
1208       /**
1209        * See if this acl just is the stat mode in acl form.
1210        */
1211       if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
1212             (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
1213             (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
1214          return false;
1215    }
1216    return true;
1217 }
1218
1219 /**
1220  * OS specific functions for handling different types of acl streams.
1221  */
1222 static bacl_exit_code hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1223 {
1224    int n;
1225    struct acl_entry acls[NACLENTRIES];
1226    char *acl_text;
1227    berrno be;
1228
1229    if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
1230       switch (errno) {
1231 #if defined(BACL_ENOTSUP)
1232       case BACL_ENOTSUP:
1233          /**
1234           * Not supported, just pretend there is nothing to see
1235           *
1236           * If the filesystem reports it doesn't support ACLs we clear the
1237           * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1238           * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1239           * when we change from one filesystem to an other.
1240           */
1241          jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1242          pm_strcpy(jcr->acl_data->content, "");
1243          jcr->acl_data->content_length = 0;
1244          return bacl_exit_ok;
1245 #endif
1246       case ENOENT:
1247          pm_strcpy(jcr->acl_data->content, "");
1248          jcr->acl_data->content_length = 0;
1249          return bacl_exit_ok;
1250       default:
1251          Mmsg2(jcr->errmsg, _("getacl error on file \"%s\": ERR=%s\n"),
1252                jcr->last_fname, be.bstrerror());
1253          Dmsg2(100, "getacl error file=%s ERR=%s\n",  
1254                jcr->last_fname, be.bstrerror());
1255
1256          pm_strcpy(jcr->acl_data->content, "");
1257          jcr->acl_data->content_length = 0;
1258          return bacl_exit_error;
1259       }
1260    }
1261    if (n == 0) {
1262       pm_strcpy(jcr->acl_data->content, "");
1263       jcr->acl_data->content_length = 0;
1264       return bacl_exit_ok;
1265    }
1266    if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
1267       if (acl_is_trivial(n, acls, ff_pkt->statp)) {
1268          /**
1269           * The ACLs simply reflect the (already known) standard permissions
1270           * So we don't send an ACL stream to the SD.
1271           */
1272          pm_strcpy(jcr->acl_data->content, "");
1273          jcr->acl_data->content_length = 0;
1274          return bacl_exit_ok;
1275       }
1276       if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
1277          jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1278          actuallyfree(acl_text);
1279
1280          return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
1281       }
1282       Mmsg2(jcr->errmsg, _("acltostr error on file \"%s\": ERR=%s\n"),
1283             jcr->last_fname, be.bstrerror());
1284       Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",  
1285             jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1286       return bacl_exit_error;
1287    }
1288    return bacl_exit_error;
1289 }
1290
1291 static bacl_exit_code hpux_parse_acl_streams(JCR *jcr, int stream)
1292 {
1293    int n, stat;
1294    struct acl_entry acls[NACLENTRIES];
1295    berrno be;
1296
1297    n = strtoacl(jcr->acl_data->content, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
1298    if (n <= 0) {
1299       Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
1300             jcr->last_fname, be.bstrerror());
1301       Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",  
1302             jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1303       return bacl_exit_error;
1304    }
1305    if (strtoacl(jcr->acl_data->content, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
1306       Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
1307             jcr->last_fname, be.bstrerror());
1308       Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",  
1309             jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1310
1311       return bacl_exit_error;
1312    }
1313    /**
1314     * Restore the ACLs, but don't complain about links which really should
1315     * not have attributes, and the file it is linked to may not yet be restored.
1316     * This is only true for the old acl streams as in the new implementation we
1317     * don't save acls of symlinks (which cannot have acls anyhow)
1318     */
1319    if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
1320       switch (errno) {
1321       case ENOENT:
1322          return bacl_exit_ok;
1323       default:
1324          Mmsg2(jcr->errmsg, _("setacl error on file \"%s\": ERR=%s\n"),
1325                jcr->last_fname, be.bstrerror());
1326          Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
1327                jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1328          return bacl_exit_error;
1329       }
1330    }
1331    return bacl_exit_ok;
1332 }
1333
1334 /**
1335  * For this OS setup the build and parse function pointer to the OS specific functions.
1336  */
1337 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = hpux_build_acl_streams;
1338 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = hpux_parse_acl_streams;
1339
1340 #elif defined(HAVE_SUN_OS)
1341 #ifdef HAVE_SYS_ACL_H
1342 #include <sys/acl.h>
1343 #else
1344 #error "configure failed to detect availability of sys/acl.h"
1345 #endif
1346
1347 #if defined(HAVE_EXTENDED_ACL)
1348 /**
1349  * We define some internals of the Solaris acl libs here as those
1350  * are not exposed yet. Probably because they want us to see the
1351  * acls as opague data. But as we need to support different platforms
1352  * and versions of Solaris we need to expose some data to be able
1353  * to determine the type of acl used to stuff it into the correct
1354  * data stream. I know this is far from portable, but maybe the
1355  * proper interface is exposed later on and we can get ride of
1356  * this kludge. Newer versions of Solaris include sys/acl_impl.h
1357  * which has implementation details of acls, if thats included we
1358  * don't have to define it ourself.
1359  */
1360 #if !defined(_SYS_ACL_IMPL_H)
1361 typedef enum acl_type {
1362    ACLENT_T = 0,
1363    ACE_T = 1
1364 } acl_type_t;
1365 #endif
1366
1367 /**
1368  * Two external references to functions in the libsec library function not in current include files.
1369  */
1370 extern "C" {
1371 int acl_type(acl_t *);
1372 char *acl_strerror(int);
1373 }
1374
1375 /**
1376  * Define the supported ACL streams for this OS
1377  */
1378 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT, STREAM_ACL_SOLARIS_ACE };
1379 static int os_default_acl_streams[1] = { -1 };
1380
1381 /**
1382  * As the new libsec interface with acl_totext and acl_fromtext also handles
1383  * the old format from acltotext we can use the new functions even
1384  * for acls retrieved and stored in the database with older fd versions. If the
1385  * new interface is not defined (Solaris 9 and older we fall back to the old code)
1386  */
1387 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1388 {
1389    int acl_enabled, flags;
1390    acl_t *aclp;
1391    char *acl_text;
1392    bacl_exit_code stream_status = bacl_exit_error;
1393    berrno be;
1394
1395    /**
1396     * See if filesystem supports acls.
1397     */
1398    acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1399    switch (acl_enabled) {
1400    case 0:
1401       /**
1402        * If the filesystem reports it doesn't support ACLs we clear the
1403        * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1404        * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1405        * when we change from one filesystem to an other.
1406        */
1407       jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1408       pm_strcpy(jcr->acl_data->content, "");
1409       jcr->acl_data->content_length = 0;
1410       return bacl_exit_ok;
1411    case -1:
1412       switch (errno) {
1413       case ENOENT:
1414          return bacl_exit_ok;
1415       default:
1416          Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1417                jcr->last_fname, be.bstrerror());
1418          Dmsg2(100, "pathconf error file=%s ERR=%s\n",  
1419                jcr->last_fname, be.bstrerror());
1420          return bacl_exit_error;
1421       }
1422    default:
1423       break;
1424    }
1425
1426    /**
1427     * Get ACL info: don't bother allocating space if there is only a trivial ACL.
1428     */
1429    if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
1430       switch (errno) {
1431       case ENOENT:
1432          return bacl_exit_ok;
1433       default:
1434          Mmsg2(jcr->errmsg, _("acl_get error on file \"%s\": ERR=%s\n"),
1435                jcr->last_fname, acl_strerror(errno));
1436          Dmsg2(100, "acl_get error file=%s ERR=%s\n",  
1437                jcr->last_fname, acl_strerror(errno));
1438          return bacl_exit_error;
1439       }
1440    }
1441
1442    if (!aclp) {
1443       /**
1444        * The ACLs simply reflect the (already known) standard permissions
1445        * So we don't send an ACL stream to the SD.
1446        */
1447       pm_strcpy(jcr->acl_data->content, "");
1448       jcr->acl_data->content_length = 0;
1449       return bacl_exit_ok;
1450    }
1451
1452 #if defined(ACL_SID_FMT)
1453    /**
1454     * New format flag added in newer Solaris versions.
1455     */
1456    flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
1457 #else
1458    flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
1459 #endif /* ACL_SID_FMT */
1460
1461    if ((acl_text = acl_totext(aclp, flags)) != NULL) {
1462       jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1463       actuallyfree(acl_text);
1464
1465       switch (acl_type(aclp)) {
1466       case ACLENT_T:
1467          stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1468          break;
1469       case ACE_T:
1470          stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE);
1471          break;
1472       default:
1473          break;
1474       }
1475
1476       acl_free(aclp);
1477    }
1478    return stream_status;
1479 }
1480
1481 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
1482 {
1483    acl_t *aclp;
1484    int acl_enabled, error;
1485    berrno be;
1486
1487    switch (stream) {
1488    case STREAM_UNIX_ACCESS_ACL:
1489    case STREAM_ACL_SOLARIS_ACLENT:
1490    case STREAM_ACL_SOLARIS_ACE:
1491       /**
1492        * First make sure the filesystem supports acls.
1493        */
1494       acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1495       switch (acl_enabled) {
1496       case 0:
1497          Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
1498                jcr->last_fname);
1499          return bacl_exit_error;
1500       case -1:
1501          switch (errno) {
1502          case ENOENT:
1503             return bacl_exit_ok;
1504          default:
1505             Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1506                   jcr->last_fname, be.bstrerror());
1507             Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",  
1508                   jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1509             return bacl_exit_error;
1510          }
1511       default:
1512          /**
1513           * On a filesystem with ACL support make sure this particular ACL type can be restored.
1514           */
1515          switch (stream) {
1516          case STREAM_ACL_SOLARIS_ACLENT:
1517             /**
1518              * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
1519              */
1520             if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
1521                Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without aclent acl support\n"),
1522                      jcr->last_fname);
1523                return bacl_exit_error;
1524             }
1525             break;
1526          case STREAM_ACL_SOLARIS_ACE:
1527             /**
1528              * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
1529              */
1530             if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
1531                Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without ace acl support\n"),
1532                      jcr->last_fname);
1533                return bacl_exit_error;
1534             }
1535             break;
1536          default:
1537             /**
1538              * Stream id which doesn't describe the type of acl which is encoded.
1539              */
1540             break;
1541          }
1542          break;
1543       }
1544
1545       if ((error = acl_fromtext(jcr->acl_data->content, &aclp)) != 0) {
1546          Mmsg2(jcr->errmsg, _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1547                jcr->last_fname, acl_strerror(error));
1548          Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",  
1549                jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1550          return bacl_exit_error;
1551       }
1552
1553       /**
1554        * Validate that the conversion gave us the correct acl type.
1555        */
1556       switch (stream) {
1557       case STREAM_ACL_SOLARIS_ACLENT:
1558          if (acl_type(aclp) != ACLENT_T) {
1559             Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1560                   jcr->last_fname);
1561             return bacl_exit_error;
1562          }
1563          break;
1564       case STREAM_ACL_SOLARIS_ACE:
1565          if (acl_type(aclp) != ACE_T) {
1566             Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1567                   jcr->last_fname);
1568             return bacl_exit_error;
1569          }
1570          break;
1571       default:
1572          /**
1573           * Stream id which doesn't describe the type of acl which is encoded.
1574           */
1575          break;
1576       }
1577
1578       /**
1579        * Restore the ACLs, but don't complain about links which really should
1580        * not have attributes, and the file it is linked to may not yet be restored.
1581        * This is only true for the old acl streams as in the new implementation we
1582        * don't save acls of symlinks (which cannot have acls anyhow)
1583        */
1584       if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1585          switch (errno) {
1586          case ENOENT:
1587             acl_free(aclp);
1588             return bacl_exit_ok;
1589          default:
1590             Mmsg2(jcr->errmsg, _("acl_set error on file \"%s\": ERR=%s\n"),
1591                   jcr->last_fname, acl_strerror(error));
1592             Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",  
1593                   jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1594             acl_free(aclp);
1595             return bacl_exit_error;
1596          }
1597       }
1598
1599       acl_free(aclp);
1600       return bacl_exit_ok;
1601    default:
1602       return bacl_exit_error;
1603    } /* end switch (stream) */
1604 }
1605
1606 #else /* HAVE_EXTENDED_ACL */
1607
1608 /**
1609  * Define the supported ACL streams for this OS
1610  */
1611 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT };
1612 static int os_default_acl_streams[1] = { -1 };
1613
1614 /**
1615  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1616  * There is no need to store those acls as we already store the stat bits too.
1617  */
1618 static bool acl_is_trivial(int count, aclent_t *entries)
1619 {
1620    int n;
1621    aclent_t *ace;
1622
1623    for (n = 0; n < count; n++) {
1624       ace = &entries[n];
1625
1626       if (!(ace->a_type == USER_OBJ ||
1627             ace->a_type == GROUP_OBJ ||
1628             ace->a_type == OTHER_OBJ ||
1629             ace->a_type == CLASS_OBJ))
1630         return false;
1631    }
1632    return true;
1633 }
1634
1635 /**
1636  * OS specific functions for handling different types of acl streams.
1637  */
1638 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1639 {
1640    int n;
1641    aclent_t *acls;
1642    char *acl_text;
1643    berrno be;
1644
1645    n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1646    if (n < MIN_ACL_ENTRIES)
1647       return bacl_exit_error;
1648
1649    acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1650    if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1651       if (acl_is_trivial(n, acls)) {
1652          /**
1653           * The ACLs simply reflect the (already known) standard permissions
1654           * So we don't send an ACL stream to the SD.
1655           */
1656          free(acls);
1657          pm_strcpy(jcr->acl_data->content, "");
1658          jcr->acl_data->content_length = 0;
1659          return bacl_exit_ok;
1660       }
1661
1662       if ((acl_text = acltotext(acls, n)) != NULL) {
1663          jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1664          actuallyfree(acl_text);
1665          free(acls);
1666          return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1667       }
1668
1669       Mmsg2(jcr->errmsg, _("acltotext error on file \"%s\": ERR=%s\n"),
1670             jcr->last_fname, be.bstrerror());
1671       Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",  
1672             jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1673    }
1674
1675    free(acls);
1676    return bacl_exit_error;
1677 }
1678
1679 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
1680 {
1681    int n;
1682    aclent_t *acls;
1683    berrno be;
1684
1685    acls = aclfromtext(jcr->acl_data->content, &n);
1686    if (!acls) {
1687       Mmsg2(jcr->errmsg, _("aclfromtext error on file \"%s\": ERR=%s\n"),
1688             jcr->last_fname, be.bstrerror());
1689       Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",  
1690             jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1691       return bacl_exit_error;
1692    }
1693
1694    /**
1695     * Restore the ACLs, but don't complain about links which really should
1696     * not have attributes, and the file it is linked to may not yet be restored.
1697     */
1698    if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
1699       switch (errno) {
1700       case ENOENT:
1701          actuallyfree(acls);
1702          return bacl_exit_ok;
1703       default:
1704          Mmsg2(jcr->errmsg, _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
1705                jcr->last_fname, be.bstrerror());
1706          Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
1707                jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1708          actuallyfree(acls);
1709          return bacl_exit_error;
1710       }
1711    }
1712    actuallyfree(acls);
1713    return bacl_exit_ok;
1714 }
1715 #endif /* HAVE_EXTENDED_ACL */
1716
1717 /**
1718  * For this OS setup the build and parse function pointer to the OS specific functions.
1719  */
1720 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_acl_streams;
1721 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = solaris_parse_acl_streams;
1722
1723 #endif /* HAVE_SUN_OS */
1724 #endif /* HAVE_ACL */
1725
1726 /*
1727  * Entry points when compiled with support for ACLs on a supported platform.
1728  */
1729
1730 /**
1731  * Read and send an ACL for the last encountered file.
1732  */
1733 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1734 {
1735    /**
1736     * See if we are changing from one device to an other.
1737     * We save the current device we are scanning and compare
1738     * it with the current st_dev in the last stat performed on
1739     * the file we are currently storing.
1740     */
1741    if (jcr->acl_data->current_dev != ff_pkt->statp.st_dev) {
1742       /**
1743        * Reset the acl save flags.
1744        */
1745       jcr->acl_data->flags = 0;
1746
1747       jcr->acl_data->flags |= BACL_FLAG_SAVE_NATIVE;
1748
1749       /**
1750        * Save that we started scanning a new filesystem.
1751        */
1752       jcr->acl_data->current_dev = ff_pkt->statp.st_dev;
1753    }
1754
1755 #if defined(HAVE_ACL)
1756    /**
1757     * See if the BACL_FLAG_SAVE_NATIVE flag is set which lets us know if we should
1758     * save native ACLs.
1759     */
1760    if (jcr->acl_data->flags & BACL_FLAG_SAVE_NATIVE) {
1761       /**
1762        * Call the appropriate function.
1763        */
1764       if (os_build_acl_streams) {
1765          return (*os_build_acl_streams)(jcr, ff_pkt);
1766       }
1767    } else {
1768       return bacl_exit_ok;
1769    }
1770 #endif
1771    return bacl_exit_error;
1772 }
1773
1774 bacl_exit_code parse_acl_streams(JCR *jcr, int stream)
1775 {
1776    unsigned int cnt;
1777
1778    switch (stream) {
1779 #if defined(HAVE_ACL)
1780    case STREAM_UNIX_ACCESS_ACL:
1781    case STREAM_UNIX_DEFAULT_ACL:
1782       /**
1783        * Handle legacy ACL streams.
1784        */
1785       if (os_parse_acl_streams) {
1786          return (*os_parse_acl_streams)(jcr, stream);
1787       }
1788       break;
1789    default:
1790       if (os_parse_acl_streams) {
1791          /**
1792           * Walk the os_access_acl_streams array with the supported Access ACL streams for this OS.
1793           */
1794          for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1795             if (os_access_acl_streams[cnt] == stream) {
1796                return (*os_parse_acl_streams)(jcr, stream);
1797             }
1798          }
1799          /**
1800           * Walk the os_default_acl_streams array with the supported Default ACL streams for this OS.
1801           */
1802          for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1803             if (os_default_acl_streams[cnt] == stream) {
1804                return (*os_parse_acl_streams)(jcr, stream);
1805             }
1806          }
1807       }
1808       break;
1809 #else
1810    default:
1811       break;
1812 #endif
1813    }
1814    Qmsg2(jcr, M_WARNING, 0,
1815       _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
1816       jcr->last_fname, stream);
1817    return bacl_exit_error;
1818 }
1819 #endif