1 /*
2 Unix SMB/CIFS implementation.
3 Samba system utilities
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jeremy Allison 1998-2005
6 Copyright (C) Timur Bakeyev 2005
7 Copyright (C) Bjoern Jacke 2006-2007
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22
23 sys_copyxattr modified from LGPL2.1 libattr copyright
24 Copyright (C) 2001-2002 Silicon Graphics, Inc. All Rights Reserved.
25 Copyright (C) 2001 Andreas Gruenbacher.
26
27 Samba 3.0.28, modified for netatalk.
28 */
29
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/types.h>
37 #include <errno.h>
38
39 #if HAVE_ATTR_XATTR_H
40 #include <attr/xattr.h>
41 #elif HAVE_SYS_XATTR_H
42 #include <sys/xattr.h>
43 #endif
44
45 #ifdef HAVE_SYS_EA_H
46 #include <sys/ea.h>
47 #endif
48
49 #ifdef HAVE_ATTROPEN
50
51 #include <dirent.h>
52 #endif
53
54 #ifdef HAVE_SYS_EXTATTR_H
55 #include <sys/extattr.h>
56 #endif
57
58 #include <atalk/adouble.h>
59 #include <atalk/util.h>
60 #include <atalk/logger.h>
61 #include <atalk/ea.h>
62 #include <atalk/compat.h>
63 #include <atalk/errchk.h>
64
65 /******** Solaris EA helper function prototypes ********/
66 #ifdef HAVE_ATTROPEN
67 #define SOLARIS_ATTRMODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH
68 static int solaris_write_xattr(int attrfd, const char *value, size_t size);
69 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size);
70 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size);
71 static int solaris_unlinkat(int attrdirfd, const char *name);
72 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode);
73 static int solaris_attropenat(int filedes, const char *path, const char *attrpath, int oflag, mode_t mode);
74 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode);
75 #endif
76
77 /**************************************************************************
78 Wrappers for extented attribute calls. Based on the Linux package with
79 support for IRIX and (Net|Free)BSD also. Expand as other systems have them.
80 ****************************************************************************/
81 static char attr_name[256 +5] = "user.";
82
prefix(const char * uname)83 static const char *prefix(const char *uname)
84 {
85 #if defined(HAVE_ATTROPEN)
86 return uname;
87 #else
88 strlcpy(attr_name +5, uname, 256);
89 return attr_name;
90 #endif
91 }
92
sys_getxattrfd(int fd,const char * uname,int oflag,...)93 int sys_getxattrfd(int fd, const char *uname, int oflag, ...)
94 {
95 #if defined HAVE_ATTROPEN
96 int eafd;
97 va_list args;
98 mode_t mode = 0;
99
100 if (oflag & O_CREAT) {
101 va_start(args, oflag);
102 mode = va_arg(args, mode_t);
103 va_end(args);
104 }
105
106 if (oflag & O_CREAT)
107 eafd = solaris_openat(fd, uname, oflag | O_XATTR, mode);
108 else
109 eafd = solaris_openat(fd, uname, oflag | O_XATTR, mode);
110
111 return eafd;
112 #else
113 errno = ENOSYS;
114 return -1;
115 #endif
116 }
117
sys_getxattr(const char * path,const char * uname,void * value,size_t size)118 ssize_t sys_getxattr (const char *path, const char *uname, void *value, size_t size)
119 {
120 const char *name = prefix(uname);
121
122 #if defined(HAVE_GETXATTR)
123 #ifndef XATTR_ADD_OPT
124 return getxattr(path, name, value, size);
125 #else
126 int options = 0;
127 return getxattr(path, name, value, size, 0, options);
128 #endif
129 #elif defined(HAVE_GETEA)
130 return getea(path, name, value, size);
131 #elif defined(HAVE_EXTATTR_GET_FILE)
132 ssize_t retval;
133 /*
134 * The BSD implementation has a nasty habit of silently truncating
135 * the returned value to the size of the buffer, so we have to check
136 * that the buffer is large enough to fit the returned value.
137 */
138 if((retval = extattr_get_file(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0)) >= 0) {
139 if (size == 0)
140 /* size == 0 means only return size */
141 return retval;
142 if (retval > size) {
143 errno = ERANGE;
144 return -1;
145 }
146 if ((retval = extattr_get_file(path, EXTATTR_NAMESPACE_USER, uname, value, size)) >= 0)
147 return retval;
148 }
149
150 LOG(log_maxdebug, logtype_default, "sys_getxattr: extattr_get_file() failed with: %s\n", strerror(errno));
151 return -1;
152 #elif defined(HAVE_ATTR_GET)
153 int retval, flags = 0;
154 int valuelength = (int)size;
155 char *attrname = strchr(name,'.') + 1;
156
157 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
158
159 retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
160
161 return retval ? retval : valuelength;
162 #elif defined(HAVE_ATTROPEN)
163 ssize_t ret = -1;
164 int attrfd = solaris_attropen(path, name, O_RDONLY, 0);
165 if (attrfd >= 0) {
166 ret = solaris_read_xattr(attrfd, value, size);
167 close(attrfd);
168 }
169 return ret;
170 #else
171 errno = ENOSYS;
172 return -1;
173 #endif
174 }
175
sys_fgetxattr(int filedes,const char * uname,void * value,size_t size)176 ssize_t sys_fgetxattr (int filedes, const char *uname, void *value, size_t size)
177 {
178 const char *name = prefix(uname);
179
180 #if defined(HAVE_FGETXATTR)
181 #ifndef XATTR_ADD_OPT
182 return fgetxattr(filedes, name, value, size);
183 #else
184 int options = 0;
185 return fgetxattr(filedes, name, value, size, 0, options);
186 #endif
187 #elif defined(HAVE_FGETEA)
188 return fgetea(filedes, name, value, size);
189 #elif defined(HAVE_EXTATTR_GET_FD)
190 char *s;
191 ssize_t retval;
192 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
193 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
194 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
195
196 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) {
197 if (size == 0) {
198 /* size == 0 means only return size */
199 return retval;
200 }
201 if(retval > size) {
202 errno = ERANGE;
203 return -1;
204 }
205 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0)
206 return retval;
207 }
208
209 LOG(log_debug, logtype_default, "sys_fgetxattr: extattr_get_fd(): %s", strerror(errno));
210 return -1;
211 #elif defined(HAVE_ATTR_GETF)
212 int retval, flags = 0;
213 int valuelength = (int)size;
214 char *attrname = strchr(name,'.') + 1;
215
216 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
217
218 retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags);
219
220 return retval ? retval : valuelength;
221 #elif defined(HAVE_ATTROPEN)
222 ssize_t ret = -1;
223 int attrfd = solaris_openat(filedes, name, O_RDONLY|O_XATTR, 0);
224 if (attrfd >= 0) {
225 ret = solaris_read_xattr(attrfd, value, size);
226 close(attrfd);
227 }
228 return ret;
229 #else
230 errno = ENOSYS;
231 return -1;
232 #endif
233 }
234
sys_lgetxattr(const char * path,const char * uname,void * value,size_t size)235 ssize_t sys_lgetxattr (const char *path, const char *uname, void *value, size_t size)
236 {
237 const char *name = prefix(uname);
238
239 #if defined(HAVE_LGETXATTR)
240 return lgetxattr(path, name, value, size);
241 #elif defined(HAVE_GETXATTR) && defined(XATTR_ADD_OPT)
242 int options = XATTR_NOFOLLOW;
243 return getxattr(path, name, value, size, 0, options);
244 #elif defined(HAVE_LGETEA)
245 return lgetea(path, name, value, size);
246 #elif defined(HAVE_EXTATTR_GET_LINK)
247 ssize_t retval;
248
249 retval = extattr_get_link(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0);
250 if (retval == -1) {
251 LOG(log_maxdebug, logtype_default, "extattr_get_link(): %s",
252 strerror(errno));
253 return -1;
254 }
255 if (size == 0)
256 /* Only interested in size of xattr */
257 return retval;
258 if (retval > size) {
259 errno = ERANGE;
260 return -1;
261 }
262 return extattr_get_link(path, EXTATTR_NAMESPACE_USER, uname, value, size);
263
264 #elif defined(HAVE_ATTR_GET)
265 int retval, flags = ATTR_DONTFOLLOW;
266 int valuelength = (int)size;
267 char *attrname = strchr(name,'.') + 1;
268
269 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
270
271 retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
272
273 return retval ? retval : valuelength;
274 #elif defined(HAVE_ATTROPEN)
275 ssize_t ret = -1;
276 int attrfd = solaris_attropen(path, name, O_RDONLY | O_NOFOLLOW, 0);
277 if (attrfd >= 0) {
278 ret = solaris_read_xattr(attrfd, value, size);
279 close(attrfd);
280 }
281 return ret;
282 #else
283 errno = ENOSYS;
284 return -1;
285 #endif
286 }
287
288 #if defined(HAVE_EXTATTR_LIST_FILE)
289
290 #define EXTATTR_PREFIX(s) (s), (sizeof((s))-1)
291
292 static struct {
293 int space;
294 const char *name;
295 size_t len;
296 }
297 extattr[] = {
298 { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("") },
299 { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("") },
300 };
301
302 typedef union {
303 const char *path;
304 int filedes;
305 } extattr_arg;
306
bsd_attr_list(int type,extattr_arg arg,char * list,size_t size)307 static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
308 {
309 ssize_t list_size;
310 int i, len;
311
312 switch(type) {
313 #if defined(HAVE_EXTATTR_LIST_FILE)
314 case 0:
315 list_size = extattr_list_file(arg.path, EXTATTR_NAMESPACE_USER, list, size);
316 break;
317 #endif
318 #if defined(HAVE_EXTATTR_LIST_LINK)
319 case 1:
320 list_size = extattr_list_link(arg.path, EXTATTR_NAMESPACE_USER, list, size);
321 break;
322 #endif
323 #if defined(HAVE_EXTATTR_LIST_FD)
324 case 2:
325 list_size = extattr_list_fd(arg.filedes, EXTATTR_NAMESPACE_USER, list, size);
326 break;
327 #endif
328 default:
329 errno = ENOSYS;
330 return -1;
331 }
332
333 /* Some error happend. Errno should be set by the previous call */
334 if(list_size < 0)
335 return -1;
336
337 /* No attributes */
338 if(list_size == 0)
339 return 0;
340
341 /* XXX: Call with an empty buffer may be used to calculate
342 necessary buffer size. Unfortunately, we can't say, how
343 many attributes were returned, so here is the potential
344 problem with the emulation.
345 */
346 if(list == NULL)
347 return list_size;
348
349 /* Buffer is too small to fit the results */
350 if(list_size > size) {
351 errno = ERANGE;
352 return -1;
353 }
354
355 /* Convert from pascal strings to C strings */
356 len = (unsigned char)list[0];
357 memmove(list, list + 1, list_size - 1);
358
359 for(i = len; i < list_size; ) {
360 LOG(log_maxdebug, logtype_afpd, "len: %d, i: %d", len, i);
361
362 len = (unsigned char)list[i];
363 list[i] = '\0';
364 i += len + 1;
365 }
366
367 return list_size;
368 }
369
370 #endif
371
372 #if defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
373 static char attr_buffer[ATTR_MAX_VALUELEN];
374
irix_attr_list(const char * path,int filedes,char * list,size_t size,int flags)375 static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
376 {
377 int retval = 0, index;
378 attrlist_cursor_t *cursor = 0;
379 int total_size = 0;
380 attrlist_t * al = (attrlist_t *)attr_buffer;
381 attrlist_ent_t *ae;
382 size_t ent_size, left = size;
383 char *bp = list;
384
385 while (True) {
386 if (filedes)
387 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
388 else
389 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
390 if (retval) break;
391 for (index = 0; index < al->al_count; index++) {
392 ae = ATTR_ENTRY(attr_buffer, index);
393 ent_size = strlen(ae->a_name) + sizeof("user.");
394 if (left >= ent_size) {
395 strncpy(bp, "user.", sizeof("user."));
396 strncat(bp, ae->a_name, ent_size - sizeof("user."));
397 bp += ent_size;
398 left -= ent_size;
399 } else if (size) {
400 errno = ERANGE;
401 retval = -1;
402 break;
403 }
404 total_size += ent_size;
405 }
406 if (al->al_more == 0) break;
407 }
408 if (retval == 0) {
409 flags |= ATTR_ROOT;
410 cursor = 0;
411 while (True) {
412 if (filedes)
413 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
414 else
415 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
416 if (retval) break;
417 for (index = 0; index < al->al_count; index++) {
418 ae = ATTR_ENTRY(attr_buffer, index);
419 ent_size = strlen(ae->a_name) + sizeof("system.");
420 if (left >= ent_size) {
421 strncpy(bp, "system.", sizeof("system."));
422 strncat(bp, ae->a_name, ent_size - sizeof("system."));
423 bp += ent_size;
424 left -= ent_size;
425 } else if (size) {
426 errno = ERANGE;
427 retval = -1;
428 break;
429 }
430 total_size += ent_size;
431 }
432 if (al->al_more == 0) break;
433 }
434 }
435 return (ssize_t)(retval ? retval : total_size);
436 }
437
438 #endif
439
440 #if defined(HAVE_LISTXATTR)
remove_user(ssize_t ret,char * list,size_t size)441 static ssize_t remove_user(ssize_t ret, char *list, size_t size)
442 {
443 size_t len;
444 char *ptr;
445 char *ptr1;
446 ssize_t ptrsize;
447
448 if (ret <= 0 || size == 0)
449 return ret;
450 ptrsize = ret;
451 ptr = ptr1 = list;
452 while (ptrsize > 0) {
453 len = strlen(ptr1) +1;
454 ptrsize -= len;
455 if (strncmp(ptr1, "user.",5)) {
456 ptr1 += len;
457 continue;
458 }
459 memmove(ptr, ptr1 +5, len -5);
460 ptr += len -5;
461 ptr1 += len;
462 }
463 return ptr -list;
464 }
465 #endif
466
sys_listxattr(const char * path,char * list,size_t size)467 ssize_t sys_listxattr (const char *path, char *list, size_t size)
468 {
469 #if defined(HAVE_LISTXATTR)
470 ssize_t ret;
471
472 #ifndef XATTR_ADD_OPT
473 ret = listxattr(path, list, size);
474 #else
475 int options = 0;
476 ret = listxattr(path, list, size, options);
477 #endif
478 return remove_user(ret, list, size);
479
480 #elif defined(HAVE_LISTEA)
481 return listea(path, list, size);
482 #elif defined(HAVE_EXTATTR_LIST_FILE)
483 extattr_arg arg;
484 arg.path = path;
485 return bsd_attr_list(0, arg, list, size);
486 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
487 return irix_attr_list(path, 0, list, size, 0);
488 #elif defined(HAVE_ATTROPEN)
489 ssize_t ret = -1;
490 int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
491 if (attrdirfd >= 0) {
492 ret = solaris_list_xattr(attrdirfd, list, size);
493 close(attrdirfd);
494 }
495 return ret;
496 #else
497 errno = ENOSYS;
498 return -1;
499 #endif
500 }
501
sys_flistxattr(int filedes,const char * path,char * list,size_t size)502 ssize_t sys_flistxattr (int filedes, const char *path, char *list, size_t size)
503 {
504 #if defined(HAVE_LISTXATTR)
505 ssize_t ret;
506
507 #ifndef XATTR_ADD_OPT
508 ret = listxattr(path, list, size);
509 #else
510 int options = 0;
511 ret = listxattr(path, list, size, options);
512 #endif
513 return remove_user(ret, list, size);
514
515 #elif defined(HAVE_LISTEA)
516 return listea(path, list, size);
517 #elif defined(HAVE_EXTATTR_LIST_FILE)
518 extattr_arg arg;
519 arg.path = path;
520 return bsd_attr_list(0, arg, list, size);
521 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
522 return irix_attr_list(path, 0, list, size, 0);
523 #elif defined(HAVE_ATTROPEN)
524 ssize_t ret = -1;
525 int attrdirfd = solaris_attropenat(filedes, path, ".", O_RDONLY, 0);
526 if (attrdirfd >= 0) {
527 ret = solaris_list_xattr(attrdirfd, list, size);
528 close(attrdirfd);
529 }
530 return ret;
531 #else
532 errno = ENOSYS;
533 return -1;
534 #endif
535 }
536
sys_llistxattr(const char * path,char * list,size_t size)537 ssize_t sys_llistxattr (const char *path, char *list, size_t size)
538 {
539 #if defined(HAVE_LLISTXATTR)
540 ssize_t ret;
541
542 ret = llistxattr(path, list, size);
543 return remove_user(ret, list, size);
544 #elif defined(HAVE_LISTXATTR) && defined(XATTR_ADD_OPT)
545 ssize_t ret;
546 int options = XATTR_NOFOLLOW;
547
548 ret = listxattr(path, list, size, options);
549 return remove_user(ret, list, size);
550
551 #elif defined(HAVE_LLISTEA)
552 return llistea(path, list, size);
553 #elif defined(HAVE_EXTATTR_LIST_LINK)
554 extattr_arg arg;
555 arg.path = path;
556 return bsd_attr_list(1, arg, list, size);
557 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
558 return irix_attr_list(path, 0, list, size, ATTR_DONTFOLLOW);
559 #elif defined(HAVE_ATTROPEN)
560 ssize_t ret = -1;
561 int attrdirfd = solaris_attropen(path, ".", O_RDONLY | O_NOFOLLOW, 0);
562 if (attrdirfd >= 0) {
563 ret = solaris_list_xattr(attrdirfd, list, size);
564 close(attrdirfd);
565 }
566 return ret;
567 #else
568 errno = ENOSYS;
569 return -1;
570 #endif
571 }
572
sys_removexattr(const char * path,const char * uname)573 int sys_removexattr (const char *path, const char *uname)
574 {
575 const char *name = prefix(uname);
576 #if defined(HAVE_REMOVEXATTR)
577 #ifndef XATTR_ADD_OPT
578 return removexattr(path, name);
579 #else
580 int options = 0;
581 return removexattr(path, name, options);
582 #endif
583 #elif defined(HAVE_REMOVEEA)
584 return removeea(path, name);
585 #elif defined(HAVE_EXTATTR_DELETE_FILE)
586 return extattr_delete_file(path, EXTATTR_NAMESPACE_USER, uname);
587 #elif defined(HAVE_ATTR_REMOVE)
588 int flags = 0;
589 char *attrname = strchr(name,'.') + 1;
590
591 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
592
593 return attr_remove(path, attrname, flags);
594 #elif defined(HAVE_ATTROPEN)
595 int ret = -1;
596 int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
597 if (attrdirfd >= 0) {
598 ret = solaris_unlinkat(attrdirfd, name);
599 close(attrdirfd);
600 }
601 return ret;
602 #else
603 errno = ENOSYS;
604 return -1;
605 #endif
606 }
607
sys_fremovexattr(int filedes,const char * path,const char * uname)608 int sys_fremovexattr (int filedes, const char *path, const char *uname)
609 {
610 const char *name = prefix(uname);
611 #if defined(HAVE_REMOVEXATTR)
612 #ifndef XATTR_ADD_OPT
613 return removexattr(path, name);
614 #else
615 int options = 0;
616 return removexattr(path, name, options);
617 #endif
618 #elif defined(HAVE_REMOVEEA)
619 return removeea(path, name);
620 #elif defined(HAVE_EXTATTR_DELETE_FILE)
621 return extattr_delete_file(path, EXTATTR_NAMESPACE_USER, uname);
622 #elif defined(HAVE_ATTR_REMOVE)
623 int flags = 0;
624 char *attrname = strchr(name,'.') + 1;
625
626 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
627
628 return attr_remove(path, attrname, flags);
629 #elif defined(HAVE_ATTROPEN)
630 int ret = -1;
631 int attrdirfd = solaris_attropenat(filedes, path, ".", O_RDONLY, 0);
632 if (attrdirfd >= 0) {
633 ret = solaris_unlinkat(attrdirfd, name);
634 close(attrdirfd);
635 }
636 return ret;
637 #else
638 errno = ENOSYS;
639 return -1;
640 #endif
641 }
642
sys_lremovexattr(const char * path,const char * uname)643 int sys_lremovexattr (const char *path, const char *uname)
644 {
645 const char *name = prefix(uname);
646 #if defined(HAVE_LREMOVEXATTR)
647 return lremovexattr(path, name);
648 #elif defined(HAVE_REMOVEXATTR) && defined(XATTR_ADD_OPT)
649 int options = XATTR_NOFOLLOW;
650 return removexattr(path, name, options);
651 #elif defined(HAVE_LREMOVEEA)
652 return lremoveea(path, name);
653 #elif defined(HAVE_EXTATTR_DELETE_LINK)
654 return extattr_delete_link(path, EXTATTR_NAMESPACE_USER, uname);
655 #elif defined(HAVE_ATTR_REMOVE)
656 int flags = ATTR_DONTFOLLOW;
657 char *attrname = strchr(name,'.') + 1;
658
659 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
660
661 return attr_remove(path, attrname, flags);
662 #elif defined(HAVE_ATTROPEN)
663 int ret = -1;
664 int attrdirfd = solaris_attropen(path, ".", O_RDONLY | O_NOFOLLOW, 0);
665 if (attrdirfd >= 0) {
666 ret = solaris_unlinkat(attrdirfd, name);
667 close(attrdirfd);
668 }
669 return ret;
670 #else
671 errno = ENOSYS;
672 return -1;
673 #endif
674 }
675
sys_setxattr(const char * path,const char * uname,const void * value,size_t size,int flags)676 int sys_setxattr (const char *path, const char *uname, const void *value, size_t size, int flags)
677 {
678 const char *name = prefix(uname);
679 #if defined(HAVE_SETXATTR)
680 #ifndef XATTR_ADD_OPT
681 return setxattr(path, name, value, size, flags);
682 #else
683 int options = 0;
684 return setxattr(path, name, value, size, 0, options);
685 #endif
686 #elif defined(HAVE_SETEA)
687 return setea(path, name, value, size, flags);
688 #elif defined(HAVE_EXTATTR_SET_FILE)
689 int retval = 0;
690 if (flags) {
691 /* Check attribute existence */
692 retval = extattr_get_file(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0);
693 if (retval < 0) {
694 /* REPLACE attribute, that doesn't exist */
695 if (flags & XATTR_REPLACE && errno == ENOATTR) {
696 errno = ENOATTR;
697 return -1;
698 }
699 /* Ignore other errors */
700 }
701 else {
702 /* CREATE attribute, that already exists */
703 if (flags & XATTR_CREATE) {
704 errno = EEXIST;
705 return -1;
706 }
707 }
708 }
709 retval = extattr_set_file(path, EXTATTR_NAMESPACE_USER, uname, value, size);
710 return (retval < 0) ? -1 : 0;
711 #elif defined(HAVE_ATTR_SET)
712 int myflags = 0;
713 char *attrname = strchr(name,'.') + 1;
714
715 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
716 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
717 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
718
719 return attr_set(path, attrname, (const char *)value, size, myflags);
720 #elif defined(HAVE_ATTROPEN)
721 int ret = -1;
722 int myflags = O_RDWR;
723 int attrfd;
724 if (flags & XATTR_CREATE) myflags |= O_EXCL;
725 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
726 attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
727 if (attrfd >= 0) {
728 ret = solaris_write_xattr(attrfd, value, size);
729 close(attrfd);
730 }
731 return ret;
732 #else
733 errno = ENOSYS;
734 return -1;
735 #endif
736 }
737
sys_fsetxattr(int filedes,const char * uname,const void * value,size_t size,int flags)738 int sys_fsetxattr (int filedes, const char *uname, const void *value, size_t size, int flags)
739 {
740 const char *name = prefix(uname);
741
742 #if defined(HAVE_FSETXATTR)
743 #ifndef XATTR_ADD_OPT
744 return fsetxattr(filedes, name, value, size, flags);
745 #else
746 int options = 0;
747 return fsetxattr(filedes, name, value, size, 0, options);
748 #endif
749 #elif defined(HAVE_FSETEA)
750 return fsetea(filedes, name, value, size, flags);
751 #elif defined(HAVE_EXTATTR_SET_FD)
752 char *s;
753 int retval = 0;
754 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
755 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
756 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
757 if (flags) {
758 /* Check attribute existence */
759 retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
760 if (retval < 0) {
761 /* REPLACE attribute, that doesn't exist */
762 if (flags & XATTR_REPLACE && errno == ENOATTR) {
763 errno = ENOATTR;
764 return -1;
765 }
766 /* Ignore other errors */
767 }
768 else {
769 if (flags & XATTR_CREATE) {
770 errno = EEXIST;
771 return -1;
772 }
773 }
774 }
775 retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
776 return (retval < 0) ? -1 : 0;
777 #elif defined(HAVE_ATTR_SETF)
778 int myflags = 0;
779 char *attrname = strchr(name,'.') + 1;
780
781 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
782 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
783 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
784
785 return attr_setf(filedes, attrname, (const char *)value, size, myflags);
786 #elif defined(HAVE_ATTROPEN)
787 int ret = -1;
788 int myflags = O_RDWR | O_XATTR;
789 int attrfd;
790 if (flags & XATTR_CREATE) myflags |= O_EXCL;
791 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
792 attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE);
793 if (attrfd >= 0) {
794 ret = solaris_write_xattr(attrfd, value, size);
795 close(attrfd);
796 }
797 return ret;
798 #else
799 errno = ENOSYS;
800 return -1;
801 #endif
802 }
803
sys_lsetxattr(const char * path,const char * uname,const void * value,size_t size,int flags)804 int sys_lsetxattr (const char *path, const char *uname, const void *value, size_t size, int flags)
805 {
806 const char *name = prefix(uname);
807 #if defined(HAVE_LSETXATTR)
808 return lsetxattr(path, name, value, size, flags);
809 #elif defined(HAVE_SETXATTR) && defined(XATTR_ADD_OPT)
810 int options = XATTR_NOFOLLOW;
811 return setxattr(path, name, value, size, 0, options);
812 #elif defined(LSETEA)
813 return lsetea(path, name, value, size, flags);
814 #elif defined(HAVE_EXTATTR_SET_LINK)
815 int retval = 0;
816 if (flags) {
817 /* Check attribute existence */
818 retval = extattr_get_link(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0);
819 if (retval < 0) {
820 /* REPLACE attribute, that doesn't exist */
821 if (flags & XATTR_REPLACE && errno == ENOATTR) {
822 errno = ENOATTR;
823 return -1;
824 }
825 /* Ignore other errors */
826 }
827 else {
828 /* CREATE attribute, that already exists */
829 if (flags & XATTR_CREATE) {
830 errno = EEXIST;
831 return -1;
832 }
833 }
834 }
835
836 retval = extattr_set_link(path, EXTATTR_NAMESPACE_USER, uname, value, size);
837 return (retval < 0) ? -1 : 0;
838 #elif defined(HAVE_ATTR_SET)
839 int myflags = ATTR_DONTFOLLOW;
840 char *attrname = strchr(name,'.') + 1;
841
842 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
843 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
844 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
845
846 return attr_set(path, attrname, (const char *)value, size, myflags);
847 #elif defined(HAVE_ATTROPEN)
848 int ret = -1;
849 int myflags = O_RDWR | O_NOFOLLOW;
850 int attrfd;
851 if (flags & XATTR_CREATE) myflags |= O_EXCL;
852 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
853 attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
854 if (attrfd >= 0) {
855 ret = solaris_write_xattr(attrfd, value, size);
856 close(attrfd);
857 }
858 return ret;
859 #else
860 errno = ENOSYS;
861 return -1;
862 #endif
863 }
864
865 /**************************************************************************
866 helper functions for Solaris' EA support
867 ****************************************************************************/
868 #ifdef HAVE_ATTROPEN
solaris_read_xattr(int attrfd,void * value,size_t size)869 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
870 {
871 struct stat sbuf;
872
873 if (fstat(attrfd, &sbuf) == -1) {
874 return -1;
875 }
876
877 /* This is to return the current size of the named extended attribute */
878 if (size == 0) {
879 return sbuf.st_size;
880 }
881
882 /* check size and read xattr */
883 if (sbuf.st_size > size) {
884 return -1;
885 }
886
887 return read(attrfd, value, sbuf.st_size);
888 }
889
solaris_list_xattr(int attrdirfd,char * list,size_t size)890 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
891 {
892 ssize_t len = 0;
893 DIR *dirp;
894 struct dirent *de;
895 int newfd = dup(attrdirfd);
896 /* CAUTION: The originating file descriptor should not be
897 used again following the call to fdopendir().
898 For that reason we dup() the file descriptor
899 here to make things more clear. */
900 dirp = fdopendir(newfd);
901
902 while ((de = readdir(dirp))) {
903 size_t listlen;
904 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
905 {
906 /* we don't want "." and ".." here: */
907 LOG(log_maxdebug, logtype_default, "skipped EA %s\n",de->d_name);
908 continue;
909 }
910
911 listlen = strlen(de->d_name);
912 if (size == 0) {
913 /* return the current size of the list of extended attribute names*/
914 len += listlen + 1;
915 } else {
916 /* check size and copy entry + nul into list. */
917 if ((len + listlen + 1) > size) {
918 errno = ERANGE;
919 len = -1;
920 break;
921 } else {
922 strcpy(list + len, de->d_name);
923 len += listlen;
924 list[len] = '\0';
925 ++len;
926 }
927 }
928 }
929
930 if (closedir(dirp) == -1) {
931 LOG(log_error, logtype_default, "closedir dirp: %s",strerror(errno));
932 return -1;
933 }
934 return len;
935 }
936
solaris_unlinkat(int attrdirfd,const char * name)937 static int solaris_unlinkat(int attrdirfd, const char *name)
938 {
939 if (unlinkat(attrdirfd, name, 0) == -1) {
940 return -1;
941 }
942 return 0;
943 }
944
solaris_attropen(const char * path,const char * attrpath,int oflag,mode_t mode)945 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
946 {
947 EC_INIT;
948 int filedes = -1, eafd = -1;
949
950 if ((filedes = open(path, O_RDONLY | (oflag & O_NOFOLLOW), mode)) == -1) {
951 switch (errno) {
952 case ENOENT:
953 case EEXIST:
954 case OPEN_NOFOLLOW_ERRNO:
955 EC_FAIL;
956 default:
957 LOG(log_debug, logtype_default, "open(\"%s\"): %s", fullpathname(path), strerror(errno));
958 EC_FAIL;
959 }
960 }
961
962 if ((eafd = openat(filedes, attrpath, oflag | O_XATTR, mode)) == -1) {
963 switch (errno) {
964 case ENOENT:
965 case EEXIST:
966 EC_FAIL;
967 default:
968 LOG(log_debug, logtype_default, "openat(\"%s\"): %s", fullpathname(path), strerror(errno));
969 EC_FAIL;
970 }
971 }
972
973 EC_CLEANUP:
974 if (filedes != -1)
975 close(filedes);
976 if (ret != 0) {
977 if (eafd != -1)
978 close(eafd);
979 eafd = -1;
980 }
981 return eafd;
982 }
983
solaris_attropenat(int filedes,const char * path,const char * attrpath,int oflag,mode_t mode)984 static int solaris_attropenat(int filedes, const char *path, const char *attrpath, int oflag, mode_t mode)
985 {
986 EC_INIT;
987 int eafd = -1;
988
989 if ((eafd = openat(filedes, attrpath, oflag | O_XATTR, mode)) == -1) {
990 switch (errno) {
991 case ENOENT:
992 case EEXIST:
993 EC_FAIL;
994 default:
995 LOG(log_debug, logtype_default, "openat(\"%s\"): %s", fullpathname(path), strerror(errno));
996 EC_FAIL;
997 }
998 }
999
1000 EC_CLEANUP:
1001 if (ret != 0) {
1002 if (eafd != -1)
1003 close(eafd);
1004 eafd = -1;
1005 }
1006 return eafd;
1007 }
1008
1009
solaris_openat(int fildes,const char * path,int oflag,mode_t mode)1010 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
1011 {
1012 int filedes;
1013
1014 if ((filedes = openat(fildes, path, oflag, mode)) == -1) {
1015 switch (errno) {
1016 case ENOENT:
1017 case EEXIST:
1018 case EACCES:
1019 break;
1020 default:
1021 LOG(log_debug, logtype_default, "openat(\"%s\"): %s",
1022 path, strerror(errno));
1023 errno = ENOATTR;
1024 break;
1025 }
1026 }
1027 return filedes;
1028 }
1029
solaris_write_xattr(int attrfd,const char * value,size_t size)1030 static int solaris_write_xattr(int attrfd, const char *value, size_t size)
1031 {
1032 if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
1033 return 0;
1034 } else {
1035 LOG(log_error, logtype_default, "solaris_write_xattr: %s",
1036 strerror(errno));
1037 return -1;
1038 }
1039 }
1040
1041 #endif /*HAVE_ATTROPEN*/
1042
1043