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