2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2016 Kern Sibbald
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.
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.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
20 * Major refactoring of ACL and XATTR code written by:
22 * Radosław Korzeniewski, MMXVI
23 * radoslaw@korzeniewski.net, radekk@inteos.pl
24 * Inteos Sp. z o.o. http://www.inteos.pl/
30 #include "xacl_linux.h"
32 #if defined(HAVE_LINUX_OS)
34 * Define the supported ACL streams for this OS
36 static const int os_acl_streams[] = {
37 STREAM_XACL_LINUX_ACCESS,
41 static const int os_default_acl_streams[] = {
42 STREAM_XACL_LINUX_DEFAULT,
47 * Define the supported XATTR streams for this OS
49 static const int os_xattr_streams[] = {
50 STREAM_XACL_LINUX_XATTR,
54 static const char *os_xattr_acl_skiplist[] = {
55 "system.posix_acl_access",
56 "system.posix_acl_default",
60 static const char *os_xattr_skiplist[] = {
65 * OS Specyfic constructor
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);
74 * Translates Bacula internal acl representation into
78 * xacltype - internal Bacula acl type (XACL_type)
80 * acl_type_t - os dependent acl type
81 * when failed - ACL_TYPE_NONE is returned
83 acl_type_t XACL_Linux::get_acltype(XACL_type xacltype){
88 case XACL_TYPE_ACCESS:
89 acltype = ACL_TYPE_ACCESS;
91 case XACL_TYPE_DEFAULT:
92 acltype = ACL_TYPE_DEFAULT;
96 * sanity check for acl's not supported by OS
98 acltype = (acl_type_t)ACL_TYPE_NONE;
105 * Counts a number of acl entries
110 * int - number of entries in acl object
111 * when no acl entry available or any error then return zero '0'
113 int XACL_Linux::acl_nrentries(acl_t acl){
116 acl_entry_t aclentry;
119 rc = acl_get_entry(acl, ACL_FIRST_ENTRY, &aclentry);
122 rc = acl_get_entry(acl, ACL_NEXT_ENTRY, &aclentry);
129 * Checks if acl is simple.
131 * acl is simple if it has only the following entries:
139 * true - when acl object is simple
140 * false - when acl object is not simple
142 bool XACL_Linux::acl_issimple(acl_t acl){
144 acl_entry_t aclentry;
148 rc = acl_get_entry(acl, ACL_FIRST_ENTRY, &aclentry);
150 if (acl_get_tag_type(aclentry, &acltag) < 0){
154 * Check for ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER to find out.
156 if (acltag != ACL_USER_OBJ &&
157 acltag != ACL_GROUP_OBJ &&
158 acltag != ACL_OTHER){
161 rc = acl_get_entry(acl, ACL_NEXT_ENTRY, &aclentry);
167 * Perform OS specyfic ACL backup
169 * in/out - check API at xacl.h
171 bRC_XACL XACL_Linux::os_backup_acl (JCR *jcr, FF_PKT *ff_pkt){
172 return generic_backup_acl(jcr, ff_pkt);
176 * Perform OS specyfic ACL restore
178 * in/out - check API at xacl.h
180 bRC_XACL XACL_Linux::os_restore_acl (JCR *jcr, int stream, char *content, uint32_t length){
181 return generic_restore_acl(jcr, stream);
185 * Perform OS specyfic extended attribute backup
187 * in/out - check API at xacl.h
189 bRC_XACL XACL_Linux::os_backup_xattr (JCR *jcr, FF_PKT *ff_pkt){
190 return generic_backup_xattr(jcr, ff_pkt);
194 * Perform OS specyfic XATTR restore. Runtime is called only when stream is supported by OS.
196 * in/out - check API at xacl.h
198 bRC_XACL XACL_Linux::os_restore_xattr (JCR *jcr, int stream, char *content, uint32_t length){
199 return generic_restore_xattr(jcr, stream);
203 * Low level OS specyfic runtime to get ACL data from file. The ACL data is set in internal content buffer.
205 * in/out - check API at xacl.h
207 bRC_XACL XACL_Linux::os_get_acl(JCR *jcr, XACL_type xacltype){
212 bRC_XACL rc = bRC_XACL_ok;
214 /* check input data */
216 return bRC_XACL_inval;
219 acltype = get_acltype(xacltype);
220 acl = acl_get_file(jcr->last_fname, acltype);
223 Dmsg1(400, "OS_ACL read from file: %s\n",jcr->last_fname);
224 if (acl_nrentries(acl) == 0){
228 /* check for fimple ACL which correspond to standard permissions only */
229 if (xacltype == XACL_TYPE_ACCESS && acl_issimple(acl)){
233 if ((acltext = acl_to_text(acl, NULL)) != NULL){
234 set_content(acltext);
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());
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);
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());
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.
281 * Low level OS specyfic runtime to set ACL data on file
283 * in/out - check API at xacl.h
285 bRC_XACL XACL_Linux::os_set_acl(JCR *jcr, XACL_type xacltype, char *content, uint32_t length){
290 /* check input data */
291 if (jcr == NULL || content == NULL){
292 return bRC_XACL_inval;
295 acl = acl_from_text(content);
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;
304 if (acl_valid(acl) != 0){
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());
310 return bRC_XACL_error;
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){
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.
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;
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;
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)
347 if (acl_set_file(jcr->last_fname, acltype, acl) != 0 && jcr->last_type != FT_LNK){
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.
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);
364 return bRC_XACL_error;
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());
369 return bRC_XACL_error;
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
381 * in/out - check API at xacl.h
383 bRC_XACL XACL_Linux::os_get_xattr_names (JCR *jcr, POOLMEM ** pxlist, uint32_t * xlen){
388 /* check input data */
389 if (jcr == NULL || xlen == NULL || pxlist == NULL){
390 return bRC_XACL_inval;
393 /* get the length of the extended attributes */
394 len = llistxattr(jcr->last_fname, NULL, 0);
401 /* no file available, skip it */
402 return bRC_XACL_skip;
404 /* no xattr supported on filesystem, clear a flag and skip it */
405 clear_flag(XACL_FLAG_NATIVE);
407 return bRC_XACL_skip;
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;
416 /* xattr available but empty, skip it */
417 return bRC_XACL_skip;
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
428 list = get_pool_memory(PM_BSOCK);
429 list = check_pool_memory_size(list, len + 1);
430 memset(list, 0, len + 1);
432 /* get the list of extended attributes names for a file */
433 len = llistxattr(jcr->last_fname, list, len);
440 /* no file available, skip it, first release allocated memory */
441 free_pool_memory(list);
442 return bRC_XACL_skip;
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;
454 /* ensure a list is nul terminated */
456 /* setup return data */
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
467 * in/out - check API at xacl.h
469 bRC_XACL XACL_Linux::os_get_xattr_value (JCR *jcr, char * name, char ** pvalue, uint32_t * plen){
474 /* check input data */
475 if (jcr == NULL || name == NULL || plen == NULL || pvalue == NULL){
476 return bRC_XACL_inval;
479 /* get the length of the value for extended attribute */
480 len = lgetxattr(jcr->last_fname, name, NULL, 0);
487 /* no file available, skip it */
488 return bRC_XACL_skip;
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;
503 * allocate memory for the extented attribute value
504 * default size is a 256B for PM_MESSAGE, so we need to check required size
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);
517 /* no file available, skip it, first release allocated memory */
518 free_pool_memory(value);
519 return bRC_XACL_skip;
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;
531 /* ensure a value is nul terminated */
538 /* setup return data */
545 * Low level OS specyfic runtime to set extended attribute on file
547 * in/out - check API at xacl.h
549 bRC_XACL XACL_Linux::os_set_xattr (JCR *jcr, XACL_xattr *xattr){
551 /* check input data */
552 if (jcr == NULL || xattr == NULL){
553 return bRC_XACL_inval;
556 /* set extattr on file */
557 if (lsetxattr(jcr->last_fname, xattr->name, xattr->value, xattr->value_len, 0) != 0){
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.
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);
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;
583 #endif /* HAVE_LINUX_OS */