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 : static int in_skiplist(const char *xattr)
58 : {
59 3 : 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, uint32_t totallen)
67 : {
68 : char tmp3[10];
69 13 : size_t newlen=0;
70 13 : snprintf(tmp3, sizeof(tmp3), "%c%08X", metasymbol, totallen);
71 13 : newlen=(*xlen)+9+totallen+1;
72 13 : if(!(*xattrtext=(char *)
73 13 : realloc_w(*xattrtext, newlen, __func__)))
74 : return -1;
75 13 : memcpy((*xattrtext)+(*xlen), tmp3, 9);
76 13 : (*xlen)+=9;
77 13 : memcpy((*xattrtext)+(*xlen), toappend, totallen);
78 13 : (*xlen)+=totallen;
79 13 : (*xattrtext)[*xlen]='\0';
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, uint32_t *s, const char *path)
88 : {
89 158 : char *ret=NULL;
90 :
91 158 : if(*l<8)
92 : {
93 0 : logw(asfd, cntr, "length of xattr '%s' %zd is too short for %s\n",
94 : *data, *l, path);
95 0 : return NULL;
96 : }
97 :
98 158 : if((sscanf(*data, "%08X", s))!=1)
99 : {
100 0 : logw(asfd, cntr, "sscanf of xattr '%s' %zd failed for %s\n",
101 : *data, *l, path);
102 0 : return NULL;
103 : }
104 158 : *data+=8;
105 158 : *l-=8;
106 158 : if(*s>*l)
107 : {
108 0 : logw(asfd, cntr, "requested length %d of xattr '%s' %zd is too long for %s\n",
109 : *s, *data, *l, path);
110 0 : return NULL;
111 : }
112 158 : if(!(ret=(char *)malloc_w((*s)+1, __func__)))
113 : return NULL;
114 158 : memcpy(ret, *data, *s);
115 158 : ret[*s]='\0';
116 :
117 158 : *data+=*s;
118 158 : *l-=*s;
119 :
120 158 : return ret;
121 : }
122 :
123 : #ifdef HAVE_SYS_EXTATTR_H
124 : static int namespaces[2] = {
125 : EXTATTR_NAMESPACE_USER,
126 : EXTATTR_NAMESPACE_SYSTEM
127 : };
128 :
129 : int has_xattr(const char *path)
130 : {
131 : int i=0;
132 : for(i=0; i<(int)(sizeof(namespaces)/sizeof(int)); i++)
133 : {
134 : if(extattr_list_link(path, namespaces[i], NULL, 0)>0)
135 : return 1;
136 : }
137 : return 0;
138 : }
139 :
140 : #define BSD_BUF_SIZE 1024
141 : int get_xattr(struct asfd *asfd, const char *path,
142 : char **xattrtext, size_t *xlen, struct cntr *cntr)
143 : {
144 : int i=0;
145 : uint32_t maxlen=0xFFFFFFFF/2;
146 :
147 : for(i=0; i<(int)(sizeof(namespaces)/sizeof(int)); i++)
148 : {
149 : int j=0;
150 : ssize_t len=0;
151 : int have_acl=0;
152 : char *xattrlist=NULL;
153 : char *cnamespace=NULL;
154 : uint32_t totallen=0;
155 : char *toappend=NULL;
156 : static char z[BSD_BUF_SIZE*2]="";
157 : char cattrname[BSD_BUF_SIZE]="";
158 : if((len=extattr_list_link(path, namespaces[i], NULL, 0))<0)
159 : {
160 : logw(asfd, cntr, "could not extattr_list_link of '%s': %zd\n",
161 : path, len);
162 : return 0; // carry on
163 : }
164 : if(!len) continue;
165 : if(xattrtext && *xattrtext)
166 : {
167 : // Already have some meta text, which means that some
168 : // ACLs were set.
169 : have_acl++;
170 : }
171 : if(!(xattrlist=(char *)calloc_w(1, len+1, __func__)))
172 : return -1;
173 : if((len=extattr_list_link(path, namespaces[i], xattrlist, len))<=0)
174 : {
175 : logw(asfd, cntr, "could not extattr_list_link '%s': %zd\n",
176 : path, len);
177 : free_w(&xattrlist);
178 : return 0; // carry on
179 : }
180 : xattrlist[len]='\0';
181 :
182 : if(extattr_namespace_to_string(namespaces[i], &cnamespace))
183 : {
184 : logp("Failed to convert %d into namespace on '%s'\n",
185 : namespaces[i], path);
186 : free_w(&xattrlist);
187 : return 0; // carry on
188 : }
189 :
190 :
191 : for(j=0; j<(int)len; j+=xattrlist[j]+1)
192 : {
193 : int cnt=0;
194 : char tmp1[9];
195 : char tmp2[9];
196 : size_t newlen=0;
197 : uint32_t zlen=0;
198 : ssize_t vlen=0;
199 : char *val=NULL;
200 : cnt=xattrlist[j];
201 : if(cnt>((int)sizeof(cattrname)-1))
202 : cnt=((int)sizeof(cattrname)-1);
203 : strncpy(cattrname, xattrlist+(j+1), cnt);
204 : cattrname[cnt]='\0';
205 : snprintf(z, sizeof(z), "%s.%s",
206 : cnamespace, cattrname);
207 :
208 : if(have_acl && in_skiplist(z))
209 : continue;
210 : zlen=(uint32_t)strlen(z);
211 : //printf("\ngot: %s (%s)\n", z, path);
212 :
213 : if((vlen=extattr_list_link(path, namespaces[i],
214 : xattrlist, len))<0)
215 : {
216 : logw(asfd, cntr, "could not extattr_list_link on %s for %s: %zd\n", path, cnamespace, vlen);
217 : continue;
218 : }
219 : if(vlen)
220 : {
221 : if(!(val=(char *)malloc_w(vlen+1, __func__)))
222 : {
223 : free_w(&xattrlist);
224 : free_w(&toappend);
225 : return -1;
226 : }
227 : if((vlen=extattr_get_link(path, namespaces[i],
228 : cattrname, val, vlen))<0)
229 : {
230 : logw(asfd, cntr, "could not extattr_list_link %s for %s: %zd\n", path, cnamespace, vlen);
231 : free_w(&val);
232 : continue;
233 : }
234 : val[vlen]='\0';
235 :
236 : if(vlen>maxlen)
237 : {
238 : logw(asfd, cntr, "xattr value of '%s' too long: %zd\n",
239 : path, vlen);
240 : free_w(&toappend);
241 : free_w(&val);
242 : break;
243 : }
244 : }
245 :
246 : snprintf(tmp1, sizeof(tmp1), "%08X", zlen);
247 : snprintf(tmp2, sizeof(tmp2), "%08X", (uint32_t)vlen);
248 : newlen=totallen+8+zlen+8+vlen;
249 : if(!(toappend=(char *)realloc_w(toappend, newlen, __func__)))
250 : {
251 : free_w(&val);
252 : free_w(&xattrlist);
253 : return -1;
254 : }
255 : memcpy(toappend+totallen, tmp1, 8);
256 : totallen+=8;
257 : memcpy(toappend+totallen, z, zlen);
258 : totallen+=zlen;
259 : memcpy(toappend+totallen, tmp2, 8);
260 : totallen+=8;
261 : memcpy(toappend+totallen, val, vlen);
262 : totallen+=vlen;
263 : free_w(&val);
264 :
265 : if(totallen>maxlen)
266 : {
267 : logw(asfd, cntr,
268 : "xattr length of '%s' grew too long: %d\n",
269 : path, totallen);
270 : free_w(&val);
271 : free_w(&toappend);
272 : free_w(&xattrlist);
273 : return 0; // carry on
274 : }
275 : }
276 :
277 : if(toappend)
278 : {
279 : if(append_to_extrameta(toappend, META_XATTR_BSD,
280 : xattrtext, xlen, totallen))
281 : {
282 : free_w(&toappend);
283 : free_w(&xattrlist);
284 : return -1;
285 : }
286 : }
287 : free_w(&toappend);
288 : free_w(&xattrlist);
289 : }
290 :
291 : return 0;
292 : }
293 :
294 : static int do_set_xattr_bsd(struct asfd *asfd,
295 : const char *path,
296 : const char *xattrtext, size_t xlen, struct cntr *cntr)
297 : {
298 : int ret=-1;
299 : size_t l=0;
300 : char *data=NULL;
301 : char *value=NULL;
302 : char *nspace=NULL;
303 :
304 : data=(char *)xattrtext;
305 : l=xlen;
306 : while(l>0)
307 : {
308 : ssize_t cnt;
309 : uint32_t vlen=0;
310 : int cnspace=0;
311 : char *name=NULL;
312 :
313 : if(!(nspace=get_next_xattr_str(asfd, &data, &l,
314 : cntr, &vlen, path))
315 : || !(value=get_next_xattr_str(asfd, &data, &l,
316 : cntr, &vlen, path)))
317 : goto end;
318 :
319 : // Need to split the name into two parts.
320 : if(!(name=strchr(nspace, '.')))
321 : {
322 : logw(asfd, cntr,
323 : "could not split %s into namespace and name on %s\n",
324 : nspace, path);
325 : goto end;
326 : }
327 : *name='\0';
328 : name++;
329 :
330 : if(extattr_string_to_namespace(nspace, &cnspace))
331 : {
332 : logw(asfd, cntr,
333 : "could not convert %s into namespace on %s\n",
334 : nspace, path);
335 : goto end;
336 : }
337 :
338 : //printf("set_link: %d %s %s %s\n", cnspace, nspace, name, value);
339 : if((cnt=extattr_set_link(path,
340 : cnspace, name, value, vlen))!=vlen)
341 : {
342 : logw(asfd, cntr,
343 : "extattr_set_link error on %s %zd!=%d: %s\n",
344 : path, cnt, vlen, strerror(errno));
345 : goto end;
346 : }
347 :
348 : free_w(&nspace);
349 : free_w(&value);
350 : }
351 : ret=0;
352 : end:
353 : free_w(&nspace);
354 : free_w(&value);
355 : return ret;
356 : }
357 :
358 : int set_xattr(struct asfd *asfd, const char *path,
359 : const char *xattrtext,
360 : size_t xlen, char metacmd, struct cntr *cntr)
361 : {
362 : switch(metacmd)
363 : {
364 : case META_XATTR_BSD:
365 : return do_set_xattr_bsd(asfd, path,
366 : xattrtext, xlen, cntr);
367 : default:
368 : logp("unknown xattr type: %c\n", metacmd);
369 : logw(asfd, cntr, "unknown xattr type: %c\n", metacmd);
370 : break;
371 : }
372 : return -1;
373 : }
374 :
375 : #elif HAVE_SYS_XATTR_H
376 :
377 15 : int has_xattr(const char *path)
378 : {
379 15 : if(llistxattr(path, NULL, 0)>0) return 1;
380 15 : return 0;
381 : }
382 :
383 15 : static int get_toappend(struct asfd *asfd, const char *path,
384 : char **toappend, const char *xattrlist,
385 : ssize_t len, uint32_t *totallen,
386 : int have_acl,
387 : struct cntr *cntr)
388 : {
389 15 : char *val=NULL;
390 15 : const char *z=NULL;
391 15 : uint32_t maxlen=0xFFFFFFFF/2;
392 :
393 38 : for(z=xattrlist; z-xattrlist < len; z=strchr(z, '\0')+1)
394 : {
395 : char tmp1[9];
396 : char tmp2[9];
397 : ssize_t vlen;
398 23 : uint32_t zlen=0;
399 23 : uint32_t newlen=0;
400 :
401 23 : free_w(&val);
402 :
403 23 : if((zlen=(uint32_t)strlen(z))>maxlen)
404 : {
405 0 : logw(asfd, cntr,
406 : "xattr element of '%s' too long: %d\n",
407 : path, zlen);
408 0 : goto carryon;
409 : }
410 :
411 27 : if(have_acl && in_skiplist(z))
412 6 : continue;
413 :
414 20 : if((vlen=lgetxattr(path, z, NULL, 0))<0)
415 : {
416 0 : logw(asfd, cntr,
417 : "could not lgetxattr on %s for %s: %zd %s\n",
418 0 : path, z, vlen, strerror(errno));
419 0 : continue;
420 : }
421 20 : if(vlen)
422 : {
423 16 : if(!(val=(char *)malloc_w(vlen+1, __func__)))
424 : goto error;
425 16 : if((vlen=lgetxattr(path, z, val, vlen))<0)
426 : {
427 0 : logw(asfd, cntr,
428 : "could not lgetxattr %s for %s: %zd %s\n",
429 0 : path, z, vlen, strerror(errno));
430 0 : continue;
431 : }
432 16 : val[vlen]='\0';
433 :
434 16 : if(vlen>maxlen)
435 : {
436 0 : logw(asfd, cntr,
437 : "xattr value of '%s' too long: %zd\n",
438 : path, vlen);
439 0 : goto carryon;
440 : }
441 : }
442 :
443 20 : snprintf(tmp1, sizeof(tmp1), "%08X", zlen);
444 20 : snprintf(tmp2, sizeof(tmp2), "%08X", (uint32_t)vlen);
445 20 : newlen=(*totallen)+8+zlen+8+vlen;
446 20 : if(!(*toappend=(char *)realloc_w(*toappend, newlen, __func__)))
447 : goto error;
448 20 : memcpy((*toappend)+(*totallen), tmp1, 8);
449 20 : *totallen+=8;
450 20 : memcpy((*toappend)+(*totallen), z, zlen);
451 20 : *totallen+=zlen;
452 20 : memcpy((*toappend)+(*totallen), tmp2, 8);
453 20 : *totallen+=8;
454 20 : memcpy((*toappend)+(*totallen), val, vlen);
455 20 : *totallen+=vlen;
456 :
457 20 : if(*totallen>maxlen)
458 : {
459 0 : logw(asfd, cntr,
460 : "xattr length of '%s' grew too long: %d\n",
461 : path, *totallen);
462 0 : goto carryon;
463 : }
464 : }
465 :
466 15 : free_w(&val);
467 15 : return 0;
468 : error:
469 0 : free_w(&val);
470 0 : free_w(toappend);
471 0 : return -1;
472 : carryon:
473 0 : free_w(&val);
474 0 : free_w(toappend);
475 0 : return 0;
476 : }
477 :
478 15 : int get_xattr(struct asfd *asfd, const char *path,
479 : char **xattrtext, size_t *xlen, struct cntr *cntr)
480 : {
481 15 : int ret=0;
482 : ssize_t len;
483 15 : int have_acl=0;
484 15 : char *toappend=NULL;
485 15 : char *xattrlist=NULL;
486 15 : uint32_t totallen=0;
487 :
488 15 : if((len=llistxattr(path, NULL, 0))<0)
489 : {
490 0 : logw(asfd, cntr, "could not llistxattr '%s': %zd %s\n",
491 0 : path, len, strerror(errno));
492 0 : goto end; // Carry on.
493 : }
494 15 : if(!(xattrlist=(char *)calloc_w(1, len, __func__)))
495 : {
496 : ret=-1;
497 : goto end;
498 : }
499 15 : if((len=llistxattr(path, xattrlist, len))<0)
500 : {
501 0 : logw(asfd, cntr, "could not llistxattr '%s': %zd %s\n",
502 0 : path, len, strerror(errno));
503 0 : goto end; // Carry on.
504 : }
505 :
506 15 : if(xattrtext && *xattrtext)
507 : {
508 : // Already have some meta text, which means that some
509 : // ACLs were set.
510 3 : have_acl++;
511 : }
512 :
513 15 : if(get_toappend(asfd, path, &toappend, xattrlist, len, &totallen,
514 : have_acl, cntr))
515 : {
516 : ret=-1;
517 : goto end;
518 : }
519 :
520 15 : if(toappend)
521 13 : ret=append_to_extrameta(toappend, META_XATTR,
522 : xattrtext, xlen, totallen);
523 : end:
524 15 : free_w(&toappend);
525 15 : free_w(&xattrlist);
526 15 : return ret;
527 : }
528 :
529 13 : static int do_set_xattr(struct asfd *asfd,
530 : const char *path,
531 : const char *xattrtext, size_t xlen, struct cntr *cntr)
532 : {
533 : size_t l=0;
534 13 : int ret=-1;
535 : char *data=NULL;
536 13 : char *name=NULL;
537 13 : char *value=NULL;
538 :
539 13 : data=(char *)xattrtext;
540 13 : l=xlen;
541 46 : while(l>0)
542 : {
543 20 : uint32_t s=0;
544 20 : free_w(&name);
545 20 : free_w(&value);
546 :
547 20 : if(!(name=get_next_xattr_str(asfd, &data, &l,
548 : cntr, &s, path))
549 20 : || !(value=get_next_xattr_str(asfd, &data, &l,
550 : cntr, &s, path)))
551 : goto end;
552 20 : if(lsetxattr(path, name, value, s, 0))
553 : {
554 0 : logw(asfd, cntr, "lsetxattr error on %s: %s\n",
555 0 : path, strerror(errno));
556 0 : goto end;
557 : }
558 : }
559 :
560 : ret=0;
561 : end:
562 13 : free_w(&name);
563 13 : free_w(&value);
564 13 : return ret;
565 : }
566 :
567 13 : int set_xattr(struct asfd *asfd, const char *path,
568 : const char *xattrtext, size_t xlen, char metacmd, struct cntr *cntr)
569 : {
570 13 : switch(metacmd)
571 : {
572 : case META_XATTR:
573 13 : return do_set_xattr(asfd,
574 : path, xattrtext, xlen, cntr);
575 : default:
576 0 : logp("unknown xattr type: %c\n", metacmd);
577 0 : logw(asfd, cntr, "unknown xattr type: %c\n", metacmd);
578 : break;
579 : }
580 0 : return -1;
581 : }
582 : #endif
583 :
584 : #ifdef UTEST
585 1098 : int fs_supports_xattr(void)
586 : {
587 : FILE *fp;
588 1098 : int ret=-1;
589 1098 : const char *fname="xattr_test_file";
590 1098 : if(!(fp=fopen(fname, "w")))
591 : {
592 0 : printf("Could not open %s!\n", fname);
593 0 : return 0;
594 : }
595 1098 : fclose(fp);
596 : #ifdef HAVE_SYS_EXTATTR_H
597 : ret=extattr_set_link(fname, EXTATTR_NAMESPACE_USER, "comment", "a", strlen("a"));
598 : #elif HAVE_SYS_XATTR_H
599 1098 : ret=lsetxattr(fname, "user.comment", "a", strlen("a"), /*flags*/0);
600 : #else
601 : errno=ENOTSUP;
602 : #endif
603 1098 : if(ret<0 && errno==ENOTSUP)
604 : {
605 0 : printf("File system does not support xattrs!\n");
606 0 : unlink(fname);
607 0 : return 0;
608 : }
609 1098 : unlink(fname);
610 1098 : return 1;
611 : }
612 : #endif
613 :
614 : #endif
|