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