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