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