]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/acl.c
- Fix ANSI labels to put EOF1 and EOF2 after each file mark.
[bacula/bacula] / bacula / src / filed / acl.c
1 /*
2  * Functions to handle ACL for bacula.
3  *
4  * We handle two different typers of ACLs: access and default ACLS.
5  * Default ACLs only apply to directories.
6  *
7  * On some systems (eg. linux and FreeBSD) we must obtain the two ACLs
8  * independently, while others (eg. Solaris) provide both in one call.
9  *
10  * As for the streams to use, we have two choices:
11  *
12  * 1. Build a generic framework.
13  *    With two different types of ACLs, supported differently, we
14  *    probably end up encoding and decoding everything ourselves.
15  *
16  * 2. Take the easy way out.
17  *    Just handle each platform individually, assuming that backups
18  *    and restores are done on the same (kind of) client.
19  *
20  * Currently we take the easy way out. We use two kinds of streams, one
21  * for access ACLs and one for default ACLs. If an OS mixes the two, we
22  * send the mix in the access ACL stream.
23  *
24  * Looking at more man pages, supporting a framework seems really hard
25  * if we want to support HP-UX. Deity knows what AIX is up to.
26  *
27  *   Written by Preben 'Peppe' Guldberg, December MMIV
28  *
29  *   Version $Id$
30  */
31
32 #ifndef TEST_PROGRAM
33
34 #include "bacula.h"
35 #include "filed.h"
36 /* So we can free system allocated memory */
37 #undef free
38 #undef malloc
39 #define malloc &* dont use malloc in this routine
40
41 #else
42 /*
43  * Test program setup 
44  *
45  * Compile and set up with eg. with eg.
46  *
47  *    $ cc -DTEST_PROGRAM -DHAVE_SUN_OS -lsec -o acl acl.c
48  *    $ ln -s acl aclcp
49  *
50  * You can then list ACLs with acl and copy them with aclcp.
51  *
52  * For a list of compiler flags, see the list preceding the big #if below.
53  */
54 #include <errno.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <sys/stat.h>
59 #include "acl.h"
60
61 #define BACLLEN 65535
62 #define pm_strcpy(d,s)     (strncpy(d, s, BACLLEN - 1) == NULL ? -1 : (int)strlen(d))
63 #define Dmsg0(n,s)         fprintf(stderr, s)
64 #define Dmsg1(n,s,a1)      fprintf(stderr, s, a1)
65 #define Dmsg2(n,s,a1,a2)   fprintf(stderr, s, a1, a2)
66
67 int aclls(char *fname);
68 int aclcp(char *src, char *dst);
69
70 struct JCRstruct {
71    char *last_fname;
72    char acl_text[BACLLEN];
73 };
74 typedef struct JCRstruct JCR;
75 JCR jcr;
76 #endif
77
78 /*
79  * List of supported OSs.
80  * Not sure if all the HAVE_XYZ_OS are correct for autoconf.
81  * The ones that says man page, are coded according to man pages only.
82  */
83 #if !defined(HAVE_ACL)              /* ACL support is required, of course */ \
84    || !( defined(HAVE_AIX_OS)       /* man page -- may need flags         */ \
85       || defined(HAVE_FREEBSD_OS)   /* tested   -- compile wihtout flags  */ \
86       || defined(HAVE_IRIX_OS)      /* man page -- compile without flags  */ \
87       || defined(HAVE_OSF1_OS)      /* man page -- may need -lpacl        */ \
88       || defined(HAVE_LINUX_OS)     /* tested   -- compile with -lacl     */ \
89       || defined(HAVE_HPUX_OS)      /* man page -- may need flags         */ \
90       || defined(HAVE_SUN_OS)       /* tested   -- compile with -lsec     */ \
91        )
92 /*
93  * ***FIXME***
94  * For now we abandon this test and only test for Linux:
95  * 1. This is backwards compatible.
96  * 2. If we allow any of the other now, we may have to provide conversion
97  *    routines if we ever want to distinguish them. Or just do our best
98  *    with what we have and give all ACL streams a new number/type.
99  */
100 #endif
101 #if !defined(HAVE_ACL) || !defined(HAVE_LINUX_OS)
102
103 /* bacl_get() returns the lenght of the string, or -1 on error. */
104 int bacl_get(JCR *jcr, int acltype)
105 {
106    return -1;
107 }
108
109 int bacl_set(JCR *jcr, int acltype)
110 {
111    return -1;
112 }
113
114 #elif defined(HAVE_AIX_OS)
115
116 #include <sys/access.h>
117
118 int bacl_get(JCR *jcr, int acltype)
119 {
120    char *acl_text;
121    int len;
122
123    if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
124       len = pm_strcpy(jcr->acl_text, acl_text);
125       free(acl_text);
126       return len;
127    }
128    return -1;
129 }
130
131 int bacl_set(JCR *jcr, int acltype)
132 {
133    if (acl_put(jcr->last_fname, jcr->acl_text, 0) != 0) {
134       return -1;
135    }
136    return 0;
137 }
138
139 #elif defined(HAVE_FREEBSD_OS) \
140    || defined(HAVE_IRIX_OS) \
141    || defined(HAVE_OSF1_OS) \
142    || defined(HAVE_LINUX_OS)
143
144 #include <sys/types.h>
145 #include <sys/acl.h>
146
147 /* On IRIX we can get shortened ACLs */
148 #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
149 #define acl_to_text(acl,len)     acl_to_short_text((acl), (len))
150 #endif
151
152 /* In Linux we can get numeric and/or shorted ACLs */
153 #if defined(HAVE_LINUX_OS)
154 #if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
155 #define BACL_ALTERNATE_TEXT            (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
156 #elif defined(BACL_WANT_SHORT_ACLS)
157 #define BACL_ALTERNATE_TEXT            TEXT_ABBREVIATE
158 #elif defined(BACL_WANT_NUMERIC_IDS)
159 #define BACL_ALTERNATE_TEXT            TEXT_NUMERIC_IDS
160 #endif
161 #ifdef BACL_ALTERNATE_TEXT
162 #include <acl/libacl.h>
163 #define acl_to_text(acl,len)     ((len), acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
164 #endif
165 #endif
166
167 int bacl_get(JCR *jcr, int acltype)
168 {
169    acl_t acl;
170    int len, ostype;
171    char *acl_text;
172
173    ostype = (acltype & BACL_TYPE_DEFAULT) ? ACL_TYPE_DEFAULT : ACL_TYPE_ACCESS;
174
175    acl = acl_get_file(jcr->last_fname, ostype);
176    if (acl) {
177       if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
178          len = pm_strcpy(jcr->acl_text, acl_text);
179          acl_free(acl);
180          acl_free(acl_text);
181          return len;
182       }
183       acl_free(acl);
184 #ifndef HAVE_OSF1_OS          /* BACL_ENOTSUP not defined for OSF1 */
185    } else if (errno == BACL_ENOTSUP) {
186       /* Not supported, just pretend there is nothing to see */
187       return pm_strcpy(jcr->acl_text, "");
188 #endif
189    }
190    /***** Do we really want to silently ignore errors from acl_get_file
191      and acl_to_text?  *****/
192    return 0;
193 }
194
195 int bacl_set(JCR *jcr, int acltype)
196 {
197    acl_t acl;
198    int ostype;
199
200    ostype = (acltype & BACL_TYPE_DEFAULT) ? ACL_TYPE_DEFAULT : ACL_TYPE_ACCESS;
201
202    /* If we get empty default ACLs, clear ACLs now */
203    if (ostype == ACL_TYPE_DEFAULT && strlen(jcr->acl_text) == 0) {
204       if (acl_delete_def_file(jcr->last_fname) == 0) {
205          return 0;
206       }
207       return -1;
208    }
209
210    acl = acl_from_text(jcr->acl_text);
211    if (acl == NULL) {
212       return -1;
213    }
214
215    /*
216     * FreeBSD always fails acl_valid() - at least on valid input...
217     * As it does the right thing, given valid input, just ignore acl_valid().
218     */
219 #ifndef HAVE_FREEBSD_OS
220    if (acl_valid(acl) != 0) {
221       acl_free(acl);
222       return -1;
223    }
224 #endif
225
226    if (acl_set_file(jcr->last_fname, ostype, acl) != 0) {
227       acl_free(acl);
228       return -1;
229    }
230    acl_free(acl);
231    return 0;
232 }
233
234 #elif defined(HAVE_HPUX_OS)
235 #include <sys/acl.h>
236 #include <acllib.h>
237
238 int bacl_get(JCR *jcr, int acltype)
239 {
240    int n, len;
241    struct acl_entry acls[NACLENTRIES];
242    char *acl_text;
243
244    if ((n = getacl(jcr->last_fname, 0, acls)) <= 0) {
245       if (errno == BACL_ENOTSUP) {
246          return pm_strcpy(jcr->acl_text, "");
247       }
248       return -1;
249    }
250    if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
251       if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
252          len = pm_strcpy(jcr->acl_text, acl_text);
253          free(acl_text);
254          return len;
255       }
256    }
257    return -1;
258 }
259
260 int bacl_set(JCR *jcr, int acltype)
261 {
262    int n, stat;
263    struct acl_entry acls[NACLENTRIES];
264
265    n = strtoacl(jcr->acl_text, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
266    if (n <= 0) {
267       return -1;
268    }
269    if (strtoacl(jcr->acl_text, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
270       return -1;
271    }
272    if (setacl(jcr->last_fname, n, acls) != 0) {
273       return -1;
274    }
275    return 0;
276 }
277
278 #elif defined(HAVE_SUN_OS)
279 #include <sys/acl.h>
280
281 int bacl_get(JCR *jcr, int acltype)
282 {
283    int n, len;
284    aclent_t *acls;
285    char *acl_text;
286
287    n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
288    if (n < MIN_ACL_ENTRIES) {
289       return -1;
290    } else if (n == MIN_ACL_ENTRIES) {
291       /* The ACLs simply reflect the (already known) standard permissions */
292       return pm_strcpy(jcr->acl_text, "");
293    }
294    if ((acls = (aclent_t *)malloc(n * sizeof(aclent_t))) == NULL) {
295       return -1;
296    }
297    if (acl(jcr->last_fname, GETACL, n, acls) == n) {
298       if ((acl_text = acltotext(acls, n)) != NULL) {
299          len = pm_strcpy(jcr->acl_text, acl_text);
300          free(acl_text);
301          free(acls);
302          return len;
303       }
304    }
305    free(acls);
306    return -1;
307 }
308
309 int bacl_set(JCR *jcr, int acltype)
310 {
311    int n;
312    aclent_t *acls;
313
314    acls = aclfromtext(jcr->acl_text, &n);
315    if (!acls) {
316       return -1;
317    }
318    if (acl(jcr->last_fname, SETACL, n, acls) != 0) {
319       free(acls);
320       return -1;
321    }
322    free(acls);
323    return 0;
324 }
325
326 #endif
327
328
329 #ifdef TEST_PROGRAM
330 int main(int argc, char **argv)
331 {
332    char *prgname;
333    int status = 0;
334
335    if (argc < 1) {
336       Dmsg0(200, "Cannot determine my own name\n");
337       return EXIT_FAILURE;
338    }
339
340    prgname = strrchr(argv[0], '/');
341    if (prgname == NULL || *++prgname == '\0') {
342       prgname = argv[0];
343    }
344    --argc;
345    ++argv;
346
347    /* aclcp "copies" ACLs - set ACLs on destination equal to ACLs on source */
348    if (strcmp(prgname, "aclcp") == 0) {
349       int verbose = 0;
350       if (strcmp(*argv, "-v") == 0) {
351          ++verbose;
352          --argc;
353          ++argv;
354       }
355       if (argc != 2) {
356          Dmsg2(200, "%s: wrong number of arguments\n"
357                "usage:\t%s [-v] source destination\n"
358                "\tCopies ACLs from source to destination.\n"
359                "\tSpecify -v to show ACLs after copy for verification.\n",
360                prgname, prgname);
361          return EXIT_FAILURE;
362       }
363       if (strcmp(argv[0], argv[1]) == 0) {
364          Dmsg2(200, "%s: identical source and destination.\n"
365                "usage:\t%s [-v] source destination\n"
366                "\tCopies ACLs from source to destination.\n"
367                "\tSpecify -v to show ACLs after copy for verification.\n",
368                prgname, prgname);
369          return EXIT_FAILURE;
370       }
371       if (verbose) {
372          aclls(argv[0]);
373       }
374       status = aclcp(argv[0], argv[1]);
375       if (verbose && status == 0) {
376          aclls(argv[1]);
377       }
378       return status;
379    }
380
381    /* Default: just list ACLs */
382    if (argc < 1) {
383       Dmsg2(200, "%s: missing arguments\n"
384             "usage:\t%s file ...\n"
385             "\tLists ACLs of specified files or directories.\n",
386             prgname, prgname);
387       return EXIT_FAILURE;
388    }
389    while (argc--) {
390       if (!aclls(*argv++)) {
391          status = EXIT_FAILURE;
392       }
393    }
394
395    return status;
396 }
397
398 /**** Test program *****/
399 int aclcp(char *src, char *dst)
400 {
401    struct stat st;
402
403    if (lstat(dst, &st) != 0) {
404       Dmsg0(200, "aclcp: destination does not exist\n");
405       return EXIT_FAILURE;
406    }
407    if (S_ISLNK(st.st_mode)) {
408       Dmsg0(200, "aclcp: cannot set ACL on symlinks\n");
409       return EXIT_FAILURE;
410    }
411    if (lstat(src, &st) != 0) {
412       Dmsg0(200, "aclcp: source does not exist\n");
413       return EXIT_FAILURE;
414    }
415    if (S_ISLNK(st.st_mode)) {
416       Dmsg0(200, "aclcp: will not read ACL from symlinks\n");
417       return EXIT_FAILURE;
418    }
419
420    jcr.last_fname = src;
421    if (bacl_get(&jcr, BACL_TYPE_ACCESS) < 0) {
422       Dmsg1(200, "aclcp: could not read ACLs for %s\n", jcr.last_fname);
423       return EXIT_FAILURE;
424    } else {
425       jcr.last_fname = dst;
426       if (bacl_set(&jcr, BACL_TYPE_ACCESS) < 0) {
427          Dmsg1(200, "aclcp: could not set ACLs on %s\n", jcr.last_fname);
428          return EXIT_FAILURE;
429       }
430    }
431
432    if (S_ISDIR(st.st_mode) && (BACL_CAP & BACL_CAP_DEFAULTS_DIR)) {
433       jcr.last_fname = src;
434       if (bacl_get(&jcr, BACL_TYPE_DEFAULT) < 0) {
435          Dmsg1(200, "aclcp: could not read default ACLs for %s\n", jcr.last_fname);
436          return EXIT_FAILURE;
437       } else {
438          jcr.last_fname = dst;
439          if (bacl_set(&jcr, BACL_TYPE_DEFAULT) < 0) {
440             Dmsg1(200, "aclcp: could not set default ACLs on %s\n", jcr.last_fname);
441             return EXIT_FAILURE;
442          }
443       }
444    }
445
446    return 0;
447 }
448
449 /**** Test program *****/
450 int aclls(char *fname)
451 {
452    struct stat st;
453    int len;
454
455    if (lstat(fname, &st) != 0) {
456       Dmsg0(200, "acl: source does not exist\n");
457       return EXIT_FAILURE;
458    }
459    if (S_ISLNK(st.st_mode)) {
460       Dmsg0(200, "acl: will not read ACL from symlinks\n");
461       return EXIT_FAILURE;
462    }
463
464    jcr.last_fname = fname;
465
466    len = bacl_get(&jcr, BACL_TYPE_ACCESS);
467    if (len < 0) {
468       Dmsg1(200, "acl: could not read ACLs for %s\n", jcr.last_fname);
469       return EXIT_FAILURE;
470    } else if (len == 0) {
471       printf("#file: %s [standard permissions - or unsupported]\n\n", jcr.last_fname);
472    } else {
473       printf("#file: %s\n%s\n", jcr.last_fname, jcr.acl_text);
474    }
475
476    if (S_ISDIR(st.st_mode) && (BACL_CAP & BACL_CAP_DEFAULTS_DIR)) {
477       len = bacl_get(&jcr, BACL_TYPE_DEFAULT);
478       if (len < 0) {
479          Dmsg1(200, "acl: could not read default ACLs for %s\n", jcr.last_fname);
480          return EXIT_FAILURE;
481       } else if (len == 0) {
482          printf("#file: %s [default, none - or unsupported]\n\n", jcr.last_fname);
483       } else {
484          printf("#file: %s [default]\n%s\n", jcr.last_fname, jcr.acl_text);
485       }
486    }
487
488    return 0;
489 }
490 #endif