]> git.wh0rd.org - dump.git/blame - restore/xattr.c
Regenerate configure.
[dump.git] / restore / xattr.c
CommitLineData
cca7148b
SP
1/*
2 * Copyright (c) 1999-2004
3 * Stelian Pop <stelian@popies.net>, 1999-2004
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#ifndef lint
31static const char rcsid[] =
67febcc5 32 "$Id: xattr.c,v 1.7 2010/06/11 11:19:17 stelian Exp $";
cca7148b
SP
33#endif /* not lint */
34
35#include <config.h>
36#include <compatlfs.h>
37#include <compaterr.h>
38#include <sys/types.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <unistd.h>
43#include <errno.h>
44#include <bsdcompat.h>
45#include <protocols/dumprestore.h>
7f7d329e
SP
46#ifdef TRANSSELINUX /*GAN6May06 SELinux MLS */
47# include <selinux/selinux.h>
48#endif
cca7148b
SP
49#include "restore.h"
50#include "extern.h"
51#include "pathnames.h"
52
53/*
54 * Data structures below taken from the kernel
55 */
56
57/* Maximum number of references to one attribute block */
58#define EXT2_XATTR_REFCOUNT_MAX 1024
59
60/* Name indexes */
61#define EXT2_XATTR_INDEX_MAX 10
62#define EXT2_XATTR_INDEX_USER 1
63#define EXT2_XATTR_INDEX_POSIX_ACL_ACCESS 2
64#define EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT 3
65#define EXT2_XATTR_INDEX_TRUSTED 4
66#define EXT2_XATTR_INDEX_LUSTRE 5
67#define EXT2_XATTR_INDEX_SECURITY 6
68
69struct ext2_xattr_header {
70 u_int32_t h_magic; /* magic number for identification */
71 u_int32_t h_refcount; /* reference count */
72 u_int32_t h_blocks; /* number of disk blocks used */
73 u_int32_t h_hash; /* hash value of all attributes */
74 u_int32_t h_reserved[4]; /* zero right now */
75};
76
77struct ext3_xattr_ibody_header {
78 u_int32_t h_magic; /* magic number for identification */
79};
80
81struct ext2_xattr_entry {
82 u_char e_name_len; /* length of name */
83 u_char e_name_index; /* attribute name index */
84 u_int16_t e_value_offs; /* offset in disk block of value */
85 u_int32_t e_value_block; /* disk block attribute is stored on (n/i) */
86 u_int32_t e_value_size; /* size of attribute value */
87 u_int32_t e_hash; /* hash value of name and value */
88 char e_name[0]; /* attribute name */
89};
90
91#define EXT2_XATTR_PAD_BITS 2
92#define EXT2_XATTR_PAD (1<<EXT2_XATTR_PAD_BITS)
93#define EXT2_XATTR_ROUND (EXT2_XATTR_PAD-1)
67febcc5 94#ifndef EXT2_XATTR_LEN
cca7148b
SP
95#define EXT2_XATTR_LEN(name_len) \
96 (((name_len) + EXT2_XATTR_ROUND + \
97 sizeof(struct ext2_xattr_entry)) & ~EXT2_XATTR_ROUND)
67febcc5 98#endif
cca7148b
SP
99#define EXT2_XATTR_NEXT(entry) \
100 ( (struct ext2_xattr_entry *)( \
101 (char *)(entry) + EXT2_XATTR_LEN((entry)->e_name_len)) )
102#define EXT3_XATTR_SIZE(size) \
103 (((size) + EXT2_XATTR_ROUND) & ~EXT2_XATTR_ROUND)
104
105#define HDR(buffer) ((struct ext2_xattr_header *)(buffer))
106#define ENTRY(ptr) ((struct ext2_xattr_entry *)(ptr))
107#define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0)
108
109#define BFIRST(buffer) ENTRY(HDR(buffer)+1)
110#define IFIRST(buffer) ENTRY(((struct ext3_xattr_ibody_header *)(buffer))+1)
111
112#define FIRST_ENTRY(buffer) \
113 ((HDR(buffer)->h_magic == EXT2_XATTR_MAGIC2) ? \
114 IFIRST(buffer) : \
115 BFIRST(buffer))
116
117/*
118 * On-block xattr value offsets start at the beginning of the block, but
119 * on-inode xattr value offsets start after the initial header
120 * (ext3_xattr_ibody_header).
121 */
122#define VALUE_OFFSET(buffer, entry) \
123 (((HDR(buffer)->h_magic == EXT2_XATTR_MAGIC2) ? \
124 (entry)->e_value_offs + sizeof(struct ext3_xattr_ibody_header) : \
125 (entry)->e_value_offs))
126
127/*
128 * xattr syscalls do not exist yet in libc, get our own copy here,
129 * taken from libattr.
130 */
131#if defined (__i386__)
132# define HAVE_XATTR_SYSCALLS 1
133# define __NR_lsetxattr 227
134# define __NR_lgetxattr 230
135# define __NR_llistxattr 233
136#elif defined (__sparc__)
137# define HAVE_XATTR_SYSCALLS 1
138# define __NR_lsetxattr 170
139# define __NR_lgetxattr 173
140# define __NR_llistxattr 179
141#elif defined (__ia64__)
142# define HAVE_XATTR_SYSCALLS 1
143# define __NR_lsetxattr 1218
144# define __NR_lgetxattr 1221
145# define __NR_llistxattr 1224
146#elif defined (__powerpc__)
147# define HAVE_XATTR_SYSCALLS 1
148# define __NR_lsetxattr 210
149# define __NR_lgetxattr 213
150# define __NR_llistxattr 216
151#elif defined (__x86_64__)
152# define HAVE_XATTR_SYSCALLS 1
153# define __NR_lsetxattr 189
154# define __NR_lgetxattr 192
155# define __NR_llistxattr 195
156#elif defined (__s390__)
157# define HAVE_XATTR_SYSCALLS 1
158# define __NR_lsetxattr 225
159# define __NR_lgetxattr 228
160# define __NR_llistxattr 231
161#elif defined (__arm__)
162# define HAVE_XATTR_SYSCALLS 1
163# define __NR_SYSCALL_BASE 0x900000
164# define __NR_lsetxattr (__NR_SYSCALL_BASE+227)
165# define __NR_lgetxattr (__NR_SYSCALL_BASE+230)
166# define __NR_llistxattr (__NR_SYSCALL_BASE+233)
167#elif defined (__mips64__)
168# define HAVE_XATTR_SYSCALLS 1
169# define __NR_Linux 5000
170# define __NR_lsetxattr (__NR_Linux + 218)
171# define __NR_lgetxattr (__NR_Linux + 221)
172# define __NR_llistxattr (__NR_Linux + 224)
173#elif defined (__mips__)
174# define HAVE_XATTR_SYSCALLS 1
175# define __NR_Linux 4000
176# define __NR_lsetxattr (__NR_Linux + 225)
177# define __NR_lgetxattr (__NR_Linux + 228)
178# define __NR_llistxattr (__NR_Linux + 231)
179#elif defined (__alpha__)
180# define HAVE_XATTR_SYSCALLS 1
181# define __NR_lsetxattr 383
182# define __NR_lgetxattr 386
183# define __NR_llistxattr 389
184#elif defined (__mc68000__)
185# define HAVE_XATTR_SYSCALLS 1
186# define __NR_lsetxattr 224
187# define __NR_lgetxattr 227
188# define __NR_llistxattr 230
189#else
190# warning "Extended attribute syscalls undefined for this architecture"
191# define HAVE_XATTR_SYSCALLS 0
192#endif
193
194#if HAVE_XATTR_SYSCALLS
195# define SYSCALL(args...) syscall(args)
196#else
197# define SYSCALL(args...) ( errno = ENOSYS, -1 )
198#endif
199
200static int lsetxattr __P((const char *, const char *, void *, size_t, int));
201static ssize_t lgetxattr __P((const char *, const char *, void *, size_t));
202static ssize_t llistxattr __P((const char *, char *, size_t));
7f7d329e
SP
203static int xattr_cb_list __P((char *, char *, int, int, void *));
204static int xattr_cb_set __P((char *, char *, int, int, void *));
205static int xattr_cb_compare __P((char *, char *, int, int, void *));
cca7148b
SP
206static int xattr_verify __P((char *));
207static int xattr_count __P((char *, int *));
7f7d329e 208static int xattr_walk __P((char *, int (*)(char *, char *, int, int, void *), void *));
cca7148b
SP
209
210static int
211lsetxattr(const char *path, const char *name, void *value, size_t size, int flags)
212{
213 return SYSCALL(__NR_lsetxattr, path, name, value, size, flags);
214}
215
216static ssize_t
217lgetxattr(const char *path, const char *name, void *value, size_t size)
218{
219 return SYSCALL(__NR_lgetxattr, path, name, value, size);
220}
221
222static ssize_t
223llistxattr(const char *path, char *list, size_t size)
224{
225 return SYSCALL(__NR_llistxattr, path, list, size);
226}
227
b630baf0
SP
228#define POSIX_ACL_XATTR_VERSION 0x0002
229
230#define ACL_UNDEFINED_ID (-1)
231
232#define ACL_USER_OBJ (0x01)
233#define ACL_USER (0x02)
234#define ACL_GROUP_OBJ (0x04)
235#define ACL_GROUP (0x08)
236#define ACL_MASK (0x10)
237#define ACL_OTHER (0x20)
238
239typedef struct {
240 u_int16_t e_tag;
241 u_int16_t e_perm;
242 u_int32_t e_id;
243} posix_acl_xattr_entry;
244
245typedef struct {
246 u_int32_t a_version;
247 posix_acl_xattr_entry a_entries[0];
248} posix_acl_xattr_header;
249
250static inline size_t
251posix_acl_xattr_size(int count)
252{
253 return (sizeof(posix_acl_xattr_header) +
254 (count * sizeof(posix_acl_xattr_entry)));
255}
256
257struct posix_acl_entry {
258 short e_tag;
259 unsigned short e_perm;
260 unsigned int e_id;
261};
262
263struct posix_acl {
264 unsigned int a_count;
265 struct posix_acl_entry a_entries[0];
266};
267
268#define EXT3_ACL_VERSION 0x0001
269
270typedef struct {
271 u_int16_t e_tag;
272 u_int16_t e_perm;
273 u_int32_t e_id;
274} ext3_acl_entry;
275
276typedef struct {
277 u_int16_t e_tag;
278 u_int16_t e_perm;
279} ext3_acl_entry_short;
280
281typedef struct {
282 u_int32_t a_version;
283} ext3_acl_header;
284
285static inline int ext3_acl_count(size_t size)
286{
287 ssize_t s;
288 size -= sizeof(ext3_acl_header);
289 s = size - 4 * sizeof(ext3_acl_entry_short);
290 if (s < 0) {
291 if (size % sizeof(ext3_acl_entry_short))
292 return -1;
293 return size / sizeof(ext3_acl_entry_short);
294 } else {
295 if (s % sizeof(ext3_acl_entry))
296 return -1;
297 return s / sizeof(ext3_acl_entry) + 4;
298 }
299}
300
301int
302posix_acl_to_xattr(const struct posix_acl *acl, void *buffer, size_t size) {
303 posix_acl_xattr_header *ext_acl = (posix_acl_xattr_header *)buffer;
304 posix_acl_xattr_entry *ext_entry = ext_acl->a_entries;
305 int real_size, n;
306
307 real_size = posix_acl_xattr_size(acl->a_count);
308 if (!buffer)
309 return real_size;
310 if (real_size > size) {
67febcc5 311 fprintf(stderr, "ACL: not enough space to convert (%d %d)\n", real_size, (int)size);
b630baf0
SP
312 return -1;
313 }
314
315 ext_acl->a_version = POSIX_ACL_XATTR_VERSION;
cb6d3f79
SP
316#if BYTE_ORDER == BIG_ENDIAN
317 swabst("1i", (u_char *)ext_acl);
318#endif
b630baf0
SP
319
320 for (n=0; n < acl->a_count; n++, ext_entry++) {
321 ext_entry->e_tag = acl->a_entries[n].e_tag;
322 ext_entry->e_perm = acl->a_entries[n].e_perm;
323 ext_entry->e_id = acl->a_entries[n].e_id;
cb6d3f79
SP
324#if BYTE_ORDER == BIG_ENDIAN
325 swabst("2s1i", (u_char *)ext_entry);
326#endif
b630baf0
SP
327 }
328 return real_size;
329}
330
331static struct posix_acl *
332ext3_acl_from_disk(const void *value, size_t size)
333{
334 const char *end = (char *)value + size;
335 int n, count;
336 struct posix_acl *acl;
337
338 if (!value)
339 return NULL;
340 if (size < sizeof(ext3_acl_header)) {
341 fprintf(stderr, "ACL size too little\n");
342 return NULL;
343 }
cb6d3f79
SP
344#if BYTE_ORDER == BIG_ENDIAN
345 swabst("1i", (u_char *)value);
346#endif
b630baf0
SP
347 if (((ext3_acl_header *)value)->a_version != EXT3_ACL_VERSION) {
348 fprintf(stderr, "ACL version unknown\n");
349 return NULL;
350 }
351 value = (char *)value + sizeof(ext3_acl_header);
352 count = ext3_acl_count(size);
353 if (count < 0) {
354 fprintf(stderr, "ACL bad count\n");
355 return NULL;
356 }
357 if (count == 0)
358 return NULL;
359 acl = malloc(sizeof(struct posix_acl) + count * sizeof(struct posix_acl_entry));
360 if (!acl) {
361 fprintf(stderr, "ACL malloc failed\n");
362 return NULL;
363 }
364 acl->a_count = count;
365
366 for (n=0; n < count; n++) {
b630baf0 367 ext3_acl_entry *entry = (ext3_acl_entry *)value;
cb6d3f79
SP
368#if BYTE_ORDER == BIG_ENDIAN
369 swabst("2s", (u_char *)entry);
370#endif
b630baf0
SP
371 if ((char *)value + sizeof(ext3_acl_entry_short) > end)
372 goto fail;
373 acl->a_entries[n].e_tag = entry->e_tag;
374 acl->a_entries[n].e_perm = entry->e_perm;
375 switch(acl->a_entries[n].e_tag) {
376 case ACL_USER_OBJ:
377 case ACL_GROUP_OBJ:
378 case ACL_MASK:
379 case ACL_OTHER:
380 value = (char *)value + sizeof(ext3_acl_entry_short);
381 acl->a_entries[n].e_id = ACL_UNDEFINED_ID;
382 break;
383
384 case ACL_USER:
385 case ACL_GROUP:
cb6d3f79
SP
386#if BYTE_ORDER == BIG_ENDIAN
387 swabst("4b1i", (u_char *)entry);
388#endif
b630baf0
SP
389 value = (char *)value + sizeof(ext3_acl_entry);
390 if ((char *)value > end)
391 goto fail;
392 acl->a_entries[n].e_id = entry->e_id;
393 break;
394
395 default:
396 goto fail;
397 }
398 }
399 if (value != end)
400 goto fail;
401 return acl;
402
403fail:
404 fprintf(stderr, "ACL bad entry\n");
405 free(acl);
406 return NULL;
407}
408
cca7148b
SP
409/*
410 * Dump code starts here :)
411 */
412
413static int
7f7d329e 414xattr_cb_list(char *name, char *value, int valuelen, int isSELinux, void *private)
cca7148b 415{
7f7d329e 416 isSELinux;
cca7148b
SP
417 value[valuelen] = '\0';
418 printf("EA: %s:%s\n", name, value);
419
420 return GOOD;
421}
422
423static int
7f7d329e 424xattr_cb_set(char *name, char *value, int valuelen, int isSELinux, void *private)
cca7148b
SP
425{
426 char *path = (char *)private;
7f7d329e 427 int err;
15508d36
SP
428
429 if (Nflag)
430 return GOOD;
431
7f7d329e
SP
432 isSELinux;
433#ifdef TRANSSELINUX /*GAN6May06 SELinux MLS */
434 if (isSELinux)
435 err = lsetfilecon(path, value);
436 else
437#endif
438 err = lsetxattr(path, name, value, valuelen, 0);
439
440 if (err) {
441 warn("%s: EA set %s:%s failed", path, name, value);
cca7148b
SP
442 return FAIL;
443 }
7f7d329e 444
cca7148b
SP
445 return GOOD;
446}
447
448static int
7f7d329e 449xattr_cb_compare(char *name, char *value, int valuelen, int isSELinux, void *private)
cca7148b
SP
450{
451 char *path = (char *)private;
452 char valuef[XATTR_MAXSIZE];
453 int valuesz;
7f7d329e
SP
454
455 isSELinux;
456#ifdef TRANSSELINUX /*GAN6May06 SELinux MLS */
457 if (isSELinux)
458 {
459 security_context_t con = NULL;
460
461 if (lgetfilecon(path, &con) < 0) {
462 warn("%s: EA compare lgetfilecon failed\n", path);
463 return FAIL;
464 }
465
466 valuesz = strlen(con) + 1;
467 valuef[0] = 0;
67febcc5 468 strncat(valuef, con, sizeof(valuef) - 1);
7f7d329e 469 freecon(con);
cca7148b 470 }
7f7d329e
SP
471 else {
472#endif
473 valuesz = lgetxattr(path, name, valuef, XATTR_MAXSIZE);
474 if (valuesz < 0) {
475 warn("%s: EA compare lgetxattr failed\n", path);
476 return FAIL;
477 }
478#ifdef TRANSSELINUX /*GAN6May06 SELinux MLS */
cca7148b 479 }
7f7d329e
SP
480#endif
481
482 if (valuesz != valuelen || memcmp(value, valuef, valuelen)) {
483 /* GAN24May06: show name and new value for user to compare */
484 fprintf(stderr, "%s: EA %s:%s value changed to %s\n", path, name, value, valuef);
cca7148b
SP
485 return FAIL;
486 }
487
488 return GOOD;
489}
490
491static int
492xattr_verify(char *buffer)
493{
494 struct ext2_xattr_entry *entry;
495 char *end;
496
497 end = buffer + XATTR_MAXSIZE;
498
cb6d3f79
SP
499#if BYTE_ORDER == BIG_ENDIAN
500 swabst("4i", (u_char *)buffer);
501#endif
cca7148b
SP
502
503 if (HDR(buffer)->h_magic != EXT2_XATTR_MAGIC &&
504 HDR(buffer)->h_magic != EXT2_XATTR_MAGIC2) {
505 fprintf(stderr, "error in EA block 1\n");
506 fprintf(stderr, "magic = %x\n", HDR(buffer)->h_magic);
507
508 return FAIL;
509 }
510
511 /* check the on-disk data structure */
512 entry = FIRST_ENTRY(buffer);
cb6d3f79
SP
513#if BYTE_ORDER == BIG_ENDIAN
514 swabst("2b1s3i", (u_char *)entry);
515#endif
cca7148b
SP
516 while (!IS_LAST_ENTRY(entry)) {
517 struct ext2_xattr_entry *next = EXT2_XATTR_NEXT(entry);
518
519 if ((char *)next >= end) {
520 fprintf(stderr, "error in EA block\n");
521 return FAIL;
522 }
523 entry = next;
cb6d3f79
SP
524#if BYTE_ORDER == BIG_ENDIAN
525 swabst("2b1s3i", (u_char *)entry);
526#endif
cca7148b
SP
527 }
528 return GOOD;
529}
530
531static int
532xattr_count(char *buffer, int *count)
533{
534 struct ext2_xattr_entry *entry;
535 int result = 0;
536
537 /* list the attribute names */
538 for (entry = FIRST_ENTRY(buffer); !IS_LAST_ENTRY(entry);
539 entry = EXT2_XATTR_NEXT(entry))
540 result++;
541
542 *count = result;
543 return GOOD;
544}
545
546static int
7f7d329e 547xattr_walk(char *buffer, int (*xattr_cb)(char *, char *, int, int, void *), void *private)
cca7148b
SP
548{
549 struct ext2_xattr_entry *entry;
550
551 /* list the attribute names */
552 for (entry = FIRST_ENTRY(buffer); !IS_LAST_ENTRY(entry);
553 entry = EXT2_XATTR_NEXT(entry)) {
554 char name[XATTR_MAXSIZE], value[XATTR_MAXSIZE];
11997d3b 555 int size;
cca7148b 556 int off;
b630baf0 557 int convertacl = 0;
7f7d329e 558 int convertcon = 0;
cca7148b
SP
559
560 switch (entry->e_name_index) {
561 case EXT2_XATTR_INDEX_USER:
562 strcpy(name, "user.");
563 break;
564 case EXT2_XATTR_INDEX_POSIX_ACL_ACCESS:
b630baf0
SP
565 strcpy(name, "system.posix_acl_access");
566 convertacl = 1;
567 break;
cca7148b 568 case EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT:
b630baf0
SP
569 strcpy(name, "system.posix_acl_default");
570 convertacl = 1;
cca7148b
SP
571 break;
572 case EXT2_XATTR_INDEX_TRUSTED:
573 strcpy(name, "trusted.");
574 break;
575 case EXT2_XATTR_INDEX_LUSTRE:
576 strcpy(name, "lustre.");
577 break;
578 case EXT2_XATTR_INDEX_SECURITY:
579 strcpy(name, "security.");
7f7d329e
SP
580#ifdef TRANSSELINUX /*GAN6May06 SELinux MLS */
581 convertcon = transselinuxflag;
582#endif
cca7148b
SP
583 break;
584 default:
585 fprintf(stderr, "Unknown EA index\n");
586 return FAIL;
587 }
588
589 off = strlen(name);
590 memcpy(name + off, entry->e_name, entry->e_name_len);
591 name[off + entry->e_name_len] = '\0';
11997d3b 592 size = entry->e_value_size;
cca7148b 593
11997d3b 594 memcpy(value, buffer + VALUE_OFFSET(buffer, entry), size);
cca7148b 595
b630baf0
SP
596 if (convertacl) {
597 struct posix_acl *acl;
b630baf0 598
11997d3b 599 acl = ext3_acl_from_disk(value, size);
b630baf0
SP
600 if (!acl)
601 return FAIL;
602 size = posix_acl_to_xattr(acl, value, XATTR_MAXSIZE);
603 if (size < 0)
604 return FAIL;
b630baf0
SP
605 free(acl);
606 }
7f7d329e
SP
607
608#ifdef TRANSSELINUX /*GAN6May06 SELinux MLS */
609 if (convertcon && strcmp(name, "security.selinux"))
610 convertcon = 0; /*GAN24May06 only for selinux */
611
612 if (convertcon)
613 {
614 security_context_t con = NULL;
615 int err;
616
617 if (!transselinuxarg)
618 err = security_canonicalize_context(value, &con);
619 else {
67febcc5 620 strncat(value, transselinuxarg, sizeof(value) - 1);
7f7d329e
SP
621 err = security_canonicalize_context_raw(value, &con);
622 }
623
624 if (err < 0) {
625 warn("%s: EA canonicalize failed\n", value);
626 return FAIL;
627 }
628
11997d3b 629 size = strlen(con) + 1;
7f7d329e 630 value[0] = 0;
67febcc5 631 strncat(value, con, sizeof(value) - 1);
7f7d329e
SP
632 freecon(con);
633 }
634#endif
b630baf0 635
11997d3b 636 if (xattr_cb(name, value, size, convertcon, private) != GOOD)
cca7148b
SP
637 return FAIL;
638 }
639
640 return GOOD;
641}
642
643int
644xattr_compare(char *path, char *buffer)
645{
646 int countf, countt;
647 char *names = NULL, *end_names, *name;
648
649 countf = llistxattr(path, NULL, 0);
650 if (countf < 0) {
651 warn("%s: llistxattr failed", path);
652 return FAIL;
653 }
654
655 names = malloc(countf + 1);
656 if (!names) {
657 warn("%s: llistxattr failed", path);
658 return FAIL;
659 }
660
661 countf = llistxattr(path, names, countf);
662 if (countf < 0) {
663 warn("%s: llistxattr failed", path);
664 free(names);
665 return FAIL;
666 }
667
668 names[countf] = '\0';
669 end_names = names + countf;
670
671 countf = 0;
672 for (name = names; name != end_names; name = strchr(name, '\0') + 1) {
673 if (!*name)
674 continue;
675 countf++;
676 }
677
678 free(names);
679
680 if (buffer) {
681 if (xattr_verify(buffer) == FAIL)
682 return FAIL;
683
684 if (xattr_count(buffer, &countt) == FAIL)
685 return FAIL;
686 }
687 else
688 countt = 0;
689
690 if (countf != countt) {
691 fprintf(stderr, "%s: EA count changed from %d to %d\n", path, countt, countf);
692 return FAIL;
693 }
694
695 if (!buffer)
696 return GOOD;
697
698 return xattr_walk(buffer, xattr_cb_compare, path);
699}
700
701int
702xattr_extract(char *path, char *buffer)
703{
704 if (dflag) {
705 fprintf(stderr, "xattr_extract(%s)\n", path);
706 xattr_walk(buffer, xattr_cb_list, NULL);
707 }
708
709 if (xattr_verify(buffer) == FAIL)
710 return FAIL;
711
712 return xattr_walk(buffer, xattr_cb_set, path);
713}
714