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