2 * Copyright (c) 1999-2004
3 * Stelian Pop <stelian@popies.net>, 1999-2004
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
31 static const char rcsid
[] =
32 "$Id: xattr.c,v 1.7 2010/06/11 11:19:17 stelian Exp $";
36 #include <compatlfs.h>
37 #include <compaterr.h>
38 #include <sys/types.h>
44 #include <bsdcompat.h>
45 #include <protocols/dumprestore.h>
46 #ifdef TRANSSELINUX /*GAN6May06 SELinux MLS */
47 # include <selinux/selinux.h>
51 #include "pathnames.h"
54 * Data structures below taken from the kernel
57 /* Maximum number of references to one attribute block */
58 #define EXT2_XATTR_REFCOUNT_MAX 1024
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
69 struct 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 */
77 struct ext3_xattr_ibody_header
{
78 u_int32_t h_magic
; /* magic number for identification */
81 struct 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 */
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)
94 #ifndef EXT2_XATTR_LEN
95 #define EXT2_XATTR_LEN(name_len) \
96 (((name_len) + EXT2_XATTR_ROUND + \
97 sizeof(struct ext2_xattr_entry)) & ~EXT2_XATTR_ROUND)
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)
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)
109 #define BFIRST(buffer) ENTRY(HDR(buffer)+1)
110 #define IFIRST(buffer) ENTRY(((struct ext3_xattr_ibody_header *)(buffer))+1)
112 #define FIRST_ENTRY(buffer) \
113 ((HDR(buffer)->h_magic == EXT2_XATTR_MAGIC2) ? \
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).
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))
128 * xattr syscalls do not exist yet in libc, get our own copy here,
129 * taken from libattr.
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
190 # warning "Extended attribute syscalls undefined for this architecture"
191 # define HAVE_XATTR_SYSCALLS 0
194 #if HAVE_XATTR_SYSCALLS
195 # define SYSCALL(args...) syscall(args)
197 # define SYSCALL(args...) ( errno = ENOSYS, -1 )
200 static int lsetxattr
__P((const char *, const char *, void *, size_t, int));
201 static ssize_t lgetxattr
__P((const char *, const char *, void *, size_t));
202 static ssize_t llistxattr
__P((const char *, char *, size_t));
203 static int xattr_cb_list
__P((char *, char *, int, int, void *));
204 static int xattr_cb_set
__P((char *, char *, int, int, void *));
205 static int xattr_cb_compare
__P((char *, char *, int, int, void *));
206 static int xattr_verify
__P((char *));
207 static int xattr_count
__P((char *, int *));
208 static int xattr_walk
__P((char *, int (*)(char *, char *, int, int, void *), void *));
211 lsetxattr(const char *path
, const char *name
, void *value
, size_t size
, int flags
)
213 return SYSCALL(__NR_lsetxattr
, path
, name
, value
, size
, flags
);
217 lgetxattr(const char *path
, const char *name
, void *value
, size_t size
)
219 return SYSCALL(__NR_lgetxattr
, path
, name
, value
, size
);
223 llistxattr(const char *path
, char *list
, size_t size
)
225 return SYSCALL(__NR_llistxattr
, path
, list
, size
);
228 #define POSIX_ACL_XATTR_VERSION 0x0002
230 #define ACL_UNDEFINED_ID (-1)
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)
243 } posix_acl_xattr_entry
;
247 posix_acl_xattr_entry a_entries
[0];
248 } posix_acl_xattr_header
;
251 posix_acl_xattr_size(int count
)
253 return (sizeof(posix_acl_xattr_header
) +
254 (count
* sizeof(posix_acl_xattr_entry
)));
257 struct posix_acl_entry
{
259 unsigned short e_perm
;
264 unsigned int a_count
;
265 struct posix_acl_entry a_entries
[0];
268 #define EXT3_ACL_VERSION 0x0001
279 } ext3_acl_entry_short
;
285 static inline int ext3_acl_count(size_t size
)
288 size
-= sizeof(ext3_acl_header
);
289 s
= size
- 4 * sizeof(ext3_acl_entry_short
);
291 if (size
% sizeof(ext3_acl_entry_short
))
293 return size
/ sizeof(ext3_acl_entry_short
);
295 if (s
% sizeof(ext3_acl_entry
))
297 return s
/ sizeof(ext3_acl_entry
) + 4;
302 posix_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
;
307 real_size
= posix_acl_xattr_size(acl
->a_count
);
310 if (real_size
> size
) {
311 fprintf(stderr
, "ACL: not enough space to convert (%d %d)\n", real_size
, (int)size
);
315 ext_acl
->a_version
= POSIX_ACL_XATTR_VERSION
;
316 #if BYTE_ORDER == BIG_ENDIAN
317 swabst("1i", (u_char
*)ext_acl
);
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
;
324 #if BYTE_ORDER == BIG_ENDIAN
325 swabst("2s1i", (u_char
*)ext_entry
);
331 static struct posix_acl
*
332 ext3_acl_from_disk(const void *value
, size_t size
)
334 const char *end
= (char *)value
+ size
;
336 struct posix_acl
*acl
;
340 if (size
< sizeof(ext3_acl_header
)) {
341 fprintf(stderr
, "ACL size too little\n");
344 #if BYTE_ORDER == BIG_ENDIAN
345 swabst("1i", (u_char
*)value
);
347 if (((ext3_acl_header
*)value
)->a_version
!= EXT3_ACL_VERSION
) {
348 fprintf(stderr
, "ACL version unknown\n");
351 value
= (char *)value
+ sizeof(ext3_acl_header
);
352 count
= ext3_acl_count(size
);
354 fprintf(stderr
, "ACL bad count\n");
359 acl
= malloc(sizeof(struct posix_acl
) + count
* sizeof(struct posix_acl_entry
));
361 fprintf(stderr
, "ACL malloc failed\n");
364 acl
->a_count
= count
;
366 for (n
=0; n
< count
; n
++) {
367 ext3_acl_entry
*entry
= (ext3_acl_entry
*)value
;
368 #if BYTE_ORDER == BIG_ENDIAN
369 swabst("2s", (u_char
*)entry
);
371 if ((char *)value
+ sizeof(ext3_acl_entry_short
) > end
)
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
) {
380 value
= (char *)value
+ sizeof(ext3_acl_entry_short
);
381 acl
->a_entries
[n
].e_id
= ACL_UNDEFINED_ID
;
386 #if BYTE_ORDER == BIG_ENDIAN
387 swabst("4b1i", (u_char
*)entry
);
389 value
= (char *)value
+ sizeof(ext3_acl_entry
);
390 if ((char *)value
> end
)
392 acl
->a_entries
[n
].e_id
= entry
->e_id
;
404 fprintf(stderr
, "ACL bad entry\n");
410 * Dump code starts here :)
414 xattr_cb_list(char *name
, char *value
, int valuelen
, int isSELinux
, void *private)
417 value
[valuelen
] = '\0';
418 printf("EA: %s:%s\n", name
, value
);
424 xattr_cb_set(char *name
, char *value
, int valuelen
, int isSELinux
, void *private)
426 char *path
= (char *)private;
433 #ifdef TRANSSELINUX /*GAN6May06 SELinux MLS */
435 err
= lsetfilecon(path
, value
);
438 err
= lsetxattr(path
, name
, value
, valuelen
, 0);
441 warn("%s: EA set %s:%s failed", path
, name
, value
);
449 xattr_cb_compare(char *name
, char *value
, int valuelen
, int isSELinux
, void *private)
451 char *path
= (char *)private;
452 char valuef
[XATTR_MAXSIZE
];
456 #ifdef TRANSSELINUX /*GAN6May06 SELinux MLS */
459 security_context_t con
= NULL
;
461 if (lgetfilecon(path
, &con
) < 0) {
462 warn("%s: EA compare lgetfilecon failed\n", path
);
466 valuesz
= strlen(con
) + 1;
468 strncat(valuef
, con
, sizeof(valuef
) - 1);
473 valuesz
= lgetxattr(path
, name
, valuef
, XATTR_MAXSIZE
);
475 warn("%s: EA compare lgetxattr failed\n", path
);
478 #ifdef TRANSSELINUX /*GAN6May06 SELinux MLS */
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
);
492 xattr_verify(char *buffer
)
494 struct ext2_xattr_entry
*entry
;
497 end
= buffer
+ XATTR_MAXSIZE
;
499 #if BYTE_ORDER == BIG_ENDIAN
500 swabst("4i", (u_char
*)buffer
);
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
);
511 /* check the on-disk data structure */
512 entry
= FIRST_ENTRY(buffer
);
513 #if BYTE_ORDER == BIG_ENDIAN
514 swabst("2b1s3i", (u_char
*)entry
);
516 while (!IS_LAST_ENTRY(entry
)) {
517 struct ext2_xattr_entry
*next
= EXT2_XATTR_NEXT(entry
);
519 if ((char *)next
>= end
) {
520 fprintf(stderr
, "error in EA block\n");
524 #if BYTE_ORDER == BIG_ENDIAN
525 swabst("2b1s3i", (u_char
*)entry
);
532 xattr_count(char *buffer
, int *count
)
534 struct ext2_xattr_entry
*entry
;
537 /* list the attribute names */
538 for (entry
= FIRST_ENTRY(buffer
); !IS_LAST_ENTRY(entry
);
539 entry
= EXT2_XATTR_NEXT(entry
))
547 xattr_walk(char *buffer
, int (*xattr_cb
)(char *, char *, int, int, void *), void *private)
549 struct ext2_xattr_entry
*entry
;
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
];
560 switch (entry
->e_name_index
) {
561 case EXT2_XATTR_INDEX_USER
:
562 strcpy(name
, "user.");
564 case EXT2_XATTR_INDEX_POSIX_ACL_ACCESS
:
565 strcpy(name
, "system.posix_acl_access");
568 case EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT
:
569 strcpy(name
, "system.posix_acl_default");
572 case EXT2_XATTR_INDEX_TRUSTED
:
573 strcpy(name
, "trusted.");
575 case EXT2_XATTR_INDEX_LUSTRE
:
576 strcpy(name
, "lustre.");
578 case EXT2_XATTR_INDEX_SECURITY
:
579 strcpy(name
, "security.");
580 #ifdef TRANSSELINUX /*GAN6May06 SELinux MLS */
581 convertcon
= transselinuxflag
;
585 fprintf(stderr
, "Unknown EA index\n");
590 memcpy(name
+ off
, entry
->e_name
, entry
->e_name_len
);
591 name
[off
+ entry
->e_name_len
] = '\0';
592 size
= entry
->e_value_size
;
594 memcpy(value
, buffer
+ VALUE_OFFSET(buffer
, entry
), size
);
597 struct posix_acl
*acl
;
599 acl
= ext3_acl_from_disk(value
, size
);
602 size
= posix_acl_to_xattr(acl
, value
, XATTR_MAXSIZE
);
608 #ifdef TRANSSELINUX /*GAN6May06 SELinux MLS */
609 if (convertcon
&& strcmp(name
, "security.selinux"))
610 convertcon
= 0; /*GAN24May06 only for selinux */
614 security_context_t con
= NULL
;
617 if (!transselinuxarg
)
618 err
= security_canonicalize_context(value
, &con
);
620 strncat(value
, transselinuxarg
, sizeof(value
) - 1);
621 err
= security_canonicalize_context_raw(value
, &con
);
625 warn("%s: EA canonicalize failed\n", value
);
629 size
= strlen(con
) + 1;
631 strncat(value
, con
, sizeof(value
) - 1);
636 if (xattr_cb(name
, value
, size
, convertcon
, private) != GOOD
)
644 xattr_compare(char *path
, char *buffer
)
647 char *names
= NULL
, *end_names
, *name
;
649 countf
= llistxattr(path
, NULL
, 0);
651 warn("%s: llistxattr failed", path
);
655 names
= malloc(countf
+ 1);
657 warn("%s: llistxattr failed", path
);
661 countf
= llistxattr(path
, names
, countf
);
663 warn("%s: llistxattr failed", path
);
668 names
[countf
] = '\0';
669 end_names
= names
+ countf
;
672 for (name
= names
; name
!= end_names
; name
= strchr(name
, '\0') + 1) {
681 if (xattr_verify(buffer
) == FAIL
)
684 if (xattr_count(buffer
, &countt
) == FAIL
)
690 if (countf
!= countt
) {
691 fprintf(stderr
, "%s: EA count changed from %d to %d\n", path
, countt
, countf
);
698 return xattr_walk(buffer
, xattr_cb_compare
, path
);
702 xattr_extract(char *path
, char *buffer
)
705 fprintf(stderr
, "xattr_extract(%s)\n", path
);
706 xattr_walk(buffer
, xattr_cb_list
, NULL
);
709 if (xattr_verify(buffer
) == FAIL
)
712 return xattr_walk(buffer
, xattr_cb_set
, path
);