]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/xacl_linux.c
XACL - refactoring an ACL and XATTR codes.
[bacula/bacula] / bacula / src / filed / xacl_linux.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2016 Kern Sibbald
5
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    This notice must be preserved when any source code is
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18  */
19 /**
20  * Major refactoring of ACL and XATTR code written by:
21  *
22  *  RadosÅ‚aw Korzeniewski, MMXVI
23  *  radoslaw@korzeniewski.net, radekk@inteos.pl
24  *  Inteos Sp. z o.o. http://www.inteos.pl/
25  *
26  */
27
28 #include "bacula.h"
29 #include "filed.h"
30 #include "xacl_linux.h"
31
32 #if defined(HAVE_LINUX_OS)
33 /*
34  * Define the supported ACL streams for this OS
35  */
36 static const int os_acl_streams[] = {
37    STREAM_XACL_LINUX_ACCESS,
38    0
39 };
40
41 static const int os_default_acl_streams[] = {
42    STREAM_XACL_LINUX_DEFAULT,
43    0
44 };
45
46 /*
47  * Define the supported XATTR streams for this OS
48  */
49 static const int os_xattr_streams[] = {
50    STREAM_XACL_LINUX_XATTR,
51    0
52 };
53
54 static const char *os_xattr_acl_skiplist[] = {
55    "system.posix_acl_access",
56    "system.posix_acl_default",
57    NULL
58 };
59
60 static const char *os_xattr_skiplist[] = {
61    NULL
62 };
63
64 /*
65  * OS Specyfic constructor
66  */
67 XACL_Linux::XACL_Linux(){
68    set_acl_streams(os_acl_streams, os_default_acl_streams);
69    set_xattr_streams(os_xattr_streams);
70    set_xattr_skiplists(os_xattr_skiplist, os_xattr_acl_skiplist);
71 };
72
73 /*
74  * Translates Bacula internal acl representation into
75  * acl type
76  *
77  * in:
78  *    xacltype - internal Bacula acl type (XACL_type)
79  * out:
80  *    acl_type_t - os dependent acl type
81  *    when failed - ACL_TYPE_NONE is returned
82  */
83 acl_type_t XACL_Linux::get_acltype(XACL_type xacltype){
84
85    acl_type_t acltype;
86
87    switch (xacltype){
88       case XACL_TYPE_ACCESS:
89          acltype = ACL_TYPE_ACCESS;
90          break;
91       case XACL_TYPE_DEFAULT:
92          acltype = ACL_TYPE_DEFAULT;
93          break;
94       default:
95          /*
96           * sanity check for acl's not supported by OS
97           */
98          acltype = (acl_type_t)ACL_TYPE_NONE;
99          break;
100    }
101    return acltype;
102 };
103
104 /*
105  * Counts a number of acl entries
106  *
107  * in:
108  *    acl - acl object
109  * out:
110  *    int - number of entries in acl object
111  *    when no acl entry available or any error then return zero '0'
112  */
113 int XACL_Linux::acl_nrentries(acl_t acl){
114
115    int nr = 0;
116    acl_entry_t aclentry;
117    int rc;
118
119    rc = acl_get_entry(acl, ACL_FIRST_ENTRY, &aclentry);
120    while (rc == 1){
121       nr++;
122       rc = acl_get_entry(acl, ACL_NEXT_ENTRY, &aclentry);
123    }
124
125    return nr;
126 };
127
128 /*
129  * Checks if acl is simple.
130  *
131  * acl is simple if it has only the following entries:
132  * "user::",
133  * "group::",
134  * "other::"
135  *
136  * in:
137  *    acl - acl object
138  * out:
139  *    true - when acl object is simple
140  *    false - when acl object is not simple
141  */
142 bool XACL_Linux::acl_issimple(acl_t acl){
143
144    acl_entry_t aclentry;
145    acl_tag_t acltag;
146    int rc;
147
148    rc = acl_get_entry(acl, ACL_FIRST_ENTRY, &aclentry);
149    while (rc == 1){
150       if (acl_get_tag_type(aclentry, &acltag) < 0){
151          return true;
152       }
153       /*
154        * Check for ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER to find out.
155        */
156       if (acltag != ACL_USER_OBJ &&
157           acltag != ACL_GROUP_OBJ &&
158           acltag != ACL_OTHER){
159          return false;
160       }
161       rc = acl_get_entry(acl, ACL_NEXT_ENTRY, &aclentry);
162    }
163    return true;
164 };
165
166 /*
167  * Perform OS specyfic ACL backup
168  *
169  * in/out - check API at xacl.h
170  */
171 bRC_XACL XACL_Linux::os_backup_acl (JCR *jcr, FF_PKT *ff_pkt){
172    return generic_backup_acl(jcr, ff_pkt);
173 };
174
175 /*
176  * Perform OS specyfic ACL restore
177  *
178  * in/out - check API at xacl.h
179  */
180 bRC_XACL XACL_Linux::os_restore_acl (JCR *jcr, int stream, char *content, uint32_t length){
181    return generic_restore_acl(jcr, stream);
182 };
183
184 /*
185  * Perform OS specyfic extended attribute backup
186  *
187  * in/out - check API at xacl.h
188  */
189 bRC_XACL XACL_Linux::os_backup_xattr (JCR *jcr, FF_PKT *ff_pkt){
190    return generic_backup_xattr(jcr, ff_pkt);
191 };
192
193 /*
194  * Perform OS specyfic XATTR restore. Runtime is called only when stream is supported by OS.
195  *
196  * in/out - check API at xacl.h
197  */
198 bRC_XACL XACL_Linux::os_restore_xattr (JCR *jcr, int stream, char *content, uint32_t length){
199    return generic_restore_xattr(jcr, stream);
200 };
201
202 /*
203  * Low level OS specyfic runtime to get ACL data from file. The ACL data is set in internal content buffer.
204  *
205  * in/out - check API at xacl.h
206  */
207 bRC_XACL XACL_Linux::os_get_acl(JCR *jcr, XACL_type xacltype){
208
209    acl_t acl;
210    acl_type_t acltype;
211    char *acltext;
212    bRC_XACL rc = bRC_XACL_ok;
213
214    /* check input data */
215    if (jcr == NULL){
216       return bRC_XACL_inval;
217    }
218
219    acltype = get_acltype(xacltype);
220    acl = acl_get_file(jcr->last_fname, acltype);
221
222    if (acl){
223       Dmsg1(400, "OS_ACL read from file: %s\n",jcr->last_fname);
224       if (acl_nrentries(acl) == 0){
225          goto bail_out;
226       }
227
228       /* check for fimple ACL which correspond to standard permissions only */
229       if (xacltype == XACL_TYPE_ACCESS && acl_issimple(acl)){
230          goto bail_out;
231       }
232
233       if ((acltext = acl_to_text(acl, NULL)) != NULL){
234          set_content(acltext);
235          acl_free(acl);
236          acl_free(acltext);
237          return bRC_XACL_ok;
238       }
239
240       berrno be;
241
242       Mmsg2(jcr->errmsg, _("acl_to_text error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
243       Dmsg2(100, "acl_to_text error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
244
245       rc = bRC_XACL_error;
246    } else {
247       berrno be;
248
249       switch (errno){
250       case EOPNOTSUPP:
251          /* fs does not support acl, skip it */
252          Dmsg0(400, "Wow, ACL is not supported on this filesystem\n");
253          clear_flag(XACL_FLAG_NATIVE);
254          break;
255       case ENOENT:
256          break;
257       default:
258          /* Some real error */
259          Mmsg2(jcr->errmsg, _("acl_get_file error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
260          Dmsg2(100, "acl_get_file error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
261          rc = bRC_XACL_error;
262          break;
263       }
264    }
265
266 bail_out:
267    if (acl){
268       acl_free(acl);
269    }
270    /*
271     * it is a bit of hardcore to clear a poolmemory with a NULL pointer,
272     * but it is working, hehe :)
273     * you may ask why it is working? it is simple, a pm_strcpy function is handling
274     * a null pointer with a substitiution of empty string.
275     */
276    set_content(NULL);
277    return rc;
278 };
279
280 /*
281  * Low level OS specyfic runtime to set ACL data on file
282  *
283  * in/out - check API at xacl.h
284  */
285 bRC_XACL XACL_Linux::os_set_acl(JCR *jcr, XACL_type xacltype, char *content, uint32_t length){
286
287    acl_t acl;
288    acl_type_t acltype;
289
290    /* check input data */
291    if (jcr == NULL || content == NULL){
292       return bRC_XACL_inval;
293    }
294
295    acl = acl_from_text(content);
296    if (acl == NULL){
297       berrno be;
298
299       Mmsg2(jcr->errmsg, _("acl_from_text error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
300       Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n", content, jcr->last_fname, be.bstrerror());
301       return bRC_XACL_error;
302    }
303
304    if (acl_valid(acl) != 0){
305       berrno be;
306
307       Mmsg2(jcr->errmsg, _("acl_valid error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
308       Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n", content, jcr->last_fname, be.bstrerror());
309       acl_free(acl);
310       return bRC_XACL_error;
311    }
312
313    /* handle different acl types for Linux */
314    acltype = get_acltype(xacltype);
315    if (acltype == ACL_TYPE_DEFAULT && length == 0){
316       /* delete ACl from file when no acl data available for default acl's */
317       if (acl_delete_def_file(jcr->last_fname) == 0){
318          return bRC_XACL_ok;
319       }
320
321       berrno be;
322       switch (errno){
323          case ENOENT:
324             return bRC_XACL_ok;
325          case ENOTSUP:
326             /*
327              * If the filesystem reports it doesn't support acl's we clear the
328              * XACL_FLAG_NATIVE flag so we skip ACL restores on all other files
329              * on the same filesystem. The XACL_FLAG_NATIVE flag gets set again
330              * when we change from one filesystem to an other.
331              */
332             clear_flag(XACL_FLAG_NATIVE);
333             Mmsg(jcr->errmsg, _("acl_delete_def_file error on file \"%s\": filesystem doesn't support ACLs\n"), jcr->last_fname);
334             return bRC_XACL_error;
335          default:
336             Mmsg2(jcr->errmsg, _("acl_delete_def_file error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
337             return bRC_XACL_error;
338       }
339    }
340
341    /*
342     * Restore the ACLs, but don't complain about links which really should
343     * not have attributes, and the file it is linked to may not yet be restored.
344     * This is only true for the old acl streams as in the new implementation we
345     * don't save acls of symlinks (which cannot have acls anyhow)
346     */
347    if (acl_set_file(jcr->last_fname, acltype, acl) != 0 && jcr->last_type != FT_LNK){
348       berrno be;
349       switch (errno){
350       case ENOENT:
351          acl_free(acl);
352          return bRC_XACL_ok;
353       case ENOTSUP:
354          /*
355           * If the filesystem reports it doesn't support ACLs we clear the
356           * XACL_FLAG_NATIVE flag so we skip ACL restores on all other files
357           * on the same filesystem. The XACL_FLAG_NATIVE flag gets set again
358           * when we change from one filesystem to an other.
359           */
360          clear_flag(XACL_FLAG_NATIVE);
361          Mmsg(jcr->errmsg, _("acl_set_file error on file \"%s\": filesystem doesn't support ACLs\n"), jcr->last_fname);
362          Dmsg2(100, "acl_set_file error acl=%s file=%s filesystem doesn't support ACLs\n", content, jcr->last_fname);
363          acl_free(acl);
364          return bRC_XACL_error;
365       default:
366          Mmsg2(jcr->errmsg, _("acl_set_file error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
367          Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n", content, jcr->last_fname, be.bstrerror());
368          acl_free(acl);
369          return bRC_XACL_error;
370       }
371    }
372    acl_free(acl);
373    return bRC_XACL_ok;
374 };
375
376 /*
377  * Return a list of xattr names in newly allocated pool memory and a length of the allocated buffer.
378  * It allocates a memory with poolmem subroutines every time a function is called, so it must be freed
379  * when not needed.
380  *
381  * in/out - check API at xacl.h
382  */
383 bRC_XACL XACL_Linux::os_get_xattr_names (JCR *jcr, POOLMEM ** pxlist, uint32_t * xlen){
384
385    int len;
386    POOLMEM * list;
387
388    /* check input data */
389    if (jcr == NULL || xlen == NULL || pxlist == NULL){
390       return bRC_XACL_inval;
391    }
392
393    /* get the length of the extended attributes */
394    len = llistxattr(jcr->last_fname, NULL, 0);
395    switch (len){
396       case -1: {
397          berrno be;
398
399          switch (errno){
400             case ENOENT:
401                /* no file available, skip it */
402                return bRC_XACL_skip;
403             case EOPNOTSUPP:
404                /* no xattr supported on filesystem, clear a flag and skip it */
405                clear_flag(XACL_FLAG_NATIVE);
406                set_content(NULL);
407                return bRC_XACL_skip;
408             default:
409                Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
410                Dmsg2(100, "llistxattr error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
411                return bRC_XACL_error;
412          }
413          break;
414       }
415       case 0:
416          /* xattr available but empty, skip it */
417          return bRC_XACL_skip;
418       default:
419          break;
420    }
421
422    /*
423     * allocate memory for the extented attribute list
424     * default size is a 4k for PM_BSOCK, which should be sufficient on almost all
425     * Linux system where xattrs a limited in size to single filesystem block ~4kB
426     * so we need to check required size
427     */
428    list = get_pool_memory(PM_BSOCK);
429    list = check_pool_memory_size(list, len + 1);
430    memset(list, 0, len + 1);
431
432    /* get the list of extended attributes names for a file */
433    len = llistxattr(jcr->last_fname, list, len);
434    switch (len){
435    case -1: {
436       berrno be;
437
438       switch (errno){
439       case ENOENT:
440          /* no file available, skip it, first release allocated memory */
441          free_pool_memory(list);
442          return bRC_XACL_skip;
443       default:
444          Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
445          Dmsg2(100, "llistxattr error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
446          free_pool_memory(list);
447          return bRC_XACL_error;
448       }
449       break;
450    }
451    default:
452       break;
453    }
454    /* ensure a list is nul terminated */
455    list[len] = '\0';
456    /* setup return data */
457    *pxlist = list;
458    *xlen = len;
459    return bRC_XACL_ok;
460 };
461
462 /*
463  * Return a value of the requested attribute name and a length of the allocated buffer.
464  * It allocates a memory with poolmem subroutines every time a function is called, so it must be freed
465  * when not needed.
466  *
467  * in/out - check API at xacl.h
468  */
469 bRC_XACL XACL_Linux::os_get_xattr_value (JCR *jcr, char * name, char ** pvalue, uint32_t * plen){
470
471    int len;
472    POOLMEM * value;
473
474    /* check input data */
475    if (jcr == NULL || name == NULL || plen == NULL || pvalue == NULL){
476       return bRC_XACL_inval;
477    }
478
479    /* get the length of the value for extended attribute */
480    len = lgetxattr(jcr->last_fname, name, NULL, 0);
481    switch (len){
482       case -1: {
483          berrno be;
484
485          switch (errno){
486             case ENOENT:
487                /* no file available, skip it */
488                return bRC_XACL_skip;
489             default:
490                /* XXX: what about ENOATTR error value? */
491                Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
492                Dmsg2(100, "lgetxattr error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
493                return bRC_XACL_error;
494          }
495          break;
496       }
497       default:
498          break;
499    }
500
501    if (len > 0){
502       /*
503        * allocate memory for the extented attribute value
504        * default size is a 256B for PM_MESSAGE, so we need to check required size
505        */
506       value = get_pool_memory(PM_MESSAGE);
507       value = check_pool_memory_size(value, len + 1);
508       memset(value, 0, len + 1);
509       /* value is not empty, get a data */
510       len = lgetxattr(jcr->last_fname, name, value, len);
511       switch (len){
512       case -1: {
513          berrno be;
514
515          switch (errno){
516          case ENOENT:
517             /* no file available, skip it, first release allocated memory */
518             free_pool_memory(value);
519             return bRC_XACL_skip;
520          default:
521             Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
522             Dmsg2(100, "lgetxattr error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
523             free_pool_memory(value);
524             return bRC_XACL_error;
525          }
526          break;
527       }
528       default:
529          break;
530       }
531       /* ensure a value is nul terminated */
532       value[len] = '\0';
533    } else {
534       /* empty value */
535       value = NULL;
536       len = 0;
537    }
538    /* setup return data */
539    *pvalue = value;
540    *plen = len;
541    return bRC_XACL_ok;
542 };
543
544 /*
545  * Low level OS specyfic runtime to set extended attribute on file
546  *
547  * in/out - check API at xacl.h
548  */
549 bRC_XACL XACL_Linux::os_set_xattr (JCR *jcr, XACL_xattr *xattr){
550
551    /* check input data */
552    if (jcr == NULL || xattr == NULL){
553       return bRC_XACL_inval;
554    }
555
556    /* set extattr on file */
557    if (lsetxattr(jcr->last_fname, xattr->name, xattr->value, xattr->value_len, 0) != 0){
558       berrno be;
559
560       switch (errno){
561       case ENOENT:
562          break;
563       case ENOTSUP:
564          /*
565           * If the filesystem reports it doesn't support XATTR we clear the
566           * XACL_FLAG_NATIVE flag so we skip XATTR restores on all other files
567           * on the same filesystem. The XACL_FLAG_NATIVE flag gets set again
568           * when we change from one filesystem to an other.
569           */
570          clear_flag(XACL_FLAG_NATIVE);
571          Mmsg(jcr->errmsg, _("setxattr error on file \"%s\": filesystem doesn't support XATTR\n"), jcr->last_fname);
572          Dmsg3(100, "setxattr error name=%s value=%s file=%s filesystem doesn't support XATTR\n", xattr->name, xattr->value, jcr->last_fname);
573          break;
574       default:
575          Mmsg2(jcr->errmsg, _("setxattr error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
576          Dmsg2(100, "setxattr error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
577          return bRC_XACL_error;
578       }
579    }
580    return bRC_XACL_ok;
581 };
582
583 #endif /* HAVE_LINUX_OS */