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