1 /*
2    Bacula(R) - The Network Backup Solution
3 
4    Copyright (C) 2000-2020 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 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 "bxattr_linux.h"
31 
32 #if defined(HAVE_LINUX_OS)
33 
34 /* check if XATTR support is enabled */
35 #if defined(HAVE_XATTR)
36 
37 /*
38  * Define the supported XATTR streams for this OS
39  */
40 static const int os_xattr_streams[] = {
41    STREAM_XACL_LINUX_XATTR,
42    0
43 };
44 
45 static const char *os_xattr_acl_skiplist[] = {
46    "system.posix_acl_access",
47    "system.posix_acl_default",
48    NULL
49 };
50 
51 static const char *os_xattr_skiplist[] = {
52    NULL
53 };
54 
55 /*
56  * OS specific constructor
57  */
BXATTR_Linux()58 BXATTR_Linux::BXATTR_Linux(){
59    set_xattr_streams(os_xattr_streams);
60    set_xattr_skiplists(os_xattr_skiplist, os_xattr_acl_skiplist);
61 };
62 
63 /*
64  * Perform OS specific extended attribute backup
65  *
66  * in/out - check API at bxattr.h
67  */
os_backup_xattr(JCR * jcr,FF_PKT * ff_pkt)68 bRC_BXATTR BXATTR_Linux::os_backup_xattr (JCR *jcr, FF_PKT *ff_pkt){
69    return generic_backup_xattr(jcr, ff_pkt);
70 };
71 
72 /*
73  * Perform OS specific XATTR restore. Runtime is called only when stream is supported by OS.
74  *
75  * in/out - check API at bxattr.h
76  */
os_restore_xattr(JCR * jcr,int stream,char * content,uint32_t length)77 bRC_BXATTR BXATTR_Linux::os_restore_xattr (JCR *jcr, int stream, char *content, uint32_t length){
78    return generic_restore_xattr(jcr, stream);
79 };
80 
81 #define CIFS_XATTR "system.cifs_acl"
82 #define CIFS_XATTR_LEN 15
83 
84 /*
85  * Return a list of xattr names in newly allocated pool memory and a length of the allocated buffer.
86  * It allocates a memory with poolmem subroutines every time a function is called, so it must be freed
87  * when not needed.
88  *
89  * in/out - check API at bxattr.h
90  */
os_get_xattr_names(JCR * jcr,POOLMEM ** pxlist,uint32_t * xlen)91 bRC_BXATTR BXATTR_Linux::os_get_xattr_names (JCR *jcr, POOLMEM ** pxlist, uint32_t * xlen){
92 
93    int len, len2;
94    POOLMEM * list;
95    bool append_cifs=false;
96 
97    /* check input data */
98    if (jcr == NULL || xlen == NULL || pxlist == NULL){
99       return bRC_BXATTR_inval;
100    }
101 
102    /* With CIFS and CIFS2, the system.cifs_acl attribute holds the BackupRead
103     * information, but it is not listed by llistxattr
104     */
105    if (strncmp(get_current_fs(), "cifs", 4) == 0) {
106       append_cifs = true;
107    }
108 
109    /* get the length of the extended attributes */
110    len = llistxattr(jcr->last_fname, NULL, 0);
111    switch (len){
112       case -1: {
113          berrno be;
114 
115          switch (errno){
116             case ENOENT:
117                /* no file available, skip it */
118                return bRC_BXATTR_skip;
119             case EOPNOTSUPP:
120                /* no xattr supported on filesystem, clear a flag and skip it */
121                clear_flag(BXATTR_FLAG_NATIVE);
122                set_content(NULL);
123                return bRC_BXATTR_skip;
124             default:
125                Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
126                Dmsg2(100, "llistxattr error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
127                return bRC_BXATTR_error;
128          }
129          break;
130       }
131       case 0:
132          if (append_cifs) {     /* We have nothing, but the cifs attribute can be hidden */
133             len += CIFS_XATTR_LEN + 1;
134          } else {
135             /* xattr available but empty, skip it */
136             return bRC_BXATTR_skip;
137          }
138       default:
139          break;
140    }
141 
142    /*
143     * allocate memory for the extented attribute list
144     * default size is a 4k for PM_BSOCK, which should be sufficient on almost all
145     * Linux system where xattrs a limited in size to single filesystem block ~4kB
146     * so we need to check required size
147     */
148    list = get_pool_memory(PM_BSOCK);
149    list = check_pool_memory_size(list, len + 1);
150    memset(list, 0, len + 1);
151 
152    /* get the list of extended attributes names for a file */
153    len2 = llistxattr(jcr->last_fname, list, len);
154    switch (len2){
155    case -1: {
156       berrno be;
157 
158       switch (errno){
159       case ENOENT:
160          /* no file available, skip it, first release allocated memory */
161          free_pool_memory(list);
162          return bRC_BXATTR_skip;
163       default:
164          Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
165          Dmsg2(100, "llistxattr error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
166          free_pool_memory(list);
167          return bRC_BXATTR_error;
168       }
169       break;
170    }
171    default:
172       break;
173    }
174    /* ensure a list is nul terminated */
175    list[len2] = '\0';
176    if (append_cifs) {
177       len2 = xattr_list_append(list, len2, CIFS_XATTR, CIFS_XATTR_LEN);
178    }
179    /* setup return data */
180    *pxlist = list;
181    *xlen = len2;
182    return bRC_BXATTR_ok;
183 };
184 
185 /*
186  * Return a value of the requested attribute name and a length of the allocated buffer.
187  * It allocates a memory with poolmem subroutines every time a function is called, so it must be freed
188  * when not needed.
189  *
190  * in/out - check API at bxattr.h
191  */
os_get_xattr_value(JCR * jcr,char * name,char ** pvalue,uint32_t * plen)192 bRC_BXATTR BXATTR_Linux::os_get_xattr_value (JCR *jcr, char * name, char ** pvalue, uint32_t * plen){
193 
194    int len;
195    POOLMEM * value;
196 
197    /* check input data */
198    if (jcr == NULL || name == NULL || plen == NULL || pvalue == NULL){
199       return bRC_BXATTR_inval;
200    }
201 
202    /* get the length of the value for extended attribute */
203    len = lgetxattr(jcr->last_fname, name, NULL, 0);
204    switch (len){
205       case -1: {
206          berrno be;
207 
208          switch (errno){
209             case ENOENT:
210                /* no file available, skip it */
211                return bRC_BXATTR_skip;
212             default:
213                /* XXX: what about ENOATTR error value? */
214                Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
215                Dmsg2(100, "lgetxattr error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
216                return bRC_BXATTR_error;
217          }
218          break;
219       }
220       default:
221          break;
222    }
223 
224    if (len > 0){
225       /*
226        * allocate memory for the extented attribute value
227        * default size is a 256B for PM_MESSAGE, so we need to check required size
228        */
229       value = get_pool_memory(PM_MESSAGE);
230       value = check_pool_memory_size(value, len + 1);
231       memset(value, 0, len + 1);
232       /* value is not empty, get a data */
233       len = lgetxattr(jcr->last_fname, name, value, len);
234       switch (len){
235       case -1: {
236          berrno be;
237 
238          switch (errno){
239          case ENOENT:
240             /* no file available, skip it, first release allocated memory */
241             free_pool_memory(value);
242             return bRC_BXATTR_skip;
243          default:
244             Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
245             Dmsg2(100, "lgetxattr error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
246             free_pool_memory(value);
247             return bRC_BXATTR_error;
248          }
249          break;
250       }
251       default:
252          break;
253       }
254       /* ensure a value is nul terminated */
255       value[len] = '\0';
256    } else {
257       /* empty value */
258       value = NULL;
259       len = 0;
260    }
261    /* setup return data */
262    *pvalue = value;
263    *plen = len;
264    return bRC_BXATTR_ok;
265 };
266 
267 /*
268  * Low level OS specific runtime to set extended attribute on file
269  *
270  * in/out - check API at bxattr.h
271  */
os_set_xattr(JCR * jcr,BXATTR_xattr * xattr)272 bRC_BXATTR BXATTR_Linux::os_set_xattr (JCR *jcr, BXATTR_xattr *xattr){
273 
274    /* check input data */
275    if (jcr == NULL || xattr == NULL){
276       return bRC_BXATTR_inval;
277    }
278 
279    /* set extattr on file */
280    if (lsetxattr(jcr->last_fname, xattr->name, xattr->value, xattr->value_len, 0) != 0){
281       berrno be;
282 
283       switch (errno){
284       case ENOENT:
285          break;
286       case ENOTSUP:
287          /*
288           * If the filesystem reports it doesn't support XATTR we clear the
289           * BXATTR_FLAG_NATIVE flag so we skip XATTR restores on all other files
290           * on the same filesystem. The BXATTR_FLAG_NATIVE flag gets set again
291           * when we change from one filesystem to an other.
292           */
293          clear_flag(BXATTR_FLAG_NATIVE);
294          Mmsg(jcr->errmsg, _("setxattr error on file \"%s\": filesystem doesn't support XATTR\n"), jcr->last_fname);
295          Dmsg3(100, "setxattr error name=%s value=%s file=%s filesystem doesn't support XATTR\n", xattr->name, xattr->value, jcr->last_fname);
296          break;
297       default:
298          Mmsg2(jcr->errmsg, _("setxattr error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
299          Dmsg2(100, "setxattr error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
300          return bRC_BXATTR_error;
301       }
302    }
303    return bRC_BXATTR_ok;
304 };
305 
306 #endif /* HAVE_XATTR */
307 
308 #endif /* HAVE_LINUX_OS */
309