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