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