]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/acl.c
Added support for NFSv4 ACLs added to FreeBSD 8.1.
[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 (POSIX and NFSv4/ZFS acls)
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  * On 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  * On FreeBSD we can get numeric ACLs
459  */
460 #if defined(HAVE_FREEBSD_OS)
461 #if defined(BACL_WANT_NUMERIC_IDS)
462 #define BACL_ALTERNATE_TEXT            ACL_TEXT_NUMERIC_IDS
463 #endif
464 #ifdef BACL_ALTERNATE_TEXT
465 #define acl_to_text(acl,len)     (acl_to_text_np((acl), (len), BACL_ALTERNATE_TEXT))
466 #endif
467 #endif
468
469 /**
470  * Some generic functions used by multiple OSes.
471  */
472 static acl_type_t bac_to_os_acltype(bacl_type acltype)
473 {
474    acl_type_t ostype;
475
476    switch (acltype) {
477    case BACL_TYPE_ACCESS:
478       ostype = ACL_TYPE_ACCESS;
479       break;
480    case BACL_TYPE_DEFAULT:
481       ostype = ACL_TYPE_DEFAULT;
482       break;
483 #ifdef ACL_TYPE_NFS4
484       /**
485        * FreeBSD has an additional acl type named ACL_TYPE_NFS4.
486        */
487    case BACL_TYPE_NFS4:
488       ostype = ACL_TYPE_NFS4;
489       break;
490 #endif
491 #ifdef ACL_TYPE_DEFAULT_DIR
492    case BACL_TYPE_DEFAULT_DIR:
493       /**
494        * TRU64 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
495        */
496       ostype = ACL_TYPE_DEFAULT_DIR;
497       break;
498 #endif
499 #ifdef ACL_TYPE_EXTENDED
500    case BACL_TYPE_EXTENDED:
501       /**
502        * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
503        */
504       ostype = ACL_TYPE_EXTENDED;
505       break;
506 #endif
507    default:
508       /**
509        * This should never happen, as the per OS version function only tries acl
510        * types supported on a certain platform.
511        */
512       ostype = (acl_type_t)ACL_TYPE_NONE;
513       break;
514    }
515    return ostype;
516 }
517
518 #if !defined(HAVE_DARWIN_OS)
519 /**
520  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
521  * There is no need to store those acls as we already store the stat bits too.
522  */
523 static bool acl_is_trivial(acl_t acl)
524 {
525   /**
526    * acl is trivial if it has only the following entries:
527    * "user::",
528    * "group::",
529    * "other::"
530    */
531    acl_entry_t ace;
532    acl_tag_t tag;
533 #if defined(HAVE_FREEBSD_OS) || \
534     defined(HAVE_LINUX_OS)
535    int entry_available;
536
537    entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
538    while (entry_available == 1) {
539       /**
540        * Get the tag type of this acl entry.
541        * If we fail to get the tagtype we call the acl non-trivial.
542        */
543       if (acl_get_tag_type(ace, &tag) < 0)
544          return true;
545       /**
546        * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
547        */
548       if (tag != ACL_USER_OBJ &&
549           tag != ACL_GROUP_OBJ &&
550           tag != ACL_OTHER)
551          return false;
552       entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
553    }
554    return true;
555 #elif defined(HAVE_IRIX_OS)
556    int n;
557
558    for (n = 0; n < acl->acl_cnt; n++) {
559       ace = &acl->acl_entry[n];
560       tag = ace->ae_tag;
561
562       /**
563        * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
564        */
565       if (tag != ACL_USER_OBJ &&
566           tag != ACL_GROUP_OBJ &&
567           tag != ACL_OTHER_OBJ)
568          return false;
569    }
570    return true;
571 #elif defined(HAVE_OSF1_OS)
572    int count;
573
574    ace = acl->acl_first;
575    count = acl->acl_num;
576
577    while (count > 0) {
578       tag = ace->entry->acl_type;
579       /**
580        * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
581        */
582       if (tag != ACL_USER_OBJ &&
583           tag != ACL_GROUP_OBJ &&
584           tag != ACL_OTHER)
585          return false;
586       /**
587        * On Tru64, perm can also contain non-standard bits such as
588        * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
589        */
590       if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
591          return false;
592       ace = ace->next;
593       count--;
594    }
595    return true;
596 #endif
597 }
598 #endif
599
600 /**
601  * Generic wrapper around acl_get_file call.
602  */
603 static bacl_exit_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
604 {
605    acl_t acl;
606    acl_type_t ostype;
607    char *acl_text;
608    berrno be;
609
610    ostype = bac_to_os_acltype(acltype);
611    acl = acl_get_file(jcr->last_fname, ostype);
612    if (acl) {
613 #if defined(HAVE_IRIX_OS)
614       /**
615        * From observation, IRIX's acl_get_file() seems to return a
616        * non-NULL acl with a count field of -1 when a file has no ACL
617        * defined, while IRIX's acl_to_text() returns NULL when presented
618        * with such an ACL. 
619        *
620        * Checking the count in the acl structure before calling
621        * acl_to_text() lets us avoid error messages about files
622        * with no ACLs, without modifying the flow of the code used for 
623        * other operating systems, and it saves making some calls
624        * to acl_to_text() besides.
625        */
626       if (acl->acl_cnt <= 0) {
627          pm_strcpy(jcr->acl_data->content, "");
628          jcr->acl_data->content_length = 0;
629          acl_free(acl);
630          return bacl_exit_ok;
631       }
632 #endif
633
634       /**
635        * Make sure this is not just a trivial ACL.
636        */
637 #if !defined(HAVE_DARWIN_OS)
638       if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
639          /**
640           * The ACLs simply reflect the (already known) standard permissions
641           * So we don't send an ACL stream to the SD.
642           */
643          pm_strcpy(jcr->acl_data->content, "");
644          jcr->acl_data->content_length = 0;
645          acl_free(acl);
646          return bacl_exit_ok;
647       }
648 #endif
649 #if defined(HAVE_FREEBSD_OS) && defined(_PC_ACL_NFS4)
650       if (acltype == BACL_TYPE_NFS4) {
651          int trivial;
652          if (acl_is_trivial_np(acl, &trivial) == 0) {
653             if (trivial == 1) {
654                /**
655                 * The ACLs simply reflect the (already known) standard permissions
656                 * So we don't send an ACL stream to the SD.
657                 */
658                pm_strcpy(jcr->acl_data->content, "");
659                jcr->acl_data->content_length = 0;
660                acl_free(acl);
661                return bacl_exit_ok;
662             }
663          }
664       }
665 #endif
666
667       if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
668          jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
669          acl_free(acl);
670          acl_free(acl_text);
671          return bacl_exit_ok;
672       }
673
674       Mmsg2(jcr->errmsg, _("acl_to_text error on file \"%s\": ERR=%s\n"),
675             jcr->last_fname, be.bstrerror());
676       Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",  
677             jcr->last_fname, be.bstrerror());
678
679       pm_strcpy(jcr->acl_data->content, "");
680       jcr->acl_data->content_length = 0;
681       acl_free(acl);
682       return bacl_exit_error;
683    }
684
685    /**
686     * Handle errors gracefully.
687     */
688    if (acl == (acl_t)NULL) {
689       switch (errno) {
690 #if defined(BACL_ENOTSUP)
691       case BACL_ENOTSUP:
692          /**
693           * If the filesystem reports it doesn't support ACLs we clear the
694           * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
695           * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
696           * when we change from one filesystem to an other.
697           */
698          jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
699          break;                       /* not supported */
700 #endif
701       case ENOENT:
702          pm_strcpy(jcr->acl_data->content, "");
703          jcr->acl_data->content_length = 0;
704          return bacl_exit_ok;
705       default:
706          /* Some real error */
707          Mmsg2(jcr->errmsg, _("acl_get_file error on file \"%s\": ERR=%s\n"),
708                jcr->last_fname, be.bstrerror());
709          Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",  
710                jcr->last_fname, be.bstrerror());
711
712          pm_strcpy(jcr->acl_data->content, "");
713          jcr->acl_data->content_length = 0;
714          return bacl_exit_error;
715       }
716    }
717
718    /**
719     * Not supported, just pretend there is nothing to see
720     */
721    pm_strcpy(jcr->acl_data->content, "");
722    jcr->acl_data->content_length = 0;
723    return bacl_exit_ok;
724 }
725
726 /**
727  * Generic wrapper around acl_set_file call.
728  */
729 static bacl_exit_code generic_set_acl_on_os(JCR *jcr, bacl_type acltype)
730 {
731    acl_t acl;
732    acl_type_t ostype;
733    berrno be;
734
735    /**
736     * If we get empty default ACLs, clear ACLs now
737     */
738    ostype = bac_to_os_acltype(acltype);
739    if (ostype == ACL_TYPE_DEFAULT && strlen(jcr->acl_data->content) == 0) {
740       if (acl_delete_def_file(jcr->last_fname) == 0) {
741          return bacl_exit_ok;
742       }
743       switch (errno) {
744       case ENOENT:
745          return bacl_exit_ok;
746       default:
747          Mmsg2(jcr->errmsg, _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
748                jcr->last_fname, be.bstrerror());
749          return bacl_exit_error;
750       }
751    }
752
753    acl = acl_from_text(jcr->acl_data->content);
754    if (acl == NULL) {
755       Mmsg2(jcr->errmsg, _("acl_from_text error on file \"%s\": ERR=%s\n"),
756             jcr->last_fname, be.bstrerror());
757       Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",  
758          jcr->acl_data->content, jcr->last_fname, be.bstrerror());
759       return bacl_exit_error;
760    }
761
762 #ifndef HAVE_FREEBSD_OS
763    /**
764     * FreeBSD always fails acl_valid() - at least on valid input...
765     * As it does the right thing, given valid input, just ignore acl_valid().
766     */
767    if (acl_valid(acl) != 0) {
768       Mmsg2(jcr->errmsg, _("acl_valid error on file \"%s\": ERR=%s\n"),
769             jcr->last_fname, be.bstrerror());
770       Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",  
771          jcr->acl_data->content, jcr->last_fname, be.bstrerror());
772       acl_free(acl);
773       return bacl_exit_error;
774    }
775 #endif
776
777    /**
778     * Restore the ACLs, but don't complain about links which really should
779     * not have attributes, and the file it is linked to may not yet be restored.
780     * This is only true for the old acl streams as in the new implementation we
781     * don't save acls of symlinks (which cannot have acls anyhow)
782     */
783    if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
784       switch (errno) {
785       case ENOENT:
786          acl_free(acl);
787          return bacl_exit_ok;
788       default:
789          Mmsg2(jcr->errmsg, _("acl_set_file error on file \"%s\": ERR=%s\n"),
790                jcr->last_fname, be.bstrerror());
791          Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
792                jcr->acl_data->content, jcr->last_fname, be.bstrerror());
793          acl_free(acl);
794          return bacl_exit_error;
795       }
796    }
797    acl_free(acl);
798    return bacl_exit_ok;
799 }
800
801 /**
802  * OS specific functions for handling different types of acl streams.
803  */
804 #if defined(HAVE_DARWIN_OS)
805 /**
806  * Define the supported ACL streams for this OS
807  */
808 static int os_access_acl_streams[1] = { STREAM_ACL_DARWIN_ACCESS_ACL };
809 static int os_default_acl_streams[1] = { -1 };
810
811 static bacl_exit_code darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
812 {
813 #if defined(ACL_TYPE_EXTENDED)
814    /**
815     * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
816     * and acl_get_file (name, ACL_TYPE_DEFAULT)
817     * always return NULL / EINVAL.  There is no point in making
818     * these two useless calls.  The real ACL is retrieved through
819     * acl_get_file (name, ACL_TYPE_EXTENDED).
820     *
821     * Read access ACLs for files, dirs and links
822     */
823    if (generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED) == bacl_exit_fatal)
824       return bacl_exit_fatal;
825 #else
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 #endif
832
833    if (jcr->acl_data->content_length > 0) {
834       return send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL);
835    }
836    return bacl_exit_ok;
837 }
838
839 static bacl_exit_code darwin_parse_acl_streams(JCR *jcr, int stream)
840 {
841 #if defined(ACL_TYPE_EXTENDED)
842       return generic_set_acl_on_os(jcr, BACL_TYPE_EXTENDED);
843 #else
844       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
845 #endif
846 }
847
848 /**
849  * For this OS setup the build and parse function pointer to the OS specific functions.
850  */
851 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = darwin_build_acl_streams;
852 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = darwin_parse_acl_streams;
853
854 #elif defined(HAVE_FREEBSD_OS)
855 /**
856  * Define the supported ACL streams for these OSes
857  */
858 static int os_access_acl_streams[2] = { STREAM_ACL_FREEBSD_ACCESS_ACL, STREAM_ACL_FREEBSD_NFS4_ACL };
859 static int os_default_acl_streams[1] = { STREAM_ACL_FREEBSD_DEFAULT_ACL };
860
861 static bacl_exit_code freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
862 {
863    int acl_enabled = 0;
864    bacl_type acltype = BACL_TYPE_NONE;
865    berrno be;
866
867 #if defined(_PC_ACL_NFS4)
868    /**
869     * See if filesystem supports NFS4 acls.
870     */
871    acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
872    switch (acl_enabled) {
873    case -1:
874       switch (errno) {
875       case ENOENT:
876          return bacl_exit_ok;
877       default:
878          Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
879                jcr->last_fname, be.bstrerror());
880          Dmsg2(100, "pathconf error file=%s ERR=%s\n",
881                jcr->last_fname, be.bstrerror());
882          return bacl_exit_error;
883       }
884    default:
885       acltype = BACL_TYPE_NFS4;
886       break;
887    }
888 #endif
889
890    if (acl_enabled == 0) {
891       /**
892        * See if filesystem supports POSIX acls.
893        */
894       acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
895       switch (acl_enabled) {
896       case -1:
897          switch (errno) {
898          case ENOENT:
899             return bacl_exit_ok;
900          default:
901             Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
902                   jcr->last_fname, be.bstrerror());
903             Dmsg2(100, "pathconf error file=%s ERR=%s\n",
904                   jcr->last_fname, be.bstrerror());
905             return bacl_exit_error;
906          }
907       default:
908          acltype = BACL_TYPE_ACCESS;
909          break;
910       }
911    }
912
913    /**
914     * If the filesystem reports it doesn't support ACLs we clear the
915     * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
916     * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
917     * when we change from one filesystem to an other.
918     */
919    if (acl_enabled == 0) {
920       jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
921       pm_strcpy(jcr->acl_data->content, "");
922       jcr->acl_data->content_length = 0;
923       return bacl_exit_ok;
924    }
925
926    /**
927     * Based on the supported ACLs retrieve and store them.
928     */
929    switch (acltype) {
930    case BACL_TYPE_NFS4:
931       /**
932        * Read NFS4 ACLs for files, dirs and links
933        */
934       if (generic_get_acl_from_os(jcr, BACL_TYPE_NFS4) == bacl_exit_fatal)
935          return bacl_exit_fatal;
936
937       if (jcr->acl_data->content_length > 0) {
938          if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_NFS4_ACL) == bacl_exit_fatal)
939             return bacl_exit_fatal;
940       }
941       break;
942    case BACL_TYPE_ACCESS:
943       /**
944        * Read access ACLs for files, dirs and links
945        */
946       if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
947          return bacl_exit_fatal;
948
949       if (jcr->acl_data->content_length > 0) {
950          if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_ACCESS_ACL) == bacl_exit_fatal)
951             return bacl_exit_fatal;
952       }
953
954       /**
955        * Directories can have default ACLs too
956        */
957       if (ff_pkt->type == FT_DIREND) {
958          if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
959             return bacl_exit_fatal;
960          if (jcr->acl_data->content_length > 0) {
961             if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_DEFAULT_ACL) == bacl_exit_fatal)
962                return bacl_exit_fatal;
963          }
964       }
965       break;
966    default:
967       break;
968    }
969
970    return bacl_exit_ok;
971 }
972
973 static bacl_exit_code freebsd_parse_acl_streams(JCR *jcr, int stream)
974 {
975    int acl_enabled = 0;
976    berrno be;
977
978    /**
979     * First make sure the filesystem supports acls.
980     */
981    switch (stream) {
982    case STREAM_UNIX_ACCESS_ACL:
983    case STREAM_ACL_FREEBSD_ACCESS_ACL:
984    case STREAM_UNIX_DEFAULT_ACL:
985    case STREAM_ACL_FREEBSD_DEFAULT_ACL:
986       acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
987       break;
988    case STREAM_ACL_FREEBSD_NFS4_ACL:
989 #if defined(_PC_ACL_NFS4)
990       acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
991 #endif
992       break;
993    default:
994       break;
995    }
996
997    switch (acl_enabled) {
998    case 0:
999       Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
1000             jcr->last_fname);
1001       return bacl_exit_error;
1002    case -1:
1003       switch (errno) {
1004       case ENOENT:
1005          return bacl_exit_ok;
1006       default:
1007          Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1008                jcr->last_fname, be.bstrerror());
1009          Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1010                jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1011          return bacl_exit_error;
1012       }
1013    }
1014
1015    /**
1016     * Restore the ACLs.
1017     */
1018    switch (stream) {
1019    case STREAM_UNIX_ACCESS_ACL:
1020    case STREAM_ACL_FREEBSD_ACCESS_ACL:
1021       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
1022    case STREAM_UNIX_DEFAULT_ACL:
1023    case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1024       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
1025    case STREAM_ACL_FREEBSD_NFS4_ACL:
1026       return generic_set_acl_on_os(jcr, BACL_TYPE_NFS4);
1027    default:
1028       break;
1029    }
1030    return bacl_exit_error;
1031 }
1032
1033 /**
1034  * For this OSes setup the build and parse function pointer to the OS specific functions.
1035  */
1036 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = freebsd_build_acl_streams;
1037 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = freebsd_parse_acl_streams;
1038
1039 #elif defined(HAVE_IRIX_OS) || \
1040       defined(HAVE_LINUX_OS)
1041 /**
1042  * Define the supported ACL streams for these OSes
1043  */
1044 #if defined(HAVE_IRIX_OS)
1045 static int os_access_acl_streams[1] = { STREAM_ACL_IRIX_ACCESS_ACL };
1046 static int os_default_acl_streams[1] = { STREAM_ACL_IRIX_DEFAULT_ACL };
1047 #elif defined(HAVE_LINUX_OS)
1048 static int os_access_acl_streams[1] = { STREAM_ACL_LINUX_ACCESS_ACL };
1049 static int os_default_acl_streams[1] = { STREAM_ACL_LINUX_DEFAULT_ACL };
1050 #endif
1051
1052 static bacl_exit_code generic_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1053 {
1054    /**
1055     * Read access ACLs for files, dirs and links
1056     */
1057    if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1058       return bacl_exit_fatal;
1059
1060    if (jcr->acl_data->content_length > 0) {
1061       if (send_acl_stream(jcr, os_access_acl_streams[0]) == bacl_exit_fatal)
1062          return bacl_exit_fatal;
1063    }
1064
1065    /**
1066     * Directories can have default ACLs too
1067     */
1068    if (ff_pkt->type == FT_DIREND) {
1069       if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
1070          return bacl_exit_fatal;
1071       if (jcr->acl_data->content_length > 0) {
1072          if (send_acl_stream(jcr, os_default_acl_streams[0]) == bacl_exit_fatal)
1073             return bacl_exit_fatal;
1074       }
1075    }
1076    return bacl_exit_ok;
1077 }
1078
1079 static bacl_exit_code generic_parse_acl_streams(JCR *jcr, int stream)
1080 {
1081    unsigned int cnt;
1082
1083    switch (stream) {
1084    case STREAM_UNIX_ACCESS_ACL:
1085       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
1086    case STREAM_UNIX_DEFAULT_ACL:
1087       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
1088    default:
1089       /**
1090        * See what type of acl it is.
1091        */
1092       for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1093          if (os_access_acl_streams[cnt] == stream) {
1094             return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
1095          }
1096       }
1097       for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1098          if (os_default_acl_streams[cnt] == stream) {
1099             return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
1100          }
1101       }
1102       break;
1103    }
1104    return bacl_exit_error;
1105 }
1106
1107 /**
1108  * For this OSes setup the build and parse function pointer to the OS specific functions.
1109  */
1110 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_build_acl_streams;
1111 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = generic_parse_acl_streams;
1112
1113 #elif defined(HAVE_OSF1_OS)
1114
1115 /**
1116  * Define the supported ACL streams for this OS
1117  */
1118 static int os_access_acl_streams[1] = { STREAM_ACL_TRU64_ACCESS_ACL };
1119 static int os_default_acl_streams[2] = { STREAM_ACL_TRU64_DEFAULT_ACL, STREAM_ACL_TRU64_DEFAULT_DIR_ACL };
1120
1121 static bacl_exit_code tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1122 {
1123    /**
1124     * Read access ACLs for files, dirs and links
1125     */
1126    if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
1127       return bacl_exit_error;
1128    if (jcr->acl_data->content_length > 0) {
1129       if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL))
1130          return bacl_exit_error;
1131    }
1132    /**
1133     * Directories can have default ACLs too
1134     */
1135    if (ff_pkt->type == FT_DIREND) {
1136       if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
1137          return bacl_exit_error;
1138       if (jcr->acl_data->content_length > 0) {
1139          if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL))
1140             return bacl_exit_error;
1141       }
1142       /**
1143        * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
1144        * This is an inherited acl for all subdirs.
1145        * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
1146        * Section 21.5 Default ACLs 
1147        */
1148       if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR)) < 0)
1149          return bacl_exit_error;
1150       if (jcr->acl_data->content_length > 0) {
1151          if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL))
1152             return bacl_exit_error;
1153       }
1154    }
1155    return bacl_exit_ok;
1156 }
1157
1158 static bacl_exit_code tru64_parse_acl_streams(JCR *jcr, int stream)
1159 {
1160    switch (stream) {
1161    case STREAM_UNIX_ACCESS_ACL:
1162    case STREAM_ACL_TRU64_ACCESS_ACL:
1163       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
1164    case STREAM_UNIX_DEFAULT_ACL:
1165    case STREAM_ACL_TRU64_DEFAULT_ACL:
1166       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
1167    case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
1168       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR);
1169 }
1170
1171 /**
1172  * For this OS setup the build and parse function pointer to the OS specific functions.
1173  */
1174 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = tru64_build_acl_streams;
1175 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = tru64_parse_acl_streams;
1176
1177 #endif
1178
1179 #elif defined(HAVE_HPUX_OS)
1180 #ifdef HAVE_SYS_ACL_H
1181 #include <sys/acl.h>
1182 #else
1183 #error "configure failed to detect availability of sys/acl.h"
1184 #endif
1185
1186 #include <acllib.h>
1187
1188 /**
1189  * Define the supported ACL streams for this OS
1190  */
1191 static int os_access_acl_streams[1] = { STREAM_ACL_HPUX_ACL_ENTRY };
1192 static int os_default_acl_streams[1] = { -1 };
1193
1194 /**
1195  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1196  * There is no need to store those acls as we already store the stat bits too.
1197  */
1198 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
1199 {
1200    int n;
1201    struct acl_entry ace
1202
1203    for (n = 0; n < count; n++) {
1204       ace = entries[n];
1205       /**
1206        * See if this acl just is the stat mode in acl form.
1207        */
1208       if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
1209             (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
1210             (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
1211          return false;
1212    }
1213    return true;
1214 }
1215
1216 /**
1217  * OS specific functions for handling different types of acl streams.
1218  */
1219 static bacl_exit_code hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1220 {
1221    int n;
1222    struct acl_entry acls[NACLENTRIES];
1223    char *acl_text;
1224    berrno be;
1225
1226    if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
1227       switch (errno) {
1228 #if defined(BACL_ENOTSUP)
1229       case BACL_ENOTSUP:
1230          /**
1231           * Not supported, just pretend there is nothing to see
1232           *
1233           * If the filesystem reports it doesn't support ACLs we clear the
1234           * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1235           * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1236           * when we change from one filesystem to an other.
1237           */
1238          jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1239          pm_strcpy(jcr->acl_data->content, "");
1240          jcr->acl_data->content_length = 0;
1241          return bacl_exit_ok;
1242 #endif
1243       case ENOENT:
1244          pm_strcpy(jcr->acl_data->content, "");
1245          jcr->acl_data->content_length = 0;
1246          return bacl_exit_ok;
1247       default:
1248          Mmsg2(jcr->errmsg, _("getacl error on file \"%s\": ERR=%s\n"),
1249                jcr->last_fname, be.bstrerror());
1250          Dmsg2(100, "getacl error file=%s ERR=%s\n",  
1251                jcr->last_fname, be.bstrerror());
1252
1253          pm_strcpy(jcr->acl_data->content, "");
1254          jcr->acl_data->content_length = 0;
1255          return bacl_exit_error;
1256       }
1257    }
1258    if (n == 0) {
1259       pm_strcpy(jcr->acl_data->content, "");
1260       jcr->acl_data->content_length = 0;
1261       return bacl_exit_ok;
1262    }
1263    if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
1264       if (acl_is_trivial(n, acls, ff_pkt->statp)) {
1265          /**
1266           * The ACLs simply reflect the (already known) standard permissions
1267           * So we don't send an ACL stream to the SD.
1268           */
1269          pm_strcpy(jcr->acl_data->content, "");
1270          jcr->acl_data->content_length = 0;
1271          return bacl_exit_ok;
1272       }
1273       if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
1274          jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1275          actuallyfree(acl_text);
1276
1277          return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
1278       }
1279       Mmsg2(jcr->errmsg, _("acltostr error on file \"%s\": ERR=%s\n"),
1280             jcr->last_fname, be.bstrerror());
1281       Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",  
1282             jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1283       return bacl_exit_error;
1284    }
1285    return bacl_exit_error;
1286 }
1287
1288 static bacl_exit_code hpux_parse_acl_streams(JCR *jcr, int stream)
1289 {
1290    int n, stat;
1291    struct acl_entry acls[NACLENTRIES];
1292    berrno be;
1293
1294    n = strtoacl(jcr->acl_data->content, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
1295    if (n <= 0) {
1296       Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
1297             jcr->last_fname, be.bstrerror());
1298       Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",  
1299             jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1300       return bacl_exit_error;
1301    }
1302    if (strtoacl(jcr->acl_data->content, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
1303       Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
1304             jcr->last_fname, be.bstrerror());
1305       Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",  
1306             jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1307
1308       return bacl_exit_error;
1309    }
1310    /**
1311     * Restore the ACLs, but don't complain about links which really should
1312     * not have attributes, and the file it is linked to may not yet be restored.
1313     * This is only true for the old acl streams as in the new implementation we
1314     * don't save acls of symlinks (which cannot have acls anyhow)
1315     */
1316    if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
1317       switch (errno) {
1318       case ENOENT:
1319          return bacl_exit_ok;
1320       default:
1321          Mmsg2(jcr->errmsg, _("setacl error on file \"%s\": ERR=%s\n"),
1322                jcr->last_fname, be.bstrerror());
1323          Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
1324                jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1325          return bacl_exit_error;
1326       }
1327    }
1328    return bacl_exit_ok;
1329 }
1330
1331 /**
1332  * For this OS setup the build and parse function pointer to the OS specific functions.
1333  */
1334 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = hpux_build_acl_streams;
1335 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = hpux_parse_acl_streams;
1336
1337 #elif defined(HAVE_SUN_OS)
1338 #ifdef HAVE_SYS_ACL_H
1339 #include <sys/acl.h>
1340 #else
1341 #error "configure failed to detect availability of sys/acl.h"
1342 #endif
1343
1344 #if defined(HAVE_EXTENDED_ACL)
1345 /**
1346  * We define some internals of the Solaris acl libs here as those
1347  * are not exposed yet. Probably because they want us to see the
1348  * acls as opague data. But as we need to support different platforms
1349  * and versions of Solaris we need to expose some data to be able
1350  * to determine the type of acl used to stuff it into the correct
1351  * data stream. I know this is far from portable, but maybe the
1352  * proper interface is exposed later on and we can get ride of
1353  * this kludge. Newer versions of Solaris include sys/acl_impl.h
1354  * which has implementation details of acls, if thats included we
1355  * don't have to define it ourself.
1356  */
1357 #if !defined(_SYS_ACL_IMPL_H)
1358 typedef enum acl_type {
1359    ACLENT_T = 0,
1360    ACE_T = 1
1361 } acl_type_t;
1362 #endif
1363
1364 /**
1365  * Two external references to functions in the libsec library function not in current include files.
1366  */
1367 extern "C" {
1368 int acl_type(acl_t *);
1369 char *acl_strerror(int);
1370 }
1371
1372 /**
1373  * Define the supported ACL streams for this OS
1374  */
1375 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT, STREAM_ACL_SOLARIS_ACE };
1376 static int os_default_acl_streams[1] = { -1 };
1377
1378 /**
1379  * As the new libsec interface with acl_totext and acl_fromtext also handles
1380  * the old format from acltotext we can use the new functions even
1381  * for acls retrieved and stored in the database with older fd versions. If the
1382  * new interface is not defined (Solaris 9 and older we fall back to the old code)
1383  */
1384 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1385 {
1386    int acl_enabled, flags;
1387    acl_t *aclp;
1388    char *acl_text;
1389    bacl_exit_code stream_status = bacl_exit_error;
1390    berrno be;
1391
1392    /**
1393     * See if filesystem supports acls.
1394     */
1395    acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1396    switch (acl_enabled) {
1397    case 0:
1398       /**
1399        * If the filesystem reports it doesn't support ACLs we clear the
1400        * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1401        * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1402        * when we change from one filesystem to an other.
1403        */
1404       jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1405       pm_strcpy(jcr->acl_data->content, "");
1406       jcr->acl_data->content_length = 0;
1407       return bacl_exit_ok;
1408    case -1:
1409       switch (errno) {
1410       case ENOENT:
1411          return bacl_exit_ok;
1412       default:
1413          Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1414                jcr->last_fname, be.bstrerror());
1415          Dmsg2(100, "pathconf error file=%s ERR=%s\n",  
1416                jcr->last_fname, be.bstrerror());
1417          return bacl_exit_error;
1418       }
1419    default:
1420       break;
1421    }
1422
1423    /**
1424     * Get ACL info: don't bother allocating space if there is only a trivial ACL.
1425     */
1426    if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
1427       switch (errno) {
1428       case ENOENT:
1429          return bacl_exit_ok;
1430       default:
1431          Mmsg2(jcr->errmsg, _("acl_get error on file \"%s\": ERR=%s\n"),
1432                jcr->last_fname, acl_strerror(errno));
1433          Dmsg2(100, "acl_get error file=%s ERR=%s\n",  
1434                jcr->last_fname, acl_strerror(errno));
1435          return bacl_exit_error;
1436       }
1437    }
1438
1439    if (!aclp) {
1440       /**
1441        * The ACLs simply reflect the (already known) standard permissions
1442        * So we don't send an ACL stream to the SD.
1443        */
1444       pm_strcpy(jcr->acl_data->content, "");
1445       jcr->acl_data->content_length = 0;
1446       return bacl_exit_ok;
1447    }
1448
1449 #if defined(ACL_SID_FMT)
1450    /**
1451     * New format flag added in newer Solaris versions.
1452     */
1453    flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
1454 #else
1455    flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
1456 #endif /* ACL_SID_FMT */
1457
1458    if ((acl_text = acl_totext(aclp, flags)) != NULL) {
1459       jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1460       actuallyfree(acl_text);
1461
1462       switch (acl_type(aclp)) {
1463       case ACLENT_T:
1464          stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1465          break;
1466       case ACE_T:
1467          stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE);
1468          break;
1469       default:
1470          break;
1471       }
1472
1473       acl_free(aclp);
1474    }
1475    return stream_status;
1476 }
1477
1478 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
1479 {
1480    acl_t *aclp;
1481    int acl_enabled, error;
1482    berrno be;
1483
1484    switch (stream) {
1485    case STREAM_UNIX_ACCESS_ACL:
1486    case STREAM_ACL_SOLARIS_ACLENT:
1487    case STREAM_ACL_SOLARIS_ACE:
1488       /**
1489        * First make sure the filesystem supports acls.
1490        */
1491       acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1492       switch (acl_enabled) {
1493       case 0:
1494          Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
1495                jcr->last_fname);
1496          return bacl_exit_error;
1497       case -1:
1498          switch (errno) {
1499          case ENOENT:
1500             return bacl_exit_ok;
1501          default:
1502             Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1503                   jcr->last_fname, be.bstrerror());
1504             Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",  
1505                   jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1506             return bacl_exit_error;
1507          }
1508       default:
1509          /**
1510           * On a filesystem with ACL support make sure this particular ACL type can be restored.
1511           */
1512          switch (stream) {
1513          case STREAM_ACL_SOLARIS_ACLENT:
1514             /**
1515              * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
1516              */
1517             if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
1518                Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without aclent acl support\n"),
1519                      jcr->last_fname);
1520                return bacl_exit_error;
1521             }
1522             break;
1523          case STREAM_ACL_SOLARIS_ACE:
1524             /**
1525              * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
1526              */
1527             if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
1528                Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without ace acl support\n"),
1529                      jcr->last_fname);
1530                return bacl_exit_error;
1531             }
1532             break;
1533          default:
1534             /**
1535              * Stream id which doesn't describe the type of acl which is encoded.
1536              */
1537             break;
1538          }
1539          break;
1540       }
1541
1542       if ((error = acl_fromtext(jcr->acl_data->content, &aclp)) != 0) {
1543          Mmsg2(jcr->errmsg, _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1544                jcr->last_fname, acl_strerror(error));
1545          Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",  
1546                jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1547          return bacl_exit_error;
1548       }
1549
1550       /**
1551        * Validate that the conversion gave us the correct acl type.
1552        */
1553       switch (stream) {
1554       case STREAM_ACL_SOLARIS_ACLENT:
1555          if (acl_type(aclp) != ACLENT_T) {
1556             Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1557                   jcr->last_fname);
1558             return bacl_exit_error;
1559          }
1560          break;
1561       case STREAM_ACL_SOLARIS_ACE:
1562          if (acl_type(aclp) != ACE_T) {
1563             Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1564                   jcr->last_fname);
1565             return bacl_exit_error;
1566          }
1567          break;
1568       default:
1569          /**
1570           * Stream id which doesn't describe the type of acl which is encoded.
1571           */
1572          break;
1573       }
1574
1575       /**
1576        * Restore the ACLs, but don't complain about links which really should
1577        * not have attributes, and the file it is linked to may not yet be restored.
1578        * This is only true for the old acl streams as in the new implementation we
1579        * don't save acls of symlinks (which cannot have acls anyhow)
1580        */
1581       if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1582          switch (errno) {
1583          case ENOENT:
1584             acl_free(aclp);
1585             return bacl_exit_ok;
1586          default:
1587             Mmsg2(jcr->errmsg, _("acl_set error on file \"%s\": ERR=%s\n"),
1588                   jcr->last_fname, acl_strerror(error));
1589             Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",  
1590                   jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1591             acl_free(aclp);
1592             return bacl_exit_error;
1593          }
1594       }
1595
1596       acl_free(aclp);
1597       return bacl_exit_ok;
1598    default:
1599       return bacl_exit_error;
1600    } /* end switch (stream) */
1601 }
1602
1603 #else /* HAVE_EXTENDED_ACL */
1604
1605 /**
1606  * Define the supported ACL streams for this OS
1607  */
1608 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT };
1609 static int os_default_acl_streams[1] = { -1 };
1610
1611 /**
1612  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1613  * There is no need to store those acls as we already store the stat bits too.
1614  */
1615 static bool acl_is_trivial(int count, aclent_t *entries)
1616 {
1617    int n;
1618    aclent_t *ace;
1619
1620    for (n = 0; n < count; n++) {
1621       ace = &entries[n];
1622
1623       if (!(ace->a_type == USER_OBJ ||
1624             ace->a_type == GROUP_OBJ ||
1625             ace->a_type == OTHER_OBJ ||
1626             ace->a_type == CLASS_OBJ))
1627         return false;
1628    }
1629    return true;
1630 }
1631
1632 /**
1633  * OS specific functions for handling different types of acl streams.
1634  */
1635 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1636 {
1637    int n;
1638    aclent_t *acls;
1639    char *acl_text;
1640    berrno be;
1641
1642    n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1643    if (n < MIN_ACL_ENTRIES)
1644       return bacl_exit_error;
1645
1646    acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1647    if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1648       if (acl_is_trivial(n, acls)) {
1649          /**
1650           * The ACLs simply reflect the (already known) standard permissions
1651           * So we don't send an ACL stream to the SD.
1652           */
1653          free(acls);
1654          pm_strcpy(jcr->acl_data->content, "");
1655          jcr->acl_data->content_length = 0;
1656          return bacl_exit_ok;
1657       }
1658
1659       if ((acl_text = acltotext(acls, n)) != NULL) {
1660          jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1661          actuallyfree(acl_text);
1662          free(acls);
1663          return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1664       }
1665
1666       Mmsg2(jcr->errmsg, _("acltotext error on file \"%s\": ERR=%s\n"),
1667             jcr->last_fname, be.bstrerror());
1668       Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",  
1669             jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1670    }
1671
1672    free(acls);
1673    return bacl_exit_error;
1674 }
1675
1676 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
1677 {
1678    int n;
1679    aclent_t *acls;
1680    berrno be;
1681
1682    acls = aclfromtext(jcr->acl_data->content, &n);
1683    if (!acls) {
1684       Mmsg2(jcr->errmsg, _("aclfromtext error on file \"%s\": ERR=%s\n"),
1685             jcr->last_fname, be.bstrerror());
1686       Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",  
1687             jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1688       return bacl_exit_error;
1689    }
1690
1691    /**
1692     * Restore the ACLs, but don't complain about links which really should
1693     * not have attributes, and the file it is linked to may not yet be restored.
1694     */
1695    if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
1696       switch (errno) {
1697       case ENOENT:
1698          actuallyfree(acls);
1699          return bacl_exit_ok;
1700       default:
1701          Mmsg2(jcr->errmsg, _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
1702                jcr->last_fname, be.bstrerror());
1703          Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
1704                jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1705          actuallyfree(acls);
1706          return bacl_exit_error;
1707       }
1708    }
1709    actuallyfree(acls);
1710    return bacl_exit_ok;
1711 }
1712 #endif /* HAVE_EXTENDED_ACL */
1713
1714 /**
1715  * For this OS setup the build and parse function pointer to the OS specific functions.
1716  */
1717 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_acl_streams;
1718 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = solaris_parse_acl_streams;
1719
1720 #endif /* HAVE_SUN_OS */
1721 #endif /* HAVE_ACL */
1722
1723 /*
1724  * Entry points when compiled with support for ACLs on a supported platform.
1725  */
1726
1727 /**
1728  * Read and send an ACL for the last encountered file.
1729  */
1730 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1731 {
1732    /**
1733     * See if we are changing from one device to an other.
1734     * We save the current device we are scanning and compare
1735     * it with the current st_dev in the last stat performed on
1736     * the file we are currently storing.
1737     */
1738    if (jcr->acl_data->current_dev != ff_pkt->statp.st_dev) {
1739       /**
1740        * Reset the acl save flags.
1741        */
1742       jcr->acl_data->flags = 0;
1743
1744       jcr->acl_data->flags |= BACL_FLAG_SAVE_NATIVE;
1745
1746       /**
1747        * Save that we started scanning a new filesystem.
1748        */
1749       jcr->acl_data->current_dev = ff_pkt->statp.st_dev;
1750    }
1751
1752 #if defined(HAVE_ACL)
1753    /**
1754     * See if the BACL_FLAG_SAVE_NATIVE flag is set which lets us know if we should
1755     * save native ACLs.
1756     */
1757    if (jcr->acl_data->flags & BACL_FLAG_SAVE_NATIVE) {
1758       /**
1759        * Call the appropriate function.
1760        */
1761       if (os_build_acl_streams) {
1762          return (*os_build_acl_streams)(jcr, ff_pkt);
1763       }
1764    } else {
1765       return bacl_exit_ok;
1766    }
1767 #endif
1768    return bacl_exit_error;
1769 }
1770
1771 bacl_exit_code parse_acl_streams(JCR *jcr, int stream)
1772 {
1773    unsigned int cnt;
1774
1775    switch (stream) {
1776 #if defined(HAVE_ACL)
1777    case STREAM_UNIX_ACCESS_ACL:
1778    case STREAM_UNIX_DEFAULT_ACL:
1779       /**
1780        * Handle legacy ACL streams.
1781        */
1782       if (os_parse_acl_streams) {
1783          return (*os_parse_acl_streams)(jcr, stream);
1784       }
1785       break;
1786    default:
1787       if (os_parse_acl_streams) {
1788          /**
1789           * Walk the os_access_acl_streams array with the supported Access ACL streams for this OS.
1790           */
1791          for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1792             if (os_access_acl_streams[cnt] == stream) {
1793                return (*os_parse_acl_streams)(jcr, stream);
1794             }
1795          }
1796          /**
1797           * Walk the os_default_acl_streams array with the supported Default ACL streams for this OS.
1798           */
1799          for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1800             if (os_default_acl_streams[cnt] == stream) {
1801                return (*os_parse_acl_streams)(jcr, stream);
1802             }
1803          }
1804       }
1805       break;
1806 #else
1807    default:
1808       break;
1809 #endif
1810    }
1811    Qmsg2(jcr, M_WARNING, 0,
1812       _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
1813       jcr->last_fname, stream);
1814    return bacl_exit_error;
1815 }
1816 #endif