]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/acl.c
b8342bac674a53a70b5da1fd476272c5f727cc30
[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  * We handle two different types of ACLs: access and default ACLS.
32  * On most systems that support default ACLs they only apply to directories.
33  *
34  * On some systems (eg. linux and FreeBSD) we must obtain the two ACLs
35  * independently, while others (eg. Solaris) provide both in one call.
36  *
37  * The Filed saves ACLs in their native format and uses different streams
38  * for all different platforms. Currently we only allow ACLs to be restored
39  * which were saved in the native format of the platform they are extracted
40  * on. Later on we might add conversion functions for mapping from one
41  * platform to an other or allow restores of systems that use the same
42  * native format.
43  *
44  * Its also interesting to see what the exact format of acl text is on
45  * certain platforms and if they use they same encoding we might allow
46  * different platform streams to be decoded on an other similar platform.
47  *
48  *   Original written by Preben 'Peppe' Guldberg, December MMIV
49  *   Major rewrite by Marco van Wieringen, November MMVIII
50  */
51   
52 #include "bacula.h"
53 #include "filed.h"
54   
55 #if !defined(HAVE_ACL) && !defined(HAVE_AFS_ACL)
56 /**
57  * Entry points when compiled without support for ACLs or on an unsupported platform.
58  */
59 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
60 {
61    return bacl_exit_fatal;
62 }
63
64 bacl_exit_code parse_acl_streams(JCR *jcr, int stream)
65 {
66    return bacl_exit_fatal;
67 }
68 #else
69 /**
70  * Send an ACL stream to the SD.
71  */
72 static bacl_exit_code send_acl_stream(JCR *jcr, int stream)
73 {
74    BSOCK *sd = jcr->store_bsock;
75    POOLMEM *msgsave;
76 #ifdef FD_NO_SEND_TEST
77    return bacl_exit_ok;
78 #endif
79
80    /**
81     * Sanity check
82     */
83    if (jcr->acl_data->content_length <= 0) {
84       return bacl_exit_ok;
85    }
86
87    /**
88     * Send header
89     */
90    if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
91       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
92             sd->bstrerror());
93       return bacl_exit_fatal;
94    }
95
96    /**
97     * Send the buffer to the storage deamon
98     */
99    Dmsg1(400, "Backing up ACL <%s>\n", jcr->acl_data->content);
100    msgsave = sd->msg;
101    sd->msg = jcr->acl_data->content;
102    sd->msglen = jcr->acl_data->content_length + 1;
103    if (!sd->send()) {
104       sd->msg = msgsave;
105       sd->msglen = 0;
106       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
107             sd->bstrerror());
108       return bacl_exit_fatal;
109    }
110
111    jcr->JobBytes += sd->msglen;
112    sd->msg = msgsave;
113    if (!sd->signal(BNET_EOD)) {
114       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
115             sd->bstrerror());
116       return bacl_exit_fatal;
117    }
118
119    Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
120    return bacl_exit_ok;
121 }
122
123 /**
124  * First the native ACLs.
125  */
126 #if defined(HAVE_ACL)
127 #if defined(HAVE_AIX_OS)
128
129 #if defined(HAVE_EXTENDED_ACL)
130
131 #include <sys/acl.h>
132
133 /**
134  * Define the supported ACL streams for this OS
135  */
136 static int os_access_acl_streams[1] = { STREAM_ACL_AIX_TEXT, STREAM_ACL_AIX_AIXC, STREAM_ACL_AIX_NFS4 };
137 static int os_default_acl_streams[1] = { -1 };
138
139 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
140 {
141    return bacl_exit_error;
142 }
143
144 static bacl_exit_code aix_parse_acl_streams(JCR *jcr, int stream)
145 {
146    switch (stream) {
147    case STREAM_ACL_AIX_TEXT:
148    case STREAM_ACL_AIX_AIXC:
149       break;
150    case STREAM_ACL_AIX_NFS4:
151       break;
152    }
153
154    return bacl_exit_error;
155 }
156
157 #else /* HAVE_EXTENDED_ACL */
158
159 #include <sys/access.h>
160
161 /**
162  * Define the supported ACL streams for this OS
163  */
164 static int os_access_acl_streams[1] = { STREAM_ACL_AIX_TEXT };
165 static int os_default_acl_streams[1] = { -1 };
166
167 static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
168 {
169    char *acl_text;
170
171    if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
172       jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
173       actuallyfree(acl_text);
174       return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT);
175    }
176    return bacl_exit_error;
177 }
178
179 static bacl_exit_code aix_parse_acl_streams(JCR *jcr, int stream)
180 {
181    if (acl_put(jcr->last_fname, jcr->acl_data->content, 0) != 0) {
182       return bacl_exit_error;
183    }
184    return bacl_exit_ok;
185 }
186 #endif /* HAVE_EXTENDED_ACL */
187
188 /**
189  * For this OS setup the build and parse function pointer to the OS specific functions.
190  */
191 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = aix_build_acl_streams;
192 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = aix_parse_acl_streams;
193
194 #elif defined(HAVE_DARWIN_OS) || \
195       defined(HAVE_FREEBSD_OS) || \
196       defined(HAVE_IRIX_OS) || \
197       defined(HAVE_OSF1_OS) || \
198       defined(HAVE_LINUX_OS)
199
200 #include <sys/types.h>
201
202 #ifdef HAVE_SYS_ACL_H
203 #include <sys/acl.h>
204 #else
205 #error "configure failed to detect availability of sys/acl.h"
206 #endif
207
208 /**
209  * On IRIX we can get shortened ACLs
210  */
211 #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
212 #define acl_to_text(acl,len)     acl_to_short_text((acl), (len))
213 #endif
214
215 /**
216  * In Linux we can get numeric and/or shorted ACLs
217  */
218 #if defined(HAVE_LINUX_OS)
219 #if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
220 #define BACL_ALTERNATE_TEXT            (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
221 #elif defined(BACL_WANT_SHORT_ACLS)
222 #define BACL_ALTERNATE_TEXT            TEXT_ABBREVIATE
223 #elif defined(BACL_WANT_NUMERIC_IDS)
224 #define BACL_ALTERNATE_TEXT            TEXT_NUMERIC_IDS
225 #endif
226 #ifdef BACL_ALTERNATE_TEXT
227 #include <acl/libacl.h>
228 #define acl_to_text(acl,len)     (acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
229 #endif
230 #endif
231
232 /**
233  * Some generic functions used by multiple OSes.
234  */
235 static acl_type_t bac_to_os_acltype(bacl_type acltype)
236 {
237    acl_type_t ostype;
238
239    switch (acltype) {
240    case BACL_TYPE_ACCESS:
241       ostype = ACL_TYPE_ACCESS;
242       break;
243    case BACL_TYPE_DEFAULT:
244       ostype = ACL_TYPE_DEFAULT;
245       break;
246
247 #ifdef ACL_TYPE_DEFAULT_DIR
248    case BACL_TYPE_DEFAULT_DIR:
249       /**
250        * OSF1 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
251        */
252       ostype = ACL_TYPE_DEFAULT_DIR;
253       break;
254 #endif
255 #ifdef ACL_TYPE_EXTENDED
256    case BACL_TYPE_EXTENDED:
257       /**
258        * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
259        */
260       ostype = ACL_TYPE_EXTENDED;
261       break;
262 #endif
263    default:
264       /**
265        * This should never happen, as the per OS version function only tries acl
266        * types supported on a certain platform.
267        */
268       ostype = (acl_type_t)ACL_TYPE_NONE;
269       break;
270    }
271    return ostype;
272 }
273
274 #if !defined(HAVE_DARWIN_OS)
275 /**
276  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
277  * There is no need to store those acls as we already store the stat bits too.
278  */
279 static bool acl_is_trivial(acl_t acl)
280 {
281   /**
282    * acl is trivial if it has only the following entries:
283    * "user::",
284    * "group::",
285    * "other::"
286    */
287    acl_entry_t ace;
288    acl_tag_t tag;
289 #if defined(HAVE_FREEBSD_OS) || \
290     defined(HAVE_LINUX_OS)
291    int entry_available;
292
293    entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
294    while (entry_available == 1) {
295       /**
296        * Get the tag type of this acl entry.
297        * If we fail to get the tagtype we call the acl non-trivial.
298        */
299       if (acl_get_tag_type(ace, &tag) < 0)
300          return true;
301       /**
302        * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
303        */
304       if (tag != ACL_USER_OBJ &&
305           tag != ACL_GROUP_OBJ &&
306           tag != ACL_OTHER)
307          return false;
308       entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
309    }
310    return true;
311 #elif defined(HAVE_IRIX_OS)
312    int n;
313
314    for (n = 0; n < acl->acl_cnt; n++) {
315       ace = &acl->acl_entry[n];
316       tag = ace->ae_tag;
317
318       /**
319        * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
320        */
321       if (tag != ACL_USER_OBJ &&
322           tag != ACL_GROUP_OBJ &&
323           tag != ACL_OTHER_OBJ)
324          return false;
325    }
326    return true;
327 #elif defined(HAVE_OSF1_OS)
328    int count;
329
330    ace = acl->acl_first;
331    count = acl->acl_num;
332
333    while (count > 0) {
334       tag = ace->entry->acl_type;
335       /**
336        * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
337        */
338       if (tag != ACL_USER_OBJ &&
339           tag != ACL_GROUP_OBJ &&
340           tag != ACL_OTHER)
341          return false;
342       /**
343        * On Tru64, perm can also contain non-standard bits such as
344        * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
345        */
346       if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
347          return false;
348       ace = ace->next;
349       count--;
350    }
351    return true;
352 #endif
353 }
354 #endif
355
356 /**
357  * Generic wrapper around acl_get_file call.
358  */
359 static bacl_exit_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
360 {
361    acl_t acl;
362    acl_type_t ostype;
363    char *acl_text;
364    berrno be;
365
366    ostype = bac_to_os_acltype(acltype);
367    acl = acl_get_file(jcr->last_fname, ostype);
368    if (acl) {
369 #if defined(HAVE_IRIX_OS)
370       /**
371        * From observation, IRIX's acl_get_file() seems to return a
372        * non-NULL acl with a count field of -1 when a file has no ACL
373        * defined, while IRIX's acl_to_text() returns NULL when presented
374        * with such an ACL. 
375        *
376        * Checking the count in the acl structure before calling
377        * acl_to_text() lets us avoid error messages about files
378        * with no ACLs, without modifying the flow of the code used for 
379        * other operating systems, and it saves making some calls
380        * to acl_to_text() besides.
381        */
382       if (acl->acl_cnt <= 0) {
383          pm_strcpy(jcr->acl_data->content, "");
384          jcr->acl_data->content_length = 0;
385          acl_free(acl);
386          return bacl_exit_ok;
387       }
388 #endif
389
390 #if !defined(HAVE_DARWIN_OS)
391       /**
392        * Make sure this is not just a trivial ACL.
393        */
394       if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
395          /**
396           * The ACLs simply reflect the (already known) standard permissions
397           * So we don't send an ACL stream to the SD.
398           */
399          pm_strcpy(jcr->acl_data->content, "");
400          jcr->acl_data->content_length = 0;
401          acl_free(acl);
402          return bacl_exit_ok;
403       }
404 #endif
405
406       if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
407          jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
408          acl_free(acl);
409          acl_free(acl_text);
410          return bacl_exit_ok;
411       }
412
413       Mmsg2(jcr->errmsg, _("acl_to_text error on file \"%s\": ERR=%s\n"),
414             jcr->last_fname, be.bstrerror());
415       Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",  
416             jcr->last_fname, be.bstrerror());
417
418       pm_strcpy(jcr->acl_data->content, "");
419       jcr->acl_data->content_length = 0;
420       acl_free(acl);
421       return bacl_exit_error;
422    }
423
424    /**
425     * Handle errors gracefully.
426     */
427    if (acl == (acl_t)NULL) {
428       switch (errno) {
429 #if defined(BACL_ENOTSUP)
430       case BACL_ENOTSUP:
431          /**
432           * If the filesystem reports it doesn't support ACLs we clear the
433           * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
434           * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
435           * when we change from one filesystem to an other.
436           */
437          jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
438          break;                       /* not supported */
439 #endif
440       case ENOENT:
441          pm_strcpy(jcr->acl_data->content, "");
442          jcr->acl_data->content_length = 0;
443          return bacl_exit_ok;
444       default:
445          /* Some real error */
446          Mmsg2(jcr->errmsg, _("acl_get_file error on file \"%s\": ERR=%s\n"),
447                jcr->last_fname, be.bstrerror());
448          Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",  
449                jcr->last_fname, be.bstrerror());
450
451          pm_strcpy(jcr->acl_data->content, "");
452          jcr->acl_data->content_length = 0;
453          return bacl_exit_error;
454       }
455    }
456
457    /**
458     * Not supported, just pretend there is nothing to see
459     */
460    pm_strcpy(jcr->acl_data->content, "");
461    jcr->acl_data->content_length = 0;
462    return bacl_exit_ok;
463 }
464
465 /**
466  * Generic wrapper around acl_set_file call.
467  */
468 static bacl_exit_code generic_set_acl_on_os(JCR *jcr, bacl_type acltype)
469 {
470    acl_t acl;
471    acl_type_t ostype;
472    berrno be;
473
474    /**
475     * If we get empty default ACLs, clear ACLs now
476     */
477    ostype = bac_to_os_acltype(acltype);
478    if (ostype == ACL_TYPE_DEFAULT && strlen(jcr->acl_data->content) == 0) {
479       if (acl_delete_def_file(jcr->last_fname) == 0) {
480          return bacl_exit_ok;
481       }
482       switch (errno) {
483       case ENOENT:
484          return bacl_exit_ok;
485       default:
486          Mmsg2(jcr->errmsg, _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
487                jcr->last_fname, be.bstrerror());
488          return bacl_exit_error;
489       }
490    }
491
492    acl = acl_from_text(jcr->acl_data->content);
493    if (acl == NULL) {
494       Mmsg2(jcr->errmsg, _("acl_from_text error on file \"%s\": ERR=%s\n"),
495             jcr->last_fname, be.bstrerror());
496       Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",  
497          jcr->acl_data->content, jcr->last_fname, be.bstrerror());
498       return bacl_exit_error;
499    }
500
501 #ifndef HAVE_FREEBSD_OS
502    /**
503     * FreeBSD always fails acl_valid() - at least on valid input...
504     * As it does the right thing, given valid input, just ignore acl_valid().
505     */
506    if (acl_valid(acl) != 0) {
507       Mmsg2(jcr->errmsg, _("acl_valid error on file \"%s\": ERR=%s\n"),
508             jcr->last_fname, be.bstrerror());
509       Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",  
510          jcr->acl_data->content, jcr->last_fname, be.bstrerror());
511       acl_free(acl);
512       return bacl_exit_error;
513    }
514 #endif
515
516    /**
517     * Restore the ACLs, but don't complain about links which really should
518     * not have attributes, and the file it is linked to may not yet be restored.
519     * This is only true for the old acl streams as in the new implementation we
520     * don't save acls of symlinks (which cannot have acls anyhow)
521     */
522    if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
523       switch (errno) {
524       case ENOENT:
525          acl_free(acl);
526          return bacl_exit_ok;
527       default:
528          Mmsg2(jcr->errmsg, _("acl_set_file error on file \"%s\": ERR=%s\n"),
529                jcr->last_fname, be.bstrerror());
530          Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
531                jcr->acl_data->content, jcr->last_fname, be.bstrerror());
532          acl_free(acl);
533          return bacl_exit_error;
534       }
535    }
536    acl_free(acl);
537    return bacl_exit_ok;
538 }
539
540 /**
541  * OS specific functions for handling different types of acl streams.
542  */
543 #if defined(HAVE_DARWIN_OS)
544 /**
545  * Define the supported ACL streams for this OS
546  */
547 static int os_access_acl_streams[1] = { STREAM_ACL_DARWIN_ACCESS_ACL };
548 static int os_default_acl_streams[1] = { -1 };
549
550 static bacl_exit_code darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
551 {
552 #if defined(ACL_TYPE_EXTENDED)
553    /**
554     * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
555     * and acl_get_file (name, ACL_TYPE_DEFAULT)
556     * always return NULL / EINVAL.  There is no point in making
557     * these two useless calls.  The real ACL is retrieved through
558     * acl_get_file (name, ACL_TYPE_EXTENDED).
559     *
560     * Read access ACLs for files, dirs and links
561     */
562    if (generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED) == bacl_exit_fatal)
563       return bacl_exit_fatal;
564 #else
565    /**
566     * Read access ACLs for files, dirs and links
567     */
568    if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
569       return bacl_exit_fatal;
570 #endif
571
572    if (jcr->acl_data->content_length > 0) {
573       return send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL);
574    }
575    return bacl_exit_ok;
576 }
577
578 static bacl_exit_code darwin_parse_acl_streams(JCR *jcr, int stream)
579 {
580 #if defined(ACL_TYPE_EXTENDED)
581       return generic_set_acl_on_os(jcr, BACL_TYPE_EXTENDED);
582 #else
583       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
584 #endif
585 }
586
587 /**
588  * For this OS setup the build and parse function pointer to the OS specific functions.
589  */
590 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = darwin_build_acl_streams;
591 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = darwin_parse_acl_streams;
592
593 #elif defined(HAVE_FREEBSD_OS) || \
594       defined(HAVE_IRIX_OS) || \
595       defined(HAVE_LINUX_OS)
596
597 /**
598  * Define the supported ACL streams for these OSes
599  */
600 #if defined(HAVE_FREEBSD_OS)
601 static int os_access_acl_streams[1] = { STREAM_ACL_FREEBSD_ACCESS_ACL };
602 static int os_default_acl_streams[1] = { STREAM_ACL_FREEBSD_DEFAULT_ACL };
603 #elif defined(HAVE_IRIX_OS)
604 static int os_access_acl_streams[1] = { STREAM_ACL_IRIX_ACCESS_ACL };
605 static int os_default_acl_streams[1] = { STREAM_ACL_IRIX_DEFAULT_ACL };
606 #elif defined(HAVE_LINUX_OS)
607 static int os_access_acl_streams[1] = { STREAM_ACL_LINUX_ACCESS_ACL };
608 static int os_default_acl_streams[1] = { STREAM_ACL_LINUX_DEFAULT_ACL };
609 #endif
610
611 static bacl_exit_code generic_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
612 {
613    /**
614     * Read access ACLs for files, dirs and links
615     */
616    if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
617       return bacl_exit_fatal;
618
619    if (jcr->acl_data->content_length > 0) {
620       if (send_acl_stream(jcr, os_access_acl_streams[0]) == bacl_exit_fatal)
621          return bacl_exit_fatal;
622    }
623
624    /**
625     * Directories can have default ACLs too
626     */
627    if (ff_pkt->type == FT_DIREND) {
628       if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
629          return bacl_exit_fatal;
630       if (jcr->acl_data->content_length > 0) {
631          if (send_acl_stream(jcr, os_default_acl_streams[0]) == bacl_exit_fatal)
632             return bacl_exit_fatal;
633       }
634    }
635    return bacl_exit_ok;
636 }
637
638 static bacl_exit_code generic_parse_acl_streams(JCR *jcr, int stream)
639 {
640    unsigned int cnt;
641
642    switch (stream) {
643    case STREAM_UNIX_ACCESS_ACL:
644       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
645    case STREAM_UNIX_DEFAULT_ACL:
646       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
647    default:
648       /**
649        * See what type of acl it is.
650        */
651       for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
652          if (os_access_acl_streams[cnt] == stream) {
653             return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
654          }
655       }
656       for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
657          if (os_default_acl_streams[cnt] == stream) {
658             return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
659          }
660       }
661       break;
662    }
663    return bacl_exit_error;
664 }
665
666 /**
667  * For this OSes setup the build and parse function pointer to the OS specific functions.
668  */
669 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_build_acl_streams;
670 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = generic_parse_acl_streams;
671
672 #elif defined(HAVE_OSF1_OS)
673
674 /**
675  * Define the supported ACL streams for this OS
676  */
677 static int os_access_acl_streams[1] = { STREAM_ACL_TRU64_ACCESS_ACL };
678 static int os_default_acl_streams[2] = { STREAM_ACL_TRU64_DEFAULT_ACL, STREAM_ACL_TRU64_DEFAULT_DIR_ACL };
679
680 static bacl_exit_code tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
681 {
682    /**
683     * Read access ACLs for files, dirs and links
684     */
685    if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
686       return bacl_exit_error;
687    if (jcr->acl_data->content_length > 0) {
688       if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL))
689          return bacl_exit_error;
690    }
691    /**
692     * Directories can have default ACLs too
693     */
694    if (ff_pkt->type == FT_DIREND) {
695       if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
696          return bacl_exit_error;
697       if (jcr->acl_data->content_length > 0) {
698          if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL))
699             return bacl_exit_error;
700       }
701       /**
702        * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
703        * This is an inherited acl for all subdirs.
704        * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
705        * Section 21.5 Default ACLs 
706        */
707       if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR)) < 0)
708          return bacl_exit_error;
709       if (jcr->acl_data->content_length > 0) {
710          if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL))
711             return bacl_exit_error;
712       }
713    }
714    return bacl_exit_ok;
715 }
716
717 static bacl_exit_code tru64_parse_acl_streams(JCR *jcr, int stream)
718 {
719    switch (stream) {
720    case STREAM_UNIX_ACCESS_ACL:
721    case STREAM_ACL_TRU64_ACCESS_ACL:
722       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
723    case STREAM_UNIX_DEFAULT_ACL:
724    case STREAM_ACL_TRU64_DEFAULT_ACL:
725       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
726    case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
727       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR);
728 }
729
730 /**
731  * For this OS setup the build and parse function pointer to the OS specific functions.
732  */
733 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = tru64_build_acl_streams;
734 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = tru64_parse_acl_streams;
735
736 #endif
737
738 #elif defined(HAVE_HPUX_OS)
739 #ifdef HAVE_SYS_ACL_H
740 #include <sys/acl.h>
741 #else
742 #error "configure failed to detect availability of sys/acl.h"
743 #endif
744
745 #include <acllib.h>
746
747 /**
748  * Define the supported ACL streams for this OS
749  */
750 static int os_access_acl_streams[1] = { STREAM_ACL_HPUX_ACL_ENTRY };
751 static int os_default_acl_streams[1] = { -1 };
752
753 /**
754  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
755  * There is no need to store those acls as we already store the stat bits too.
756  */
757 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
758 {
759    int n;
760    struct acl_entry ace
761
762    for (n = 0; n < count; n++) {
763       ace = entries[n];
764       /**
765        * See if this acl just is the stat mode in acl form.
766        */
767       if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
768             (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
769             (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
770          return false;
771    }
772    return true;
773 }
774
775 /**
776  * OS specific functions for handling different types of acl streams.
777  */
778 static bacl_exit_code hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
779 {
780    int n;
781    struct acl_entry acls[NACLENTRIES];
782    char *acl_text;
783    berrno be;
784
785    if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
786       switch (errno) {
787 #if defined(BACL_ENOTSUP)
788       case BACL_ENOTSUP:
789          /**
790           * Not supported, just pretend there is nothing to see
791           *
792           * If the filesystem reports it doesn't support ACLs we clear the
793           * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
794           * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
795           * when we change from one filesystem to an other.
796           */
797          jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
798          pm_strcpy(jcr->acl_data->content, "");
799          jcr->acl_data->content_length = 0;
800          return bacl_exit_ok;
801 #endif
802       case ENOENT:
803          pm_strcpy(jcr->acl_data->content, "");
804          jcr->acl_data->content_length = 0;
805          return bacl_exit_ok;
806       default:
807          Mmsg2(jcr->errmsg, _("getacl error on file \"%s\": ERR=%s\n"),
808                jcr->last_fname, be.bstrerror());
809          Dmsg2(100, "getacl error file=%s ERR=%s\n",  
810                jcr->last_fname, be.bstrerror());
811
812          pm_strcpy(jcr->acl_data->content, "");
813          jcr->acl_data->content_length = 0;
814          return bacl_exit_error;
815       }
816    }
817    if (n == 0) {
818       pm_strcpy(jcr->acl_data->content, "");
819       jcr->acl_data->content_length = 0;
820       return bacl_exit_ok;
821    }
822    if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
823       if (acl_is_trivial(n, acls, ff_pkt->statp)) {
824          /**
825           * The ACLs simply reflect the (already known) standard permissions
826           * So we don't send an ACL stream to the SD.
827           */
828          pm_strcpy(jcr->acl_data->content, "");
829          jcr->acl_data->content_length = 0;
830          return bacl_exit_ok;
831       }
832       if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
833          jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
834          actuallyfree(acl_text);
835
836          return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
837       }
838       Mmsg2(jcr->errmsg, _("acltostr error on file \"%s\": ERR=%s\n"),
839             jcr->last_fname, be.bstrerror());
840       Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",  
841             jcr->acl_data->content, jcr->last_fname, be.bstrerror());
842       return bacl_exit_error;
843    }
844    return bacl_exit_error;
845 }
846
847 static bacl_exit_code hpux_parse_acl_streams(JCR *jcr, int stream)
848 {
849    int n, stat;
850    struct acl_entry acls[NACLENTRIES];
851    berrno be;
852
853    n = strtoacl(jcr->acl_data->content, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
854    if (n <= 0) {
855       Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
856             jcr->last_fname, be.bstrerror());
857       Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",  
858             jcr->acl_data->content, jcr->last_fname, be.bstrerror());
859       return bacl_exit_error;
860    }
861    if (strtoacl(jcr->acl_data->content, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
862       Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
863             jcr->last_fname, be.bstrerror());
864       Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",  
865             jcr->acl_data->content, jcr->last_fname, be.bstrerror());
866
867       return bacl_exit_error;
868    }
869    /**
870     * Restore the ACLs, but don't complain about links which really should
871     * not have attributes, and the file it is linked to may not yet be restored.
872     * This is only true for the old acl streams as in the new implementation we
873     * don't save acls of symlinks (which cannot have acls anyhow)
874     */
875    if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
876       switch (errno) {
877       case ENOENT:
878          return bacl_exit_ok;
879       default:
880          Mmsg2(jcr->errmsg, _("setacl error on file \"%s\": ERR=%s\n"),
881                jcr->last_fname, be.bstrerror());
882          Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
883                jcr->acl_data->content, jcr->last_fname, be.bstrerror());
884          return bacl_exit_error;
885       }
886    }
887    return bacl_exit_ok;
888 }
889
890 /**
891  * For this OS setup the build and parse function pointer to the OS specific functions.
892  */
893 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = hpux_build_acl_streams;
894 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = hpux_parse_acl_streams;
895
896 #elif defined(HAVE_SUN_OS)
897 #ifdef HAVE_SYS_ACL_H
898 #include <sys/acl.h>
899 #else
900 #error "configure failed to detect availability of sys/acl.h"
901 #endif
902
903 #if defined(HAVE_EXTENDED_ACL)
904 /**
905  * We define some internals of the Solaris acl libs here as those
906  * are not exposed yet. Probably because they want us to see the
907  * acls as opague data. But as we need to support different platforms
908  * and versions of Solaris we need to expose some data to be able
909  * to determine the type of acl used to stuff it into the correct
910  * data stream. I know this is far from portable, but maybe the
911  * proper interface is exposed later on and we can get ride of
912  * this kludge. Newer versions of Solaris include sys/acl_impl.h
913  * which has implementation details of acls, if thats included we
914  * don't have to define it ourself.
915  */
916 #if !defined(_SYS_ACL_IMPL_H)
917 typedef enum acl_type {
918    ACLENT_T = 0,
919    ACE_T = 1
920 } acl_type_t;
921 #endif
922
923 /**
924  * Two external references to functions in the libsec library function not in current include files.
925  */
926 extern "C" {
927 int acl_type(acl_t *);
928 char *acl_strerror(int);
929 }
930
931 /**
932  * Define the supported ACL streams for this OS
933  */
934 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT, STREAM_ACL_SOLARIS_ACE };
935 static int os_default_acl_streams[1] = { -1 };
936
937 /**
938  * As the new libsec interface with acl_totext and acl_fromtext also handles
939  * the old format from acltotext we can use the new functions even
940  * for acls retrieved and stored in the database with older fd versions. If the
941  * new interface is not defined (Solaris 9 and older we fall back to the old code)
942  */
943 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
944 {
945    int acl_enabled, flags;
946    acl_t *aclp;
947    char *acl_text;
948    bacl_exit_code stream_status = bacl_exit_error;
949    berrno be;
950
951    /**
952     * See if filesystem supports acls.
953     */
954    acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
955    switch (acl_enabled) {
956    case 0:
957       /**
958        * If the filesystem reports it doesn't support ACLs we clear the
959        * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
960        * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
961        * when we change from one filesystem to an other.
962        */
963       jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
964       pm_strcpy(jcr->acl_data->content, "");
965       jcr->acl_data->content_length = 0;
966       return bacl_exit_ok;
967    case -1:
968       switch (errno) {
969       case ENOENT:
970          return bacl_exit_ok;
971       default:
972          Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
973                jcr->last_fname, be.bstrerror());
974          Dmsg2(100, "pathconf error file=%s ERR=%s\n",  
975                jcr->last_fname, be.bstrerror());
976          return bacl_exit_error;
977       }
978    default:
979       break;
980    }
981
982    /**
983     * Get ACL info: don't bother allocating space if there is only a trivial ACL.
984     */
985    if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
986       switch (errno) {
987       case ENOENT:
988          return bacl_exit_ok;
989       default:
990          Mmsg2(jcr->errmsg, _("acl_get error on file \"%s\": ERR=%s\n"),
991                jcr->last_fname, acl_strerror(errno));
992          Dmsg2(100, "acl_get error file=%s ERR=%s\n",  
993                jcr->last_fname, acl_strerror(errno));
994          return bacl_exit_error;
995       }
996    }
997
998    if (!aclp) {
999       /**
1000        * The ACLs simply reflect the (already known) standard permissions
1001        * So we don't send an ACL stream to the SD.
1002        */
1003       pm_strcpy(jcr->acl_data->content, "");
1004       jcr->acl_data->content_length = 0;
1005       return bacl_exit_ok;
1006    }
1007
1008 #if defined(ACL_SID_FMT)
1009    /**
1010     * New format flag added in newer Solaris versions.
1011     */
1012    flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
1013 #else
1014    flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
1015 #endif /* ACL_SID_FMT */
1016
1017    if ((acl_text = acl_totext(aclp, flags)) != NULL) {
1018       jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1019       actuallyfree(acl_text);
1020
1021       switch (acl_type(aclp)) {
1022       case ACLENT_T:
1023          stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1024          break;
1025       case ACE_T:
1026          stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE);
1027          break;
1028       default:
1029          break;
1030       }
1031
1032       acl_free(aclp);
1033    }
1034    return stream_status;
1035 }
1036
1037 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
1038 {
1039    acl_t *aclp;
1040    int acl_enabled, error;
1041    berrno be;
1042
1043    switch (stream) {
1044    case STREAM_UNIX_ACCESS_ACL:
1045    case STREAM_ACL_SOLARIS_ACLENT:
1046    case STREAM_ACL_SOLARIS_ACE:
1047       /**
1048        * First make sure the filesystem supports acls.
1049        */
1050       acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1051       switch (acl_enabled) {
1052       case 0:
1053          Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
1054                jcr->last_fname);
1055          return bacl_exit_error;
1056       case -1:
1057          switch (errno) {
1058          case ENOENT:
1059             return bacl_exit_ok;
1060          default:
1061             Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1062                   jcr->last_fname, be.bstrerror());
1063             Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",  
1064                   jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1065             return bacl_exit_error;
1066          }
1067       default:
1068          /**
1069           * On a filesystem with ACL support make sure this particilar ACL type can be restored.
1070           */
1071          switch (stream) {
1072          case STREAM_ACL_SOLARIS_ACLENT:
1073             /**
1074              * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
1075              */
1076             if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
1077                Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without aclent acl support\n"),
1078                      jcr->last_fname);
1079                return bacl_exit_error;
1080             }
1081             break;
1082          case STREAM_ACL_SOLARIS_ACE:
1083             /**
1084              * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
1085              */
1086             if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
1087                Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without ace acl support\n"),
1088                      jcr->last_fname);
1089                return bacl_exit_error;
1090             }
1091             break;
1092          default:
1093             /**
1094              * Stream id which doesn't describe the type of acl which is encoded.
1095              */
1096             break;
1097          }
1098          break;
1099       }
1100
1101       if ((error = acl_fromtext(jcr->acl_data->content, &aclp)) != 0) {
1102          Mmsg2(jcr->errmsg, _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1103                jcr->last_fname, acl_strerror(error));
1104          Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",  
1105                jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1106          return bacl_exit_error;
1107       }
1108
1109       /**
1110        * Validate that the conversion gave us the correct acl type.
1111        */
1112       switch (stream) {
1113       case STREAM_ACL_SOLARIS_ACLENT:
1114          if (acl_type(aclp) != ACLENT_T) {
1115             Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1116                   jcr->last_fname);
1117             return bacl_exit_error;
1118          }
1119          break;
1120       case STREAM_ACL_SOLARIS_ACE:
1121          if (acl_type(aclp) != ACE_T) {
1122             Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1123                   jcr->last_fname);
1124             return bacl_exit_error;
1125          }
1126          break;
1127       default:
1128          /**
1129           * Stream id which doesn't describe the type of acl which is encoded.
1130           */
1131          break;
1132       }
1133
1134       /**
1135        * Restore the ACLs, but don't complain about links which really should
1136        * not have attributes, and the file it is linked to may not yet be restored.
1137        * This is only true for the old acl streams as in the new implementation we
1138        * don't save acls of symlinks (which cannot have acls anyhow)
1139        */
1140       if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1141          switch (errno) {
1142          case ENOENT:
1143             acl_free(aclp);
1144             return bacl_exit_ok;
1145          default:
1146             Mmsg2(jcr->errmsg, _("acl_set error on file \"%s\": ERR=%s\n"),
1147                   jcr->last_fname, acl_strerror(error));
1148             Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",  
1149                   jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1150             acl_free(aclp);
1151             return bacl_exit_error;
1152          }
1153       }
1154
1155       acl_free(aclp);
1156       return bacl_exit_ok;
1157    default:
1158       return bacl_exit_error;
1159    } /* end switch (stream) */
1160 }
1161
1162 #else /* HAVE_EXTENDED_ACL */
1163
1164 /**
1165  * Define the supported ACL streams for this OS
1166  */
1167 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT };
1168 static int os_default_acl_streams[1] = { -1 };
1169
1170 /**
1171  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1172  * There is no need to store those acls as we already store the stat bits too.
1173  */
1174 static bool acl_is_trivial(int count, aclent_t *entries)
1175 {
1176    int n;
1177    aclent_t *ace;
1178
1179    for (n = 0; n < count; n++) {
1180       ace = &entries[n];
1181
1182       if (!(ace->a_type == USER_OBJ ||
1183             ace->a_type == GROUP_OBJ ||
1184             ace->a_type == OTHER_OBJ ||
1185             ace->a_type == CLASS_OBJ))
1186         return false;
1187    }
1188    return true;
1189 }
1190
1191 /**
1192  * OS specific functions for handling different types of acl streams.
1193  */
1194 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1195 {
1196    int n;
1197    aclent_t *acls;
1198    char *acl_text;
1199    berrno be;
1200
1201    n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1202    if (n < MIN_ACL_ENTRIES)
1203       return bacl_exit_error;
1204
1205    acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1206    if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1207       if (acl_is_trivial(n, acls)) {
1208          /**
1209           * The ACLs simply reflect the (already known) standard permissions
1210           * So we don't send an ACL stream to the SD.
1211           */
1212          free(acls);
1213          pm_strcpy(jcr->acl_data->content, "");
1214          jcr->acl_data->content_length = 0;
1215          return bacl_exit_ok;
1216       }
1217
1218       if ((acl_text = acltotext(acls, n)) != NULL) {
1219          jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1220          actuallyfree(acl_text);
1221          free(acls);
1222          return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1223       }
1224
1225       Mmsg2(jcr->errmsg, _("acltotext error on file \"%s\": ERR=%s\n"),
1226             jcr->last_fname, be.bstrerror());
1227       Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",  
1228             jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1229    }
1230
1231    free(acls);
1232    return bacl_exit_error;
1233 }
1234
1235 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
1236 {
1237    int n;
1238    aclent_t *acls;
1239    berrno be;
1240
1241    acls = aclfromtext(jcr->acl_data->content, &n);
1242    if (!acls) {
1243       Mmsg2(jcr->errmsg, _("aclfromtext error on file \"%s\": ERR=%s\n"),
1244             jcr->last_fname, be.bstrerror());
1245       Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",  
1246             jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1247       return bacl_exit_error;
1248    }
1249
1250    /**
1251     * Restore the ACLs, but don't complain about links which really should
1252     * not have attributes, and the file it is linked to may not yet be restored.
1253     */
1254    if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
1255       switch (errno) {
1256       case ENOENT:
1257          actuallyfree(acls);
1258          return bacl_exit_ok;
1259       default:
1260          Mmsg2(jcr->errmsg, _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
1261                jcr->last_fname, be.bstrerror());
1262          Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
1263                jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1264          actuallyfree(acls);
1265          return bacl_exit_error;
1266       }
1267    }
1268    actuallyfree(acls);
1269    return bacl_exit_ok;
1270 }
1271 #endif /* HAVE_EXTENDED_ACL */
1272
1273 /**
1274  * For this OS setup the build and parse function pointer to the OS specific functions.
1275  */
1276 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_acl_streams;
1277 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = solaris_parse_acl_streams;
1278
1279 #endif /* HAVE_SUN_OS */
1280 #endif /* HAVE_ACL */
1281
1282 /*
1283  * Entry points when compiled with support for ACLs on a supported platform.
1284  */
1285
1286 /**
1287  * Read and send an ACL for the last encountered file.
1288  */
1289 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1290 {
1291    /**
1292     * See if we are changing from one device to an other.
1293     * We save the current device we are scanning and compare
1294     * it with the current st_dev in the last stat performed on
1295     * the file we are currently storing.
1296     */
1297    if (jcr->acl_data->current_dev != ff_pkt->statp.st_dev) {
1298       /**
1299        * Reset the acl save flags.
1300        */
1301       jcr->acl_data->flags = 0;
1302
1303       jcr->acl_data->flags |= BACL_FLAG_SAVE_NATIVE;
1304
1305       /**
1306        * Save that we started scanning a new filesystem.
1307        */
1308       jcr->acl_data->current_dev = ff_pkt->statp.st_dev;
1309    }
1310
1311 #if defined(HAVE_ACL)
1312    /**
1313     * See if the BACL_FLAG_SAVE_NATIVE flag is set which lets us know if we should
1314     * save native ACLs.
1315     */
1316    if (jcr->acl_data->flags & BACL_FLAG_SAVE_NATIVE) {
1317       /**
1318        * Call the appropriate function.
1319        */
1320       if (os_build_acl_streams) {
1321          return (*os_build_acl_streams)(jcr, ff_pkt);
1322       }
1323    } else {
1324       return bacl_exit_ok;
1325    }
1326 #endif
1327    return bacl_exit_error;
1328 }
1329
1330 bacl_exit_code parse_acl_streams(JCR *jcr, int stream)
1331 {
1332    unsigned int cnt;
1333
1334    switch (stream) {
1335 #if defined(HAVE_ACL)
1336    case STREAM_UNIX_ACCESS_ACL:
1337    case STREAM_UNIX_DEFAULT_ACL:
1338       /**
1339        * Handle legacy ACL streams.
1340        */
1341       if (os_parse_acl_streams) {
1342          return (*os_parse_acl_streams)(jcr, stream);
1343       }
1344       break;
1345    default:
1346       if (os_parse_acl_streams) {
1347          /**
1348           * Walk the os_access_acl_streams array with the supported Access ACL streams for this OS.
1349           */
1350          for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1351             if (os_access_acl_streams[cnt] == stream) {
1352                return (*os_parse_acl_streams)(jcr, stream);
1353             }
1354          }
1355          /**
1356           * Walk the os_default_acl_streams array with the supported Default ACL streams for this OS.
1357           */
1358          for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1359             if (os_default_acl_streams[cnt] == stream) {
1360                return (*os_parse_acl_streams)(jcr, stream);
1361             }
1362          }
1363       }
1364       break;
1365 #else
1366    default:
1367       break;
1368 #endif
1369    }
1370    Qmsg2(jcr, M_WARNING, 0,
1371       _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
1372       jcr->last_fname, stream);
1373    return bacl_exit_error;
1374 }
1375 #endif