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