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