Imported Upstream version 0.4b41
[debian/dump] / restore / xattr.c
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
31 static const char rcsid[] =
32         "$Id: xattr.c,v 1.3 2005/06/08 13:24:12 stelian Exp $";
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>
46 #include "restore.h"
47 #include "extern.h"
48 #include "pathnames.h"
49
50 /*
51  * Data structures below taken from the kernel
52  */
53
54 /* Maximum number of references to one attribute block */
55 #define EXT2_XATTR_REFCOUNT_MAX         1024
56
57 /* Name indexes */
58 #define EXT2_XATTR_INDEX_MAX                    10
59 #define EXT2_XATTR_INDEX_USER                   1
60 #define EXT2_XATTR_INDEX_POSIX_ACL_ACCESS       2
61 #define EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT      3
62 #define EXT2_XATTR_INDEX_TRUSTED                4
63 #define EXT2_XATTR_INDEX_LUSTRE                 5
64 #define EXT2_XATTR_INDEX_SECURITY               6
65
66 struct ext2_xattr_header {
67         u_int32_t       h_magic;        /* magic number for identification */
68         u_int32_t       h_refcount;     /* reference count */
69         u_int32_t       h_blocks;       /* number of disk blocks used */
70         u_int32_t       h_hash;         /* hash value of all attributes */
71         u_int32_t       h_reserved[4];  /* zero right now */
72 };
73
74 struct ext3_xattr_ibody_header {
75         u_int32_t       h_magic;        /* magic number for identification */
76 };
77
78 struct ext2_xattr_entry {
79         u_char          e_name_len;     /* length of name */
80         u_char          e_name_index;   /* attribute name index */
81         u_int16_t       e_value_offs;   /* offset in disk block of value */
82         u_int32_t       e_value_block;  /* disk block attribute is stored on (n/i) */
83         u_int32_t       e_value_size;   /* size of attribute value */
84         u_int32_t       e_hash;         /* hash value of name and value */
85         char            e_name[0];      /* attribute name */
86 };
87
88 #define EXT2_XATTR_PAD_BITS             2
89 #define EXT2_XATTR_PAD          (1<<EXT2_XATTR_PAD_BITS)
90 #define EXT2_XATTR_ROUND                (EXT2_XATTR_PAD-1)
91 #define EXT2_XATTR_LEN(name_len) \
92         (((name_len) + EXT2_XATTR_ROUND + \
93         sizeof(struct ext2_xattr_entry)) & ~EXT2_XATTR_ROUND)
94 #define EXT2_XATTR_NEXT(entry) \
95         ( (struct ext2_xattr_entry *)( \
96           (char *)(entry) + EXT2_XATTR_LEN((entry)->e_name_len)) )
97 #define EXT3_XATTR_SIZE(size) \
98         (((size) + EXT2_XATTR_ROUND) & ~EXT2_XATTR_ROUND)
99
100 #define HDR(buffer) ((struct ext2_xattr_header *)(buffer))
101 #define ENTRY(ptr) ((struct ext2_xattr_entry *)(ptr))
102 #define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0)
103
104 #define BFIRST(buffer) ENTRY(HDR(buffer)+1)
105 #define IFIRST(buffer) ENTRY(((struct ext3_xattr_ibody_header *)(buffer))+1)
106
107 #define FIRST_ENTRY(buffer) \
108         ((HDR(buffer)->h_magic == EXT2_XATTR_MAGIC2) ? \
109                 IFIRST(buffer) : \
110                 BFIRST(buffer))
111
112 /*
113  * On-block xattr value offsets start at the beginning of the block, but
114  * on-inode xattr value offsets start after the initial header 
115  * (ext3_xattr_ibody_header).
116  */
117 #define VALUE_OFFSET(buffer, entry) \
118         (((HDR(buffer)->h_magic == EXT2_XATTR_MAGIC2) ? \
119                 (entry)->e_value_offs + sizeof(struct ext3_xattr_ibody_header) : \
120                 (entry)->e_value_offs))
121         
122 /*
123  * xattr syscalls do not exist yet in libc, get our own copy here,
124  * taken from libattr.
125  */
126 #if defined (__i386__)
127 # define HAVE_XATTR_SYSCALLS 1
128 # define __NR_lsetxattr         227
129 # define __NR_lgetxattr         230
130 # define __NR_llistxattr        233
131 #elif defined (__sparc__)
132 # define HAVE_XATTR_SYSCALLS 1
133 # define __NR_lsetxattr         170
134 # define __NR_lgetxattr         173
135 # define __NR_llistxattr        179
136 #elif defined (__ia64__)
137 # define HAVE_XATTR_SYSCALLS 1
138 # define __NR_lsetxattr         1218
139 # define __NR_lgetxattr         1221
140 # define __NR_llistxattr        1224
141 #elif defined (__powerpc__)
142 # define HAVE_XATTR_SYSCALLS 1
143 # define __NR_lsetxattr         210
144 # define __NR_lgetxattr         213
145 # define __NR_llistxattr        216
146 #elif defined (__x86_64__)
147 # define HAVE_XATTR_SYSCALLS 1
148 # define __NR_lsetxattr         189
149 # define __NR_lgetxattr         192
150 # define __NR_llistxattr        195
151 #elif defined (__s390__)
152 # define HAVE_XATTR_SYSCALLS 1
153 # define __NR_lsetxattr         225
154 # define __NR_lgetxattr         228
155 # define __NR_llistxattr        231
156 #elif defined (__arm__)
157 # define HAVE_XATTR_SYSCALLS 1
158 # define __NR_SYSCALL_BASE 0x900000
159 # define __NR_lsetxattr         (__NR_SYSCALL_BASE+227)
160 # define __NR_lgetxattr         (__NR_SYSCALL_BASE+230)
161 # define __NR_llistxattr        (__NR_SYSCALL_BASE+233)
162 #elif defined (__mips64__)
163 # define HAVE_XATTR_SYSCALLS 1
164 # define __NR_Linux 5000
165 # define __NR_lsetxattr         (__NR_Linux + 218)
166 # define __NR_lgetxattr         (__NR_Linux + 221)
167 # define __NR_llistxattr        (__NR_Linux + 224)
168 #elif defined (__mips__)
169 # define HAVE_XATTR_SYSCALLS 1
170 # define __NR_Linux 4000
171 # define __NR_lsetxattr         (__NR_Linux + 225)
172 # define __NR_lgetxattr         (__NR_Linux + 228)
173 # define __NR_llistxattr        (__NR_Linux + 231)
174 #elif defined (__alpha__)
175 # define HAVE_XATTR_SYSCALLS 1
176 # define __NR_lsetxattr         383
177 # define __NR_lgetxattr         386
178 # define __NR_llistxattr        389
179 #elif defined (__mc68000__)
180 # define HAVE_XATTR_SYSCALLS 1
181 # define __NR_lsetxattr         224
182 # define __NR_lgetxattr         227
183 # define __NR_llistxattr        230
184 #else
185 # warning "Extended attribute syscalls undefined for this architecture"
186 # define HAVE_XATTR_SYSCALLS 0
187 #endif
188
189 #if HAVE_XATTR_SYSCALLS
190 # define SYSCALL(args...)       syscall(args)
191 #else
192 # define SYSCALL(args...)       ( errno = ENOSYS, -1 )
193 #endif
194
195 static int lsetxattr __P((const char *, const char *, void *, size_t, int));
196 static ssize_t lgetxattr __P((const char *, const char *, void *, size_t));
197 static ssize_t llistxattr __P((const char *, char *, size_t));
198 static int xattr_cb_list __P((char *, char *, int, void *));
199 static int xattr_cb_set __P((char *, char *, int, void *));
200 static int xattr_cb_compare __P((char *, char *, int, void *));
201 static int xattr_verify __P((char *));
202 static int xattr_count __P((char *, int *));
203 static int xattr_walk __P((char *, int (*)(char *, char *, int, void *), void *));
204
205 static int
206 lsetxattr(const char *path, const char *name, void *value, size_t size, int flags)
207 {
208         return SYSCALL(__NR_lsetxattr, path, name, value, size, flags);
209 }
210
211 static ssize_t
212 lgetxattr(const char *path, const char *name, void *value, size_t size)
213 {
214         return SYSCALL(__NR_lgetxattr, path, name, value, size);
215 }
216
217 static ssize_t
218 llistxattr(const char *path, char *list, size_t size)
219 {
220         return SYSCALL(__NR_llistxattr, path, list, size);
221 }
222
223 #define POSIX_ACL_XATTR_VERSION 0x0002
224
225 #define ACL_UNDEFINED_ID        (-1)
226
227 #define ACL_USER_OBJ            (0x01)
228 #define ACL_USER                (0x02)
229 #define ACL_GROUP_OBJ           (0x04)
230 #define ACL_GROUP               (0x08)
231 #define ACL_MASK                (0x10)
232 #define ACL_OTHER               (0x20)
233
234 typedef struct {
235         u_int16_t       e_tag;
236         u_int16_t       e_perm;
237         u_int32_t       e_id;
238 } posix_acl_xattr_entry;
239
240 typedef struct {
241         u_int32_t               a_version;
242         posix_acl_xattr_entry   a_entries[0];
243 } posix_acl_xattr_header;
244
245 static inline size_t
246 posix_acl_xattr_size(int count)
247 {
248         return (sizeof(posix_acl_xattr_header) +
249                 (count * sizeof(posix_acl_xattr_entry)));
250 }
251
252 struct posix_acl_entry {
253         short           e_tag;
254         unsigned short  e_perm;
255         unsigned int    e_id;
256 };
257
258 struct posix_acl {
259         unsigned int            a_count;
260         struct posix_acl_entry  a_entries[0];
261 };
262
263 #define EXT3_ACL_VERSION        0x0001
264
265 typedef struct {
266         u_int16_t       e_tag;
267         u_int16_t       e_perm;
268         u_int32_t       e_id;
269 } ext3_acl_entry;
270
271 typedef struct {
272         u_int16_t       e_tag;
273         u_int16_t       e_perm;
274 } ext3_acl_entry_short;
275
276 typedef struct {
277         u_int32_t       a_version;
278 } ext3_acl_header;
279
280 static inline int ext3_acl_count(size_t size)
281 {
282         ssize_t s;
283         size -= sizeof(ext3_acl_header);
284         s = size - 4 * sizeof(ext3_acl_entry_short);
285         if (s < 0) {
286                 if (size % sizeof(ext3_acl_entry_short))
287                         return -1;
288                 return size / sizeof(ext3_acl_entry_short);
289         } else {
290                 if (s % sizeof(ext3_acl_entry))
291                         return -1;
292                 return s / sizeof(ext3_acl_entry) + 4;
293         }
294 }
295
296 int
297 posix_acl_to_xattr(const struct posix_acl *acl, void *buffer, size_t size) {
298         posix_acl_xattr_header *ext_acl = (posix_acl_xattr_header *)buffer;
299         posix_acl_xattr_entry *ext_entry = ext_acl->a_entries;
300         int real_size, n;
301
302         real_size = posix_acl_xattr_size(acl->a_count);
303         if (!buffer)
304                 return real_size;
305         if (real_size > size) {
306                 fprintf(stderr, "ACL: not enough space to convert (%d %d)\n", real_size, size);
307                 return -1;
308         }
309
310         ext_acl->a_version = POSIX_ACL_XATTR_VERSION;
311 #if BYTE_ORDER == BIG_ENDIAN
312         swabst("1i", (u_char *)ext_acl);
313 #endif
314
315         for (n=0; n < acl->a_count; n++, ext_entry++) {
316                 ext_entry->e_tag  = acl->a_entries[n].e_tag;
317                 ext_entry->e_perm = acl->a_entries[n].e_perm;
318                 ext_entry->e_id   = acl->a_entries[n].e_id;
319 #if BYTE_ORDER == BIG_ENDIAN
320                 swabst("2s1i", (u_char *)ext_entry);
321 #endif
322         }
323         return real_size;
324 }
325
326 static struct posix_acl *
327 ext3_acl_from_disk(const void *value, size_t size)
328 {
329         const char *end = (char *)value + size;
330         int n, count;
331         struct posix_acl *acl;
332
333         if (!value)
334                 return NULL;
335         if (size < sizeof(ext3_acl_header)) {
336                 fprintf(stderr, "ACL size too little\n");
337                 return NULL;
338         }
339 #if BYTE_ORDER == BIG_ENDIAN
340         swabst("1i", (u_char *)value);
341 #endif
342         if (((ext3_acl_header *)value)->a_version != EXT3_ACL_VERSION) {
343                 fprintf(stderr, "ACL version unknown\n");
344                 return NULL;
345         }
346         value = (char *)value + sizeof(ext3_acl_header);
347         count = ext3_acl_count(size);
348         if (count < 0) {
349                 fprintf(stderr, "ACL bad count\n");
350                 return NULL;
351         }
352         if (count == 0)
353                 return NULL;
354         acl = malloc(sizeof(struct posix_acl) + count * sizeof(struct posix_acl_entry));
355         if (!acl) {
356                 fprintf(stderr, "ACL malloc failed\n");
357                 return NULL;
358         }
359         acl->a_count = count;
360
361         for (n=0; n < count; n++) {
362                 ext3_acl_entry *entry = (ext3_acl_entry *)value;
363 #if BYTE_ORDER == BIG_ENDIAN
364                 swabst("2s", (u_char *)entry);
365 #endif
366                 if ((char *)value + sizeof(ext3_acl_entry_short) > end)
367                         goto fail;
368                 acl->a_entries[n].e_tag  = entry->e_tag;
369                 acl->a_entries[n].e_perm = entry->e_perm;
370                 switch(acl->a_entries[n].e_tag) {
371                 case ACL_USER_OBJ:
372                 case ACL_GROUP_OBJ:
373                 case ACL_MASK:
374                 case ACL_OTHER:
375                         value = (char *)value + sizeof(ext3_acl_entry_short);
376                         acl->a_entries[n].e_id = ACL_UNDEFINED_ID;
377                         break;
378
379                 case ACL_USER:
380                 case ACL_GROUP:
381 #if BYTE_ORDER == BIG_ENDIAN
382                         swabst("4b1i", (u_char *)entry);
383 #endif
384                         value = (char *)value + sizeof(ext3_acl_entry);
385                         if ((char *)value > end)
386                                 goto fail;
387                         acl->a_entries[n].e_id = entry->e_id;
388                         break;
389
390                 default:
391                         goto fail;
392                 }
393         }
394         if (value != end)
395                 goto fail;
396         return acl;
397
398 fail:
399         fprintf(stderr, "ACL bad entry\n");
400         free(acl);
401         return NULL;
402 }
403
404 /*
405  * Dump code starts here :)
406  */
407
408 static int
409 xattr_cb_list(char *name, char *value, int valuelen, void *private)
410 {
411         value[valuelen] = '\0';
412         printf("EA: %s:%s\n", name, value);
413
414         return GOOD;
415 }
416
417 static int
418 xattr_cb_set(char *name, char *value, int valuelen, void *private)
419 {
420         char *path = (char *)private;
421
422         if (lsetxattr(path, name, value, valuelen, 0) < 0) {
423                 warn("lsetxattr %s failed", path);
424                 return FAIL;
425         }
426         return GOOD;
427 }
428
429 static int
430 xattr_cb_compare(char *name, char *value, int valuelen, void *private)
431 {
432         char *path = (char *)private;
433         char valuef[XATTR_MAXSIZE];
434         int valuesz;
435
436         valuesz = lgetxattr(path, name, valuef, XATTR_MAXSIZE);
437         if (valuesz < 0) {
438                 warn("%s: lgetxattr failed\n", path);
439                 return FAIL;
440         }
441
442         if (valuesz != valuelen) {
443                 fprintf(stderr, "%s: EA %s value changed\n", path, value);
444                 return FAIL;
445         }
446
447         if (memcmp(value, valuef, valuelen)) {
448                 fprintf(stderr, "%s: EA %s value changed\n", path, value);
449                 return FAIL;
450         }
451
452         return GOOD;
453 }
454
455 static int
456 xattr_verify(char *buffer)
457 {
458         struct ext2_xattr_entry *entry;
459         char *end;
460
461         end = buffer + XATTR_MAXSIZE;
462
463 #if BYTE_ORDER == BIG_ENDIAN
464         swabst("4i", (u_char *)buffer);
465 #endif
466
467         if (HDR(buffer)->h_magic != EXT2_XATTR_MAGIC &&
468             HDR(buffer)->h_magic != EXT2_XATTR_MAGIC2) {
469                 fprintf(stderr, "error in EA block 1\n");
470                 fprintf(stderr, "magic = %x\n", HDR(buffer)->h_magic);
471                 
472                 return FAIL;
473         }
474
475         /* check the on-disk data structure */
476         entry = FIRST_ENTRY(buffer);
477 #if BYTE_ORDER == BIG_ENDIAN
478         swabst("2b1s3i", (u_char *)entry);
479 #endif
480         while (!IS_LAST_ENTRY(entry)) {
481                 struct ext2_xattr_entry *next = EXT2_XATTR_NEXT(entry);
482
483                 if ((char *)next >= end) {
484                         fprintf(stderr, "error in EA block\n");
485                         return FAIL;
486                 }
487                 entry = next;
488 #if BYTE_ORDER == BIG_ENDIAN
489                 swabst("2b1s3i", (u_char *)entry);
490 #endif
491         }
492         return GOOD;
493 }
494
495 static int
496 xattr_count(char *buffer, int *count)
497 {
498         struct ext2_xattr_entry *entry;
499         int result = 0;
500
501         /* list the attribute names */
502         for (entry = FIRST_ENTRY(buffer); !IS_LAST_ENTRY(entry);
503              entry = EXT2_XATTR_NEXT(entry))
504                 result++;
505
506         *count = result;
507         return GOOD;
508 }
509
510 static int
511 xattr_walk(char *buffer, int (*xattr_cb)(char *, char *, int, void *), void *private)
512 {
513         struct ext2_xattr_entry *entry;
514
515         /* list the attribute names */
516         for (entry = FIRST_ENTRY(buffer); !IS_LAST_ENTRY(entry);
517              entry = EXT2_XATTR_NEXT(entry)) {
518                 char name[XATTR_MAXSIZE], value[XATTR_MAXSIZE];
519                 int off;
520                 int convertacl = 0;
521
522                 switch (entry->e_name_index) {
523                 case EXT2_XATTR_INDEX_USER:
524                         strcpy(name, "user.");
525                         break;
526                 case EXT2_XATTR_INDEX_POSIX_ACL_ACCESS:
527                         strcpy(name, "system.posix_acl_access");
528                         convertacl = 1;
529                         break;
530                 case EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT:
531                         strcpy(name, "system.posix_acl_default");
532                         convertacl = 1;
533                         break;
534                 case EXT2_XATTR_INDEX_TRUSTED:
535                         strcpy(name, "trusted.");
536                         break;
537                 case EXT2_XATTR_INDEX_LUSTRE:
538                         strcpy(name, "lustre.");
539                         break;
540                 case EXT2_XATTR_INDEX_SECURITY:
541                         strcpy(name, "security.");
542                         break;
543                 default:
544                         fprintf(stderr, "Unknown EA index\n");
545                         return FAIL;
546                 }
547
548                 off = strlen(name);
549                 memcpy(name + off, entry->e_name, entry->e_name_len);
550                 name[off + entry->e_name_len] = '\0';
551
552                 memcpy(value, buffer + VALUE_OFFSET(buffer, entry), entry->e_value_size);
553
554                 if (convertacl) {
555                         struct posix_acl *acl;
556                         int size;
557
558                         acl = ext3_acl_from_disk(value, entry->e_value_size);
559                         if (!acl)
560                                 return FAIL;
561                         size = posix_acl_to_xattr(acl, value, XATTR_MAXSIZE);
562                         if (size < 0)
563                                 return FAIL;
564                         entry->e_value_size = size;
565                         free(acl);
566                 }
567
568                 if (xattr_cb(name, value, entry->e_value_size, private) != GOOD)
569                         return FAIL;
570         }
571
572         return GOOD;
573 }
574
575 int
576 xattr_compare(char *path, char *buffer)
577 {
578         int countf, countt;
579         char *names = NULL, *end_names, *name;
580
581         countf = llistxattr(path, NULL, 0);
582         if (countf < 0) {
583                 warn("%s: llistxattr failed", path);
584                 return FAIL;
585         }
586
587         names = malloc(countf + 1);
588         if (!names) {
589                 warn("%s: llistxattr failed", path);
590                 return FAIL;
591         }
592
593         countf = llistxattr(path, names, countf);
594         if (countf < 0) {
595                 warn("%s: llistxattr failed", path);
596                 free(names);
597                 return FAIL;
598         }
599
600         names[countf] = '\0';
601         end_names = names + countf;
602
603         countf = 0;
604         for (name = names; name != end_names; name = strchr(name, '\0') + 1) {
605                 if (!*name)
606                         continue;
607                 countf++;
608         }
609
610         free(names);
611
612         if (buffer) {
613                 if (xattr_verify(buffer) == FAIL)
614                         return FAIL;
615
616                 if (xattr_count(buffer, &countt) == FAIL)
617                         return FAIL;
618         }
619         else
620                 countt = 0;
621
622         if (countf != countt) {
623                 fprintf(stderr, "%s: EA count changed from %d to %d\n", path, countt, countf);
624                 return FAIL;
625         }
626
627         if (!buffer)
628                 return GOOD;
629
630         return xattr_walk(buffer, xattr_cb_compare, path);
631 }
632
633 int
634 xattr_extract(char *path, char *buffer)
635 {
636         if (dflag) {
637                 fprintf(stderr, "xattr_extract(%s)\n", path);
638                 xattr_walk(buffer, xattr_cb_list, NULL);
639         }
640
641         if (xattr_verify(buffer) == FAIL)
642                 return FAIL;
643
644         return xattr_walk(buffer, xattr_cb_set, path);
645 }
646