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