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