]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/acl.c
Fix typo
[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    case 0:
885       break;
886    default:
887       acltype = BACL_TYPE_NFS4;
888       break;
889    }
890 #endif
891
892    if (acl_enabled == 0) {
893       /**
894        * See if filesystem supports POSIX acls.
895        */
896       acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
897       switch (acl_enabled) {
898       case -1:
899          switch (errno) {
900          case ENOENT:
901             return bacl_exit_ok;
902          default:
903             Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
904                   jcr->last_fname, be.bstrerror());
905             Dmsg2(100, "pathconf error file=%s ERR=%s\n",
906                   jcr->last_fname, be.bstrerror());
907             return bacl_exit_error;
908          }
909       case 0:
910          break;
911       default:
912          acltype = BACL_TYPE_ACCESS;
913          break;
914       }
915    }
916
917    /**
918     * If the filesystem reports it doesn't support ACLs we clear the
919     * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
920     * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
921     * when we change from one filesystem to an other.
922     */
923    if (acl_enabled == 0) {
924       jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
925       pm_strcpy(jcr->acl_data->content, "");
926       jcr->acl_data->content_length = 0;
927       return bacl_exit_ok;
928    }
929
930    /**
931     * Based on the supported ACLs retrieve and store them.
932     */
933    switch (acltype) {
934    case BACL_TYPE_NFS4:
935       /**
936        * Read NFS4 ACLs for files, dirs and links
937        */
938       if (generic_get_acl_from_os(jcr, BACL_TYPE_NFS4) == bacl_exit_fatal)
939          return bacl_exit_fatal;
940
941       if (jcr->acl_data->content_length > 0) {
942          if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_NFS4_ACL) == bacl_exit_fatal)
943             return bacl_exit_fatal;
944       }
945       break;
946    case BACL_TYPE_ACCESS:
947       /**
948        * Read access ACLs for files, dirs and links
949        */
950       if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
951          return bacl_exit_fatal;
952
953       if (jcr->acl_data->content_length > 0) {
954          if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_ACCESS_ACL) == bacl_exit_fatal)
955             return bacl_exit_fatal;
956       }
957
958       /**
959        * Directories can have default ACLs too
960        */
961       if (ff_pkt->type == FT_DIREND) {
962          if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
963             return bacl_exit_fatal;
964          if (jcr->acl_data->content_length > 0) {
965             if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_DEFAULT_ACL) == bacl_exit_fatal)
966                return bacl_exit_fatal;
967          }
968       }
969       break;
970    default:
971       break;
972    }
973
974    return bacl_exit_ok;
975 }
976
977 static bacl_exit_code freebsd_parse_acl_streams(JCR *jcr, int stream)
978 {
979    int acl_enabled = 0;
980    char *acl_type_name;
981    berrno be;
982
983    /**
984     * First make sure the filesystem supports acls.
985     */
986    switch (stream) {
987    case STREAM_UNIX_ACCESS_ACL:
988    case STREAM_ACL_FREEBSD_ACCESS_ACL:
989    case STREAM_UNIX_DEFAULT_ACL:
990    case STREAM_ACL_FREEBSD_DEFAULT_ACL:
991       acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
992       acl_type_name = "POSIX";
993       break;
994    case STREAM_ACL_FREEBSD_NFS4_ACL:
995 #if defined(_PC_ACL_NFS4)
996       acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
997 #endif
998       acl_type_name = "NFS4";
999       break;
1000    default:
1001       acl_type_name = "unknown";
1002       break;
1003    }
1004
1005    switch (acl_enabled) {
1006    case -1:
1007       switch (errno) {
1008       case ENOENT:
1009          return bacl_exit_ok;
1010       default:
1011          Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1012                jcr->last_fname, be.bstrerror());
1013          Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",
1014                jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1015          return bacl_exit_error;
1016       }
1017    case 0:
1018       Mmsg2(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without %s acl support\n"),
1019             jcr->last_fname, acl_type_name);
1020       return bacl_exit_error;
1021    default:
1022       break;
1023    }
1024
1025    /**
1026     * Restore the ACLs.
1027     */
1028    switch (stream) {
1029    case STREAM_UNIX_ACCESS_ACL:
1030    case STREAM_ACL_FREEBSD_ACCESS_ACL:
1031       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
1032    case STREAM_UNIX_DEFAULT_ACL:
1033    case STREAM_ACL_FREEBSD_DEFAULT_ACL:
1034       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
1035    case STREAM_ACL_FREEBSD_NFS4_ACL:
1036       return generic_set_acl_on_os(jcr, BACL_TYPE_NFS4);
1037    default:
1038       break;
1039    }
1040    return bacl_exit_error;
1041 }
1042
1043 /**
1044  * For this OSes setup the build and parse function pointer to the OS specific functions.
1045  */
1046 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = freebsd_build_acl_streams;
1047 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = freebsd_parse_acl_streams;
1048
1049 #elif defined(HAVE_IRIX_OS) || \
1050       defined(HAVE_LINUX_OS)
1051 /**
1052  * Define the supported ACL streams for these OSes
1053  */
1054 #if defined(HAVE_IRIX_OS)
1055 static int os_access_acl_streams[1] = { STREAM_ACL_IRIX_ACCESS_ACL };
1056 static int os_default_acl_streams[1] = { STREAM_ACL_IRIX_DEFAULT_ACL };
1057 #elif defined(HAVE_LINUX_OS)
1058 static int os_access_acl_streams[1] = { STREAM_ACL_LINUX_ACCESS_ACL };
1059 static int os_default_acl_streams[1] = { STREAM_ACL_LINUX_DEFAULT_ACL };
1060 #endif
1061
1062 static bacl_exit_code generic_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1063 {
1064    /**
1065     * Read access ACLs for files, dirs and links
1066     */
1067    if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
1068       return bacl_exit_fatal;
1069
1070    if (jcr->acl_data->content_length > 0) {
1071       if (send_acl_stream(jcr, os_access_acl_streams[0]) == bacl_exit_fatal)
1072          return bacl_exit_fatal;
1073    }
1074
1075    /**
1076     * Directories can have default ACLs too
1077     */
1078    if (ff_pkt->type == FT_DIREND) {
1079       if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
1080          return bacl_exit_fatal;
1081       if (jcr->acl_data->content_length > 0) {
1082          if (send_acl_stream(jcr, os_default_acl_streams[0]) == bacl_exit_fatal)
1083             return bacl_exit_fatal;
1084       }
1085    }
1086    return bacl_exit_ok;
1087 }
1088
1089 static bacl_exit_code generic_parse_acl_streams(JCR *jcr, int stream)
1090 {
1091    unsigned int cnt;
1092
1093    switch (stream) {
1094    case STREAM_UNIX_ACCESS_ACL:
1095       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
1096    case STREAM_UNIX_DEFAULT_ACL:
1097       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
1098    default:
1099       /**
1100        * See what type of acl it is.
1101        */
1102       for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1103          if (os_access_acl_streams[cnt] == stream) {
1104             return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
1105          }
1106       }
1107       for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1108          if (os_default_acl_streams[cnt] == stream) {
1109             return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
1110          }
1111       }
1112       break;
1113    }
1114    return bacl_exit_error;
1115 }
1116
1117 /**
1118  * For this OSes setup the build and parse function pointer to the OS specific functions.
1119  */
1120 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_build_acl_streams;
1121 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = generic_parse_acl_streams;
1122
1123 #elif defined(HAVE_OSF1_OS)
1124
1125 /**
1126  * Define the supported ACL streams for this OS
1127  */
1128 static int os_access_acl_streams[1] = { STREAM_ACL_TRU64_ACCESS_ACL };
1129 static int os_default_acl_streams[2] = { STREAM_ACL_TRU64_DEFAULT_ACL, STREAM_ACL_TRU64_DEFAULT_DIR_ACL };
1130
1131 static bacl_exit_code tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1132 {
1133    /**
1134     * Read access ACLs for files, dirs and links
1135     */
1136    if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
1137       return bacl_exit_error;
1138    if (jcr->acl_data->content_length > 0) {
1139       if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL))
1140          return bacl_exit_error;
1141    }
1142    /**
1143     * Directories can have default ACLs too
1144     */
1145    if (ff_pkt->type == FT_DIREND) {
1146       if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
1147          return bacl_exit_error;
1148       if (jcr->acl_data->content_length > 0) {
1149          if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL))
1150             return bacl_exit_error;
1151       }
1152       /**
1153        * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
1154        * This is an inherited acl for all subdirs.
1155        * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
1156        * Section 21.5 Default ACLs 
1157        */
1158       if ((jcr->acl_data->content_length = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR)) < 0)
1159          return bacl_exit_error;
1160       if (jcr->acl_data->content_length > 0) {
1161          if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL))
1162             return bacl_exit_error;
1163       }
1164    }
1165    return bacl_exit_ok;
1166 }
1167
1168 static bacl_exit_code tru64_parse_acl_streams(JCR *jcr, int stream)
1169 {
1170    switch (stream) {
1171    case STREAM_UNIX_ACCESS_ACL:
1172    case STREAM_ACL_TRU64_ACCESS_ACL:
1173       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
1174    case STREAM_UNIX_DEFAULT_ACL:
1175    case STREAM_ACL_TRU64_DEFAULT_ACL:
1176       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
1177    case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
1178       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR);
1179 }
1180
1181 /**
1182  * For this OS setup the build and parse function pointer to the OS specific functions.
1183  */
1184 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = tru64_build_acl_streams;
1185 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = tru64_parse_acl_streams;
1186
1187 #endif
1188
1189 #elif defined(HAVE_HPUX_OS)
1190 #ifdef HAVE_SYS_ACL_H
1191 #include <sys/acl.h>
1192 #else
1193 #error "configure failed to detect availability of sys/acl.h"
1194 #endif
1195
1196 #include <acllib.h>
1197
1198 /**
1199  * Define the supported ACL streams for this OS
1200  */
1201 static int os_access_acl_streams[1] = { STREAM_ACL_HPUX_ACL_ENTRY };
1202 static int os_default_acl_streams[1] = { -1 };
1203
1204 /**
1205  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1206  * There is no need to store those acls as we already store the stat bits too.
1207  */
1208 static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
1209 {
1210    int n;
1211    struct acl_entry ace
1212
1213    for (n = 0; n < count; n++) {
1214       ace = entries[n];
1215       /**
1216        * See if this acl just is the stat mode in acl form.
1217        */
1218       if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
1219             (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
1220             (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
1221          return false;
1222    }
1223    return true;
1224 }
1225
1226 /**
1227  * OS specific functions for handling different types of acl streams.
1228  */
1229 static bacl_exit_code hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1230 {
1231    int n;
1232    struct acl_entry acls[NACLENTRIES];
1233    char *acl_text;
1234    berrno be;
1235
1236    if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
1237       switch (errno) {
1238 #if defined(BACL_ENOTSUP)
1239       case BACL_ENOTSUP:
1240          /**
1241           * Not supported, just pretend there is nothing to see
1242           *
1243           * If the filesystem reports it doesn't support ACLs we clear the
1244           * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1245           * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1246           * when we change from one filesystem to an other.
1247           */
1248          jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1249          pm_strcpy(jcr->acl_data->content, "");
1250          jcr->acl_data->content_length = 0;
1251          return bacl_exit_ok;
1252 #endif
1253       case ENOENT:
1254          pm_strcpy(jcr->acl_data->content, "");
1255          jcr->acl_data->content_length = 0;
1256          return bacl_exit_ok;
1257       default:
1258          Mmsg2(jcr->errmsg, _("getacl error on file \"%s\": ERR=%s\n"),
1259                jcr->last_fname, be.bstrerror());
1260          Dmsg2(100, "getacl error file=%s ERR=%s\n",  
1261                jcr->last_fname, be.bstrerror());
1262
1263          pm_strcpy(jcr->acl_data->content, "");
1264          jcr->acl_data->content_length = 0;
1265          return bacl_exit_error;
1266       }
1267    }
1268    if (n == 0) {
1269       pm_strcpy(jcr->acl_data->content, "");
1270       jcr->acl_data->content_length = 0;
1271       return bacl_exit_ok;
1272    }
1273    if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
1274       if (acl_is_trivial(n, acls, ff_pkt->statp)) {
1275          /**
1276           * The ACLs simply reflect the (already known) standard permissions
1277           * So we don't send an ACL stream to the SD.
1278           */
1279          pm_strcpy(jcr->acl_data->content, "");
1280          jcr->acl_data->content_length = 0;
1281          return bacl_exit_ok;
1282       }
1283       if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
1284          jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1285          actuallyfree(acl_text);
1286
1287          return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
1288       }
1289       Mmsg2(jcr->errmsg, _("acltostr error on file \"%s\": ERR=%s\n"),
1290             jcr->last_fname, be.bstrerror());
1291       Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",  
1292             jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1293       return bacl_exit_error;
1294    }
1295    return bacl_exit_error;
1296 }
1297
1298 static bacl_exit_code hpux_parse_acl_streams(JCR *jcr, int stream)
1299 {
1300    int n, stat;
1301    struct acl_entry acls[NACLENTRIES];
1302    berrno be;
1303
1304    n = strtoacl(jcr->acl_data->content, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
1305    if (n <= 0) {
1306       Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
1307             jcr->last_fname, be.bstrerror());
1308       Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",  
1309             jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1310       return bacl_exit_error;
1311    }
1312    if (strtoacl(jcr->acl_data->content, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
1313       Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
1314             jcr->last_fname, be.bstrerror());
1315       Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",  
1316             jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1317
1318       return bacl_exit_error;
1319    }
1320    /**
1321     * Restore the ACLs, but don't complain about links which really should
1322     * not have attributes, and the file it is linked to may not yet be restored.
1323     * This is only true for the old acl streams as in the new implementation we
1324     * don't save acls of symlinks (which cannot have acls anyhow)
1325     */
1326    if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
1327       switch (errno) {
1328       case ENOENT:
1329          return bacl_exit_ok;
1330       default:
1331          Mmsg2(jcr->errmsg, _("setacl error on file \"%s\": ERR=%s\n"),
1332                jcr->last_fname, be.bstrerror());
1333          Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
1334                jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1335          return bacl_exit_error;
1336       }
1337    }
1338    return bacl_exit_ok;
1339 }
1340
1341 /**
1342  * For this OS setup the build and parse function pointer to the OS specific functions.
1343  */
1344 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = hpux_build_acl_streams;
1345 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = hpux_parse_acl_streams;
1346
1347 #elif defined(HAVE_SUN_OS)
1348 #ifdef HAVE_SYS_ACL_H
1349 #include <sys/acl.h>
1350 #else
1351 #error "configure failed to detect availability of sys/acl.h"
1352 #endif
1353
1354 #if defined(HAVE_EXTENDED_ACL)
1355 /**
1356  * We define some internals of the Solaris acl libs here as those
1357  * are not exposed yet. Probably because they want us to see the
1358  * acls as opague data. But as we need to support different platforms
1359  * and versions of Solaris we need to expose some data to be able
1360  * to determine the type of acl used to stuff it into the correct
1361  * data stream. I know this is far from portable, but maybe the
1362  * proper interface is exposed later on and we can get ride of
1363  * this kludge. Newer versions of Solaris include sys/acl_impl.h
1364  * which has implementation details of acls, if thats included we
1365  * don't have to define it ourself.
1366  */
1367 #if !defined(_SYS_ACL_IMPL_H)
1368 typedef enum acl_type {
1369    ACLENT_T = 0,
1370    ACE_T = 1
1371 } acl_type_t;
1372 #endif
1373
1374 /**
1375  * Two external references to functions in the libsec library function not in current include files.
1376  */
1377 extern "C" {
1378 int acl_type(acl_t *);
1379 char *acl_strerror(int);
1380 }
1381
1382 /**
1383  * Define the supported ACL streams for this OS
1384  */
1385 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT, STREAM_ACL_SOLARIS_ACE };
1386 static int os_default_acl_streams[1] = { -1 };
1387
1388 /**
1389  * As the new libsec interface with acl_totext and acl_fromtext also handles
1390  * the old format from acltotext we can use the new functions even
1391  * for acls retrieved and stored in the database with older fd versions. If the
1392  * new interface is not defined (Solaris 9 and older we fall back to the old code)
1393  */
1394 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1395 {
1396    int acl_enabled, flags;
1397    acl_t *aclp;
1398    char *acl_text;
1399    bacl_exit_code stream_status = bacl_exit_error;
1400    berrno be;
1401
1402    /**
1403     * See if filesystem supports acls.
1404     */
1405    acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1406    switch (acl_enabled) {
1407    case 0:
1408       /**
1409        * If the filesystem reports it doesn't support ACLs we clear the
1410        * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
1411        * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
1412        * when we change from one filesystem to an other.
1413        */
1414       jcr->acl_data->flags &= ~BACL_FLAG_SAVE_NATIVE;
1415       pm_strcpy(jcr->acl_data->content, "");
1416       jcr->acl_data->content_length = 0;
1417       return bacl_exit_ok;
1418    case -1:
1419       switch (errno) {
1420       case ENOENT:
1421          return bacl_exit_ok;
1422       default:
1423          Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1424                jcr->last_fname, be.bstrerror());
1425          Dmsg2(100, "pathconf error file=%s ERR=%s\n",  
1426                jcr->last_fname, be.bstrerror());
1427          return bacl_exit_error;
1428       }
1429    default:
1430       break;
1431    }
1432
1433    /**
1434     * Get ACL info: don't bother allocating space if there is only a trivial ACL.
1435     */
1436    if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
1437       switch (errno) {
1438       case ENOENT:
1439          return bacl_exit_ok;
1440       default:
1441          Mmsg2(jcr->errmsg, _("acl_get error on file \"%s\": ERR=%s\n"),
1442                jcr->last_fname, acl_strerror(errno));
1443          Dmsg2(100, "acl_get error file=%s ERR=%s\n",  
1444                jcr->last_fname, acl_strerror(errno));
1445          return bacl_exit_error;
1446       }
1447    }
1448
1449    if (!aclp) {
1450       /**
1451        * The ACLs simply reflect the (already known) standard permissions
1452        * So we don't send an ACL stream to the SD.
1453        */
1454       pm_strcpy(jcr->acl_data->content, "");
1455       jcr->acl_data->content_length = 0;
1456       return bacl_exit_ok;
1457    }
1458
1459 #if defined(ACL_SID_FMT)
1460    /**
1461     * New format flag added in newer Solaris versions.
1462     */
1463    flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
1464 #else
1465    flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
1466 #endif /* ACL_SID_FMT */
1467
1468    if ((acl_text = acl_totext(aclp, flags)) != NULL) {
1469       jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1470       actuallyfree(acl_text);
1471
1472       switch (acl_type(aclp)) {
1473       case ACLENT_T:
1474          stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1475          break;
1476       case ACE_T:
1477          stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE);
1478          break;
1479       default:
1480          break;
1481       }
1482
1483       acl_free(aclp);
1484    }
1485    return stream_status;
1486 }
1487
1488 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
1489 {
1490    acl_t *aclp;
1491    int acl_enabled, error;
1492    berrno be;
1493
1494    switch (stream) {
1495    case STREAM_UNIX_ACCESS_ACL:
1496    case STREAM_ACL_SOLARIS_ACLENT:
1497    case STREAM_ACL_SOLARIS_ACE:
1498       /**
1499        * First make sure the filesystem supports acls.
1500        */
1501       acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
1502       switch (acl_enabled) {
1503       case 0:
1504          Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
1505                jcr->last_fname);
1506          return bacl_exit_error;
1507       case -1:
1508          switch (errno) {
1509          case ENOENT:
1510             return bacl_exit_ok;
1511          default:
1512             Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
1513                   jcr->last_fname, be.bstrerror());
1514             Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",  
1515                   jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1516             return bacl_exit_error;
1517          }
1518       default:
1519          /**
1520           * On a filesystem with ACL support make sure this particular ACL type can be restored.
1521           */
1522          switch (stream) {
1523          case STREAM_ACL_SOLARIS_ACLENT:
1524             /**
1525              * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
1526              */
1527             if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
1528                Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without aclent acl support\n"),
1529                      jcr->last_fname);
1530                return bacl_exit_error;
1531             }
1532             break;
1533          case STREAM_ACL_SOLARIS_ACE:
1534             /**
1535              * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
1536              */
1537             if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
1538                Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without ace acl support\n"),
1539                      jcr->last_fname);
1540                return bacl_exit_error;
1541             }
1542             break;
1543          default:
1544             /**
1545              * Stream id which doesn't describe the type of acl which is encoded.
1546              */
1547             break;
1548          }
1549          break;
1550       }
1551
1552       if ((error = acl_fromtext(jcr->acl_data->content, &aclp)) != 0) {
1553          Mmsg2(jcr->errmsg, _("acl_fromtext error on file \"%s\": ERR=%s\n"),
1554                jcr->last_fname, acl_strerror(error));
1555          Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",  
1556                jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1557          return bacl_exit_error;
1558       }
1559
1560       /**
1561        * Validate that the conversion gave us the correct acl type.
1562        */
1563       switch (stream) {
1564       case STREAM_ACL_SOLARIS_ACLENT:
1565          if (acl_type(aclp) != ACLENT_T) {
1566             Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1567                   jcr->last_fname);
1568             return bacl_exit_error;
1569          }
1570          break;
1571       case STREAM_ACL_SOLARIS_ACE:
1572          if (acl_type(aclp) != ACE_T) {
1573             Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
1574                   jcr->last_fname);
1575             return bacl_exit_error;
1576          }
1577          break;
1578       default:
1579          /**
1580           * Stream id which doesn't describe the type of acl which is encoded.
1581           */
1582          break;
1583       }
1584
1585       /**
1586        * Restore the ACLs, but don't complain about links which really should
1587        * not have attributes, and the file it is linked to may not yet be restored.
1588        * This is only true for the old acl streams as in the new implementation we
1589        * don't save acls of symlinks (which cannot have acls anyhow)
1590        */
1591       if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
1592          switch (errno) {
1593          case ENOENT:
1594             acl_free(aclp);
1595             return bacl_exit_ok;
1596          default:
1597             Mmsg2(jcr->errmsg, _("acl_set error on file \"%s\": ERR=%s\n"),
1598                   jcr->last_fname, acl_strerror(error));
1599             Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",  
1600                   jcr->acl_data->content, jcr->last_fname, acl_strerror(error));
1601             acl_free(aclp);
1602             return bacl_exit_error;
1603          }
1604       }
1605
1606       acl_free(aclp);
1607       return bacl_exit_ok;
1608    default:
1609       return bacl_exit_error;
1610    } /* end switch (stream) */
1611 }
1612
1613 #else /* HAVE_EXTENDED_ACL */
1614
1615 /**
1616  * Define the supported ACL streams for this OS
1617  */
1618 static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT };
1619 static int os_default_acl_streams[1] = { -1 };
1620
1621 /**
1622  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1623  * There is no need to store those acls as we already store the stat bits too.
1624  */
1625 static bool acl_is_trivial(int count, aclent_t *entries)
1626 {
1627    int n;
1628    aclent_t *ace;
1629
1630    for (n = 0; n < count; n++) {
1631       ace = &entries[n];
1632
1633       if (!(ace->a_type == USER_OBJ ||
1634             ace->a_type == GROUP_OBJ ||
1635             ace->a_type == OTHER_OBJ ||
1636             ace->a_type == CLASS_OBJ))
1637         return false;
1638    }
1639    return true;
1640 }
1641
1642 /**
1643  * OS specific functions for handling different types of acl streams.
1644  */
1645 static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1646 {
1647    int n;
1648    aclent_t *acls;
1649    char *acl_text;
1650    berrno be;
1651
1652    n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
1653    if (n < MIN_ACL_ENTRIES)
1654       return bacl_exit_error;
1655
1656    acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1657    if (acl(jcr->last_fname, GETACL, n, acls) == n) {
1658       if (acl_is_trivial(n, acls)) {
1659          /**
1660           * The ACLs simply reflect the (already known) standard permissions
1661           * So we don't send an ACL stream to the SD.
1662           */
1663          free(acls);
1664          pm_strcpy(jcr->acl_data->content, "");
1665          jcr->acl_data->content_length = 0;
1666          return bacl_exit_ok;
1667       }
1668
1669       if ((acl_text = acltotext(acls, n)) != NULL) {
1670          jcr->acl_data->content_length = pm_strcpy(jcr->acl_data->content, acl_text);
1671          actuallyfree(acl_text);
1672          free(acls);
1673          return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
1674       }
1675
1676       Mmsg2(jcr->errmsg, _("acltotext error on file \"%s\": ERR=%s\n"),
1677             jcr->last_fname, be.bstrerror());
1678       Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",  
1679             jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1680    }
1681
1682    free(acls);
1683    return bacl_exit_error;
1684 }
1685
1686 static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
1687 {
1688    int n;
1689    aclent_t *acls;
1690    berrno be;
1691
1692    acls = aclfromtext(jcr->acl_data->content, &n);
1693    if (!acls) {
1694       Mmsg2(jcr->errmsg, _("aclfromtext error on file \"%s\": ERR=%s\n"),
1695             jcr->last_fname, be.bstrerror());
1696       Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",  
1697             jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1698       return bacl_exit_error;
1699    }
1700
1701    /**
1702     * Restore the ACLs, but don't complain about links which really should
1703     * not have attributes, and the file it is linked to may not yet be restored.
1704     */
1705    if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
1706       switch (errno) {
1707       case ENOENT:
1708          actuallyfree(acls);
1709          return bacl_exit_ok;
1710       default:
1711          Mmsg2(jcr->errmsg, _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
1712                jcr->last_fname, be.bstrerror());
1713          Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
1714                jcr->acl_data->content, jcr->last_fname, be.bstrerror());
1715          actuallyfree(acls);
1716          return bacl_exit_error;
1717       }
1718    }
1719    actuallyfree(acls);
1720    return bacl_exit_ok;
1721 }
1722 #endif /* HAVE_EXTENDED_ACL */
1723
1724 /**
1725  * For this OS setup the build and parse function pointer to the OS specific functions.
1726  */
1727 static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_acl_streams;
1728 static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = solaris_parse_acl_streams;
1729
1730 #endif /* HAVE_SUN_OS */
1731 #endif /* HAVE_ACL */
1732
1733 /*
1734  * Entry points when compiled with support for ACLs on a supported platform.
1735  */
1736
1737 /**
1738  * Read and send an ACL for the last encountered file.
1739  */
1740 bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
1741 {
1742    /**
1743     * See if we are changing from one device to an other.
1744     * We save the current device we are scanning and compare
1745     * it with the current st_dev in the last stat performed on
1746     * the file we are currently storing.
1747     */
1748    if (jcr->acl_data->current_dev != ff_pkt->statp.st_dev) {
1749       /**
1750        * Reset the acl save flags.
1751        */
1752       jcr->acl_data->flags = 0;
1753
1754       jcr->acl_data->flags |= BACL_FLAG_SAVE_NATIVE;
1755
1756       /**
1757        * Save that we started scanning a new filesystem.
1758        */
1759       jcr->acl_data->current_dev = ff_pkt->statp.st_dev;
1760    }
1761
1762 #if defined(HAVE_ACL)
1763    /**
1764     * See if the BACL_FLAG_SAVE_NATIVE flag is set which lets us know if we should
1765     * save native ACLs.
1766     */
1767    if (jcr->acl_data->flags & BACL_FLAG_SAVE_NATIVE) {
1768       /**
1769        * Call the appropriate function.
1770        */
1771       if (os_build_acl_streams) {
1772          return (*os_build_acl_streams)(jcr, ff_pkt);
1773       }
1774    } else {
1775       return bacl_exit_ok;
1776    }
1777 #endif
1778    return bacl_exit_error;
1779 }
1780
1781 bacl_exit_code parse_acl_streams(JCR *jcr, int stream)
1782 {
1783    unsigned int cnt;
1784
1785    switch (stream) {
1786 #if defined(HAVE_ACL)
1787    case STREAM_UNIX_ACCESS_ACL:
1788    case STREAM_UNIX_DEFAULT_ACL:
1789       /**
1790        * Handle legacy ACL streams.
1791        */
1792       if (os_parse_acl_streams) {
1793          return (*os_parse_acl_streams)(jcr, stream);
1794       }
1795       break;
1796    default:
1797       if (os_parse_acl_streams) {
1798          /**
1799           * Walk the os_access_acl_streams array with the supported Access ACL streams for this OS.
1800           */
1801          for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
1802             if (os_access_acl_streams[cnt] == stream) {
1803                return (*os_parse_acl_streams)(jcr, stream);
1804             }
1805          }
1806          /**
1807           * Walk the os_default_acl_streams array with the supported Default ACL streams for this OS.
1808           */
1809          for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
1810             if (os_default_acl_streams[cnt] == stream) {
1811                return (*os_parse_acl_streams)(jcr, stream);
1812             }
1813          }
1814       }
1815       break;
1816 #else
1817    default:
1818       break;
1819 #endif
1820    }
1821    Qmsg2(jcr, M_WARNING, 0,
1822       _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
1823       jcr->last_fname, stream);
1824    return bacl_exit_error;
1825 }
1826 #endif