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