Line data Source code
1 : #include "../burp.h"
2 : #include "../alloc.h"
3 : #include "../asfd.h"
4 : #include "../async.h"
5 : #include "../cntr.h"
6 : #include "../log.h"
7 : #include "../prepend.h"
8 : #include "extrameta.h"
9 : #include "xattr.h"
10 :
11 : #ifdef HAVE_XATTR
12 :
13 : #ifdef HAVE_SYS_XATTR_H
14 : #include <sys/xattr.h>
15 : #endif
16 : #ifdef HAVE_SYS_EXTATTR_H
17 : #include <sys/extattr.h>
18 : #endif
19 : #ifdef HAVE_LIBUTIL_H
20 : #include <libutil.h>
21 : #endif
22 :
23 : #ifdef HAVE_DARWIN_OS
24 : /*
25 : * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
26 : * listxattr, getxattr and setxattr with an extra options argument
27 : * which mimics the l variants of the functions when we specify
28 : * XATTR_NOFOLLOW as the options value.
29 : */
30 : #define llistxattr(path, list, size) \
31 : listxattr((path), (list), (size), XATTR_NOFOLLOW)
32 : #define lgetxattr(path, name, value, size) \
33 : getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
34 : #define lsetxattr(path, name, value, size, flags) \
35 : setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
36 : static const char *acl_skiplist[2] = {
37 : "com.apple.system.Security",
38 : NULL
39 : };
40 : #elif HAVE_LINUX_OS
41 : static const char *acl_skiplist[3] = {
42 : "system.posix_acl_access",
43 : "system.posix_acl_default",
44 : NULL
45 : };
46 : #elif HAVE_FREEBSD_OS
47 : static const char *acl_skiplist[2] = {
48 : "system.posix1e.acl_access", NULL
49 : };
50 : #else
51 : static const char *acl_skiplist[1] = {
52 : NULL
53 : };
54 : #endif
55 :
56 : // Skip xattr entries that were already saved as ACLs.
57 4 : static int in_skiplist(const char *xattr)
58 : {
59 7 : for(int c=0; acl_skiplist[c]; c++)
60 6 : if(!strcmp(xattr, acl_skiplist[c]))
61 : return 1;
62 : return 0;
63 : }
64 :
65 13 : static int append_to_extrameta(const char *toappend, char metasymbol,
66 : char **xattrtext, size_t *xlen, ssize_t totallen)
67 : {
68 : char tmp3[10];
69 13 : size_t newlen=0;
70 13 : snprintf(tmp3, sizeof(tmp3), "%c%08X",
71 : metasymbol, (unsigned int)totallen);
72 13 : newlen=(*xlen)+9+totallen;
73 13 : if(!(*xattrtext=(char *)
74 13 : realloc_w(*xattrtext, newlen, __func__)))
75 : return -1;
76 13 : memcpy((*xattrtext)+(*xlen), tmp3, 9);
77 13 : (*xlen)+=9;
78 13 : memcpy((*xattrtext)+(*xlen), toappend, totallen);
79 13 : (*xlen)+=totallen;
80 13 : return 0;
81 : }
82 :
83 : #ifndef UTEST
84 : static
85 : #endif
86 158 : char *get_next_xattr_str(struct asfd *asfd, char **data, size_t *l,
87 : struct cntr *cntr, ssize_t *s, const char *path)
88 : {
89 158 : char *ret=NULL;
90 :
91 158 : if((sscanf(*data, "%08X", (unsigned int *)s))!=1)
92 : {
93 0 : logw(asfd, cntr, "sscanf of xattr '%s' %zd failed for %s\n",
94 : *data, *l, path);
95 0 : return NULL;
96 : }
97 158 : *data+=8;
98 158 : *l-=8;
99 158 : if(!(ret=(char *)malloc_w((*s)+1, __func__)))
100 : return NULL;
101 158 : memcpy(ret, *data, *s);
102 158 : ret[*s]='\0';
103 :
104 158 : *data+=*s;
105 158 : *l-=*s;
106 :
107 158 : return ret;
108 : }
109 :
110 : #ifdef HAVE_SYS_EXTATTR_H
111 : static int namespaces[2] = {
112 : EXTATTR_NAMESPACE_USER,
113 : EXTATTR_NAMESPACE_SYSTEM
114 : };
115 :
116 : int has_xattr(const char *path)
117 : {
118 : int i=0;
119 : for(i=0; i<(int)(sizeof(namespaces)/sizeof(int)); i++)
120 : {
121 : if(extattr_list_link(path, namespaces[i], NULL, 0)>0)
122 : return 1;
123 : }
124 : return 0;
125 : }
126 :
127 : #define BSD_BUF_SIZE 1024
128 : int get_xattr(struct asfd *asfd, const char *path,
129 : char **xattrtext, size_t *xlen, struct cntr *cntr)
130 : {
131 : int i=0;
132 : ssize_t maxlen=0xFFFFFFFF/2;
133 :
134 : for(i=0; i<(int)(sizeof(namespaces)/sizeof(int)); i++)
135 : {
136 : int j=0;
137 : ssize_t len=0;
138 : int have_acl=0;
139 : char *xattrlist=NULL;
140 : char *cnamespace=NULL;
141 : ssize_t totallen=0;
142 : char *toappend=NULL;
143 : char z[BSD_BUF_SIZE]="";
144 : char cattrname[BSD_BUF_SIZE]="";
145 : if((len=extattr_list_link(path, namespaces[i], NULL, 0))<0)
146 : {
147 : logw(asfd, cntr, "could not extattr_list_link of '%s': %zd\n",
148 : path, len);
149 : return 0; // carry on
150 : }
151 : if(!len) continue;
152 : if(xattrtext && *xattrtext)
153 : {
154 : // Already have some meta text, which means that some
155 : // ACLs were set.
156 : have_acl++;
157 : }
158 : if(!(xattrlist=(char *)calloc_w(1, len+1, __func__)))
159 : return -1;
160 : if((len=extattr_list_link(path, namespaces[i], xattrlist, len))<=0)
161 : {
162 : logw(asfd, cntr, "could not extattr_list_link '%s': %zd\n",
163 : path, len);
164 : free_w(&xattrlist);
165 : return 0; // carry on
166 : }
167 : xattrlist[len]='\0';
168 :
169 : if(extattr_namespace_to_string(namespaces[i], &cnamespace))
170 : {
171 : logp("Failed to convert %d into namespace on '%s'\n",
172 : namespaces[i], path);
173 : free_w(&xattrlist);
174 : return 0; // carry on
175 : }
176 :
177 :
178 : for(j=0; j<(int)len; j+=xattrlist[j]+1)
179 : {
180 : int cnt=0;
181 : char tmp1[9];
182 : char tmp2[9];
183 : size_t newlen=0;
184 : size_t zlen=0;
185 : ssize_t vlen=0;
186 : char *val=NULL;
187 : cnt=xattrlist[j];
188 : if(cnt>((int)sizeof(cattrname)-1))
189 : cnt=((int)sizeof(cattrname)-1);
190 : strncpy(cattrname, xattrlist+(j+1), cnt);
191 : cattrname[cnt]='\0';
192 : snprintf(z, sizeof(z), "%s.%s",
193 : cnamespace, cattrname);
194 :
195 : if(have_acl && in_skiplist(z))
196 : continue;
197 : zlen=strlen(z);
198 : //printf("\ngot: %s (%s)\n", z, path);
199 :
200 : if((vlen=extattr_list_link(path, namespaces[i],
201 : xattrlist, len))<0)
202 : {
203 : logw(asfd, cntr, "could not extattr_list_link on %s for %s: %zd\n", path, cnamespace, vlen);
204 : continue;
205 : }
206 : if(vlen)
207 : {
208 : if(!(val=(char *)malloc_w(vlen+1, __func__)))
209 : {
210 : free_w(&xattrlist);
211 : free_w(&toappend);
212 : return -1;
213 : }
214 : if((vlen=extattr_get_link(path, namespaces[i],
215 : cattrname, val, vlen))<0)
216 : {
217 : logw(asfd, cntr, "could not extattr_list_link %s for %s: %zd\n", path, cnamespace, vlen);
218 : free_w(&val);
219 : continue;
220 : }
221 : val[vlen]='\0';
222 :
223 : if(vlen>maxlen)
224 : {
225 : logw(asfd, cntr, "xattr value of '%s' too long: %zd\n",
226 : path, vlen);
227 : free_w(&toappend);
228 : free_w(&val);
229 : break;
230 : }
231 : }
232 :
233 : snprintf(tmp1, sizeof(tmp1), "%08X", (unsigned int)zlen);
234 : snprintf(tmp2, sizeof(tmp2), "%08X", (unsigned int)vlen);
235 : newlen=totallen+8+zlen+8+vlen;
236 : if(!(toappend=(char *)realloc_w(toappend, newlen, __func__)))
237 : {
238 : free_w(&val);
239 : free_w(&xattrlist);
240 : return -1;
241 : }
242 : memcpy(toappend+totallen, tmp1, 8);
243 : totallen+=8;
244 : memcpy(toappend+totallen, z, zlen);
245 : totallen+=zlen;
246 : memcpy(toappend+totallen, tmp2, 8);
247 : totallen+=8;
248 : memcpy(toappend+totallen, val, vlen);
249 : totallen+=vlen;
250 : free_w(&val);
251 :
252 : if(totallen>maxlen)
253 : {
254 : logw(asfd, cntr,
255 : "xattr length of '%s' grew too long: %lu\n",
256 : path, (unsigned long)totallen);
257 : free_w(&val);
258 : free_w(&toappend);
259 : free_w(&xattrlist);
260 : return 0; // carry on
261 : }
262 : }
263 :
264 : if(toappend)
265 : {
266 : if(append_to_extrameta(toappend, META_XATTR_BSD,
267 : xattrtext, xlen, totallen))
268 : {
269 : free_w(&toappend);
270 : free_w(&xattrlist);
271 : return -1;
272 : }
273 : }
274 : free_w(&toappend);
275 : free_w(&xattrlist);
276 : }
277 :
278 : return 0;
279 : }
280 :
281 : static int do_set_xattr_bsd(struct asfd *asfd,
282 : const char *path,
283 : const char *xattrtext, size_t xlen, struct cntr *cntr)
284 : {
285 : int ret=-1;
286 : size_t l=0;
287 : char *data=NULL;
288 : char *value=NULL;
289 : char *nspace=NULL;
290 :
291 : data=(char *)xattrtext;
292 : l=xlen;
293 : while(l>0)
294 : {
295 : ssize_t cnt;
296 : ssize_t vlen=0;
297 : int cnspace=0;
298 : char *name=NULL;
299 :
300 : if(!(nspace=get_next_xattr_str(asfd, &data, &l,
301 : cntr, &vlen, path))
302 : || !(value=get_next_xattr_str(asfd, &data, &l,
303 : cntr, &vlen, path)))
304 : goto end;
305 :
306 : // Need to split the name into two parts.
307 : if(!(name=strchr(nspace, '.')))
308 : {
309 : logw(asfd, cntr,
310 : "could not split %s into namespace and name on %s\n",
311 : nspace, path);
312 : goto end;
313 : }
314 : *name='\0';
315 : name++;
316 :
317 : if(extattr_string_to_namespace(nspace, &cnspace))
318 : {
319 : logw(asfd, cntr,
320 : "could not convert %s into namespace on %s\n",
321 : nspace, path);
322 : goto end;
323 : }
324 :
325 : //printf("set_link: %d %s %s %s\n", cnspace, nspace, name, value);
326 : if((cnt=extattr_set_link(path,
327 : cnspace, name, value, vlen))!=vlen)
328 : {
329 : logw(asfd, cntr,
330 : "extattr_set_link error on %s %zd!=%zd: %s\n",
331 : path, cnt, vlen, strerror(errno));
332 : goto end;
333 : }
334 :
335 : free_w(&nspace);
336 : free_w(&value);
337 : }
338 : ret=0;
339 : end:
340 : free_w(&nspace);
341 : free_w(&value);
342 : return ret;
343 : }
344 :
345 : int set_xattr(struct asfd *asfd, const char *path,
346 : const char *xattrtext,
347 : size_t xlen, char metacmd, struct cntr *cntr)
348 : {
349 : switch(metacmd)
350 : {
351 : case META_XATTR_BSD:
352 : return do_set_xattr_bsd(asfd, path,
353 : xattrtext, xlen, cntr);
354 : default:
355 : logp("unknown xattr type: %c\n", metacmd);
356 : logw(asfd, cntr, "unknown xattr type: %c\n", metacmd);
357 : break;
358 : }
359 : return -1;
360 : }
361 :
362 : #elif HAVE_SYS_XATTR_H
363 :
364 15 : int has_xattr(const char *path)
365 : {
366 15 : if(llistxattr(path, NULL, 0)>0) return 1;
367 15 : return 0;
368 : }
369 :
370 15 : static int get_toappend(struct asfd *asfd, const char *path,
371 : char **toappend, const char *xattrlist, ssize_t len, ssize_t *totallen,
372 : int have_acl,
373 : struct cntr *cntr)
374 : {
375 15 : char *val=NULL;
376 15 : const char *z=NULL;
377 15 : ssize_t maxlen=0xFFFFFFFF/2;
378 :
379 38 : for(z=xattrlist; z-xattrlist < len; z=strchr(z, '\0')+1)
380 : {
381 : char tmp1[9];
382 : char tmp2[9];
383 : ssize_t vlen;
384 23 : ssize_t zlen=0;
385 23 : ssize_t newlen=0;
386 :
387 23 : free_w(&val);
388 :
389 23 : if((zlen=strlen(z))>maxlen)
390 : {
391 0 : logw(asfd, cntr,
392 : "xattr element of '%s' too long: %zd\n",
393 : path, zlen);
394 0 : goto carryon;
395 : }
396 :
397 23 : if(have_acl && in_skiplist(z))
398 6 : continue;
399 :
400 20 : if((vlen=lgetxattr(path, z, NULL, 0))<0)
401 : {
402 0 : logw(asfd, cntr,
403 : "could not lgetxattr on %s for %s: %zd %s\n",
404 0 : path, z, vlen, strerror(errno));
405 0 : continue;
406 : }
407 20 : if(vlen)
408 : {
409 16 : if(!(val=(char *)malloc_w(vlen+1, __func__)))
410 : goto error;
411 16 : if((vlen=lgetxattr(path, z, val, vlen))<0)
412 : {
413 0 : logw(asfd, cntr,
414 : "could not lgetxattr %s for %s: %zd %s\n",
415 0 : path, z, vlen, strerror(errno));
416 0 : continue;
417 : }
418 16 : val[vlen]='\0';
419 :
420 16 : if(vlen>maxlen)
421 : {
422 0 : logw(asfd, cntr,
423 : "xattr value of '%s' too long: %zd\n",
424 : path, vlen);
425 0 : goto carryon;
426 : }
427 : }
428 :
429 20 : snprintf(tmp1, sizeof(tmp1), "%08X", (unsigned int)zlen);
430 20 : snprintf(tmp2, sizeof(tmp2), "%08X", (unsigned int)vlen);
431 20 : newlen=(*totallen)+8+zlen+8+vlen;
432 20 : if(!(*toappend=(char *)realloc_w(*toappend, newlen, __func__)))
433 : goto error;
434 20 : memcpy((*toappend)+(*totallen), tmp1, 8);
435 20 : *totallen+=8;
436 20 : memcpy((*toappend)+(*totallen), z, zlen);
437 20 : *totallen+=zlen;
438 20 : memcpy((*toappend)+(*totallen), tmp2, 8);
439 20 : *totallen+=8;
440 20 : memcpy((*toappend)+(*totallen), val, vlen);
441 20 : *totallen+=vlen;
442 :
443 20 : if(*totallen>maxlen)
444 : {
445 0 : logw(asfd, cntr,
446 : "xattr length of '%s' grew too long: %zd\n",
447 : path, *totallen);
448 0 : goto carryon;
449 : }
450 : }
451 :
452 15 : free_w(&val);
453 15 : return 0;
454 : error:
455 0 : free_w(&val);
456 0 : free_w(toappend);
457 0 : return -1;
458 : carryon:
459 0 : free_w(&val);
460 0 : free_w(toappend);
461 0 : return 0;
462 : }
463 :
464 15 : int get_xattr(struct asfd *asfd, const char *path,
465 : char **xattrtext, size_t *xlen, struct cntr *cntr)
466 : {
467 15 : int ret=0;
468 : ssize_t len;
469 15 : int have_acl=0;
470 15 : char *toappend=NULL;
471 15 : char *xattrlist=NULL;
472 15 : ssize_t totallen=0;
473 :
474 15 : if((len=llistxattr(path, NULL, 0))<0)
475 : {
476 0 : logw(asfd, cntr, "could not llistxattr '%s': %zd %s\n",
477 0 : path, len, strerror(errno));
478 0 : goto end; // Carry on.
479 : }
480 15 : if(!(xattrlist=(char *)calloc_w(1, len, __func__)))
481 : {
482 : ret=-1;
483 : goto end;
484 : }
485 15 : if((len=llistxattr(path, xattrlist, len))<0)
486 : {
487 0 : logw(asfd, cntr, "could not llistxattr '%s': %zd %s\n",
488 0 : path, len, strerror(errno));
489 0 : goto end; // Carry on.
490 : }
491 :
492 15 : if(xattrtext && *xattrtext)
493 : {
494 : // Already have some meta text, which means that some
495 : // ACLs were set.
496 3 : have_acl++;
497 : }
498 :
499 15 : if(get_toappend(asfd, path, &toappend, xattrlist, len, &totallen,
500 : have_acl, cntr))
501 : {
502 : ret=-1;
503 : goto end;
504 : }
505 :
506 15 : if(toappend)
507 13 : ret=append_to_extrameta(toappend, META_XATTR,
508 : xattrtext, xlen, totallen);
509 : end:
510 15 : free_w(&toappend);
511 15 : free_w(&xattrlist);
512 15 : return ret;
513 : }
514 :
515 13 : static int do_set_xattr(struct asfd *asfd,
516 : const char *path,
517 : const char *xattrtext, size_t xlen, struct cntr *cntr)
518 : {
519 13 : size_t l=0;
520 13 : int ret=-1;
521 13 : char *data=NULL;
522 13 : char *name=NULL;
523 13 : char *value=NULL;
524 :
525 13 : data=(char *)xattrtext;
526 13 : l=xlen;
527 46 : while(l>0)
528 : {
529 20 : ssize_t s=0;
530 20 : free_w(&name);
531 20 : free_w(&value);
532 :
533 20 : if(!(name=get_next_xattr_str(asfd, &data, &l,
534 : cntr, &s, path))
535 20 : || !(value=get_next_xattr_str(asfd, &data, &l,
536 : cntr, &s, path)))
537 : goto end;
538 20 : if(lsetxattr(path, name, value, s, 0))
539 : {
540 0 : logw(asfd, cntr, "lsetxattr error on %s: %s\n",
541 0 : path, strerror(errno));
542 0 : goto end;
543 : }
544 : }
545 :
546 : ret=0;
547 : end:
548 13 : free_w(&name);
549 13 : free_w(&value);
550 13 : return ret;
551 : }
552 :
553 13 : int set_xattr(struct asfd *asfd, const char *path,
554 : const char *xattrtext, size_t xlen, char metacmd, struct cntr *cntr)
555 : {
556 13 : switch(metacmd)
557 : {
558 : case META_XATTR:
559 13 : return do_set_xattr(asfd,
560 : path, xattrtext, xlen, cntr);
561 : default:
562 0 : logp("unknown xattr type: %c\n", metacmd);
563 0 : logw(asfd, cntr, "unknown xattr type: %c\n", metacmd);
564 : break;
565 : }
566 0 : return -1;
567 : }
568 : #endif
569 :
570 : #endif
|