Move sys_chown() to rep_chown().
[kai/samba.git] / source3 / lib / system.c
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 3 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, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24
25 #ifdef HAVE_SYS_PRCTL_H
26 #include <sys/prctl.h>
27 #endif
28
29 /*
30    The idea is that this file will eventually have wrappers around all
31    important system calls in samba. The aims are:
32
33    - to enable easier porting by putting OS dependent stuff in here
34
35    - to allow for hooks into other "pseudo-filesystems"
36
37    - to allow easier integration of things like the japanese extensions
38
39    - to support the philosophy of Samba to expose the features of
40      the OS within the SMB model. In general whatever file/printer/variable
41      expansions/etc make sense to the OS should be acceptable to Samba.
42 */
43
44
45
46 /*******************************************************************
47  A wrapper for memalign
48 ********************************************************************/
49
50 void *sys_memalign( size_t align, size_t size )
51 {
52 #if defined(HAVE_POSIX_MEMALIGN)
53         void *p = NULL;
54         int ret = posix_memalign( &p, align, size );
55         if ( ret == 0 )
56                 return p;
57                 
58         return NULL;
59 #elif defined(HAVE_MEMALIGN)
60         return memalign( align, size );
61 #else
62         /* On *BSD systems memaligns doesn't exist, but memory will
63          * be aligned on allocations of > pagesize. */
64 #if defined(SYSCONF_SC_PAGESIZE)
65         size_t pagesize = (size_t)sysconf(_SC_PAGESIZE);
66 #elif defined(HAVE_GETPAGESIZE)
67         size_t pagesize = (size_t)getpagesize();
68 #else
69         size_t pagesize = (size_t)-1;
70 #endif
71         if (pagesize == (size_t)-1) {
72                 DEBUG(0,("memalign functionalaity not available on this platform!\n"));
73                 return NULL;
74         }
75         if (size < pagesize) {
76                 size = pagesize;
77         }
78         return SMB_MALLOC(size);
79 #endif
80 }
81
82 /*******************************************************************
83  A wrapper for usleep in case we don't have one.
84 ********************************************************************/
85
86 int sys_usleep(long usecs)
87 {
88 #ifndef HAVE_USLEEP
89         struct timeval tval;
90 #endif
91
92         /*
93          * We need this braindamage as the glibc usleep
94          * is not SPEC1170 complient... grumble... JRA.
95          */
96
97         if(usecs < 0 || usecs > 1000000) {
98                 errno = EINVAL;
99                 return -1;
100         }
101
102 #if HAVE_USLEEP
103         usleep(usecs);
104         return 0;
105 #else /* HAVE_USLEEP */
106         /*
107          * Fake it with select...
108          */
109         tval.tv_sec = 0;
110         tval.tv_usec = usecs/1000;
111         select(0,NULL,NULL,NULL,&tval);
112         return 0;
113 #endif /* HAVE_USLEEP */
114 }
115
116 /*******************************************************************
117 A read wrapper that will deal with EINTR.
118 ********************************************************************/
119
120 ssize_t sys_read(int fd, void *buf, size_t count)
121 {
122         ssize_t ret;
123
124         do {
125                 ret = read(fd, buf, count);
126         } while (ret == -1 && errno == EINTR);
127         return ret;
128 }
129
130 /*******************************************************************
131 A write wrapper that will deal with EINTR.
132 ********************************************************************/
133
134 ssize_t sys_write(int fd, const void *buf, size_t count)
135 {
136         ssize_t ret;
137
138         do {
139                 ret = write(fd, buf, count);
140         } while (ret == -1 && errno == EINTR);
141         return ret;
142 }
143
144 /*******************************************************************
145 A pread wrapper that will deal with EINTR and 64-bit file offsets.
146 ********************************************************************/
147
148 #if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
149 ssize_t sys_pread(int fd, void *buf, size_t count, SMB_OFF_T off)
150 {
151         ssize_t ret;
152
153         do {
154 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_PREAD64)
155                 ret = pread64(fd, buf, count, off);
156 #else
157                 ret = pread(fd, buf, count, off);
158 #endif
159         } while (ret == -1 && errno == EINTR);
160         return ret;
161 }
162 #endif
163
164 /*******************************************************************
165 A write wrapper that will deal with EINTR and 64-bit file offsets.
166 ********************************************************************/
167
168 #if defined(HAVE_PWRITE) || defined(HAVE_PWRITE64)
169 ssize_t sys_pwrite(int fd, const void *buf, size_t count, SMB_OFF_T off)
170 {
171         ssize_t ret;
172
173         do {
174 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_PWRITE64)
175                 ret = pwrite64(fd, buf, count, off);
176 #else
177                 ret = pwrite(fd, buf, count, off);
178 #endif
179         } while (ret == -1 && errno == EINTR);
180         return ret;
181 }
182 #endif
183
184 /*******************************************************************
185 A send wrapper that will deal with EINTR.
186 ********************************************************************/
187
188 ssize_t sys_send(int s, const void *msg, size_t len, int flags)
189 {
190         ssize_t ret;
191
192         do {
193                 ret = send(s, msg, len, flags);
194         } while (ret == -1 && errno == EINTR);
195         return ret;
196 }
197
198 /*******************************************************************
199 A sendto wrapper that will deal with EINTR.
200 ********************************************************************/
201
202 ssize_t sys_sendto(int s,  const void *msg, size_t len, int flags, const struct sockaddr *to, socklen_t tolen)
203 {
204         ssize_t ret;
205
206         do {
207                 ret = sendto(s, msg, len, flags, to, tolen);
208         } while (ret == -1 && errno == EINTR);
209         return ret;
210 }
211
212 /*******************************************************************
213 A recv wrapper that will deal with EINTR.
214 ********************************************************************/
215
216 ssize_t sys_recv(int fd, void *buf, size_t count, int flags)
217 {
218         ssize_t ret;
219
220         do {
221                 ret = recv(fd, buf, count, flags);
222         } while (ret == -1 && errno == EINTR);
223         return ret;
224 }
225
226 /*******************************************************************
227 A recvfrom wrapper that will deal with EINTR.
228 ********************************************************************/
229
230 ssize_t sys_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
231 {
232         ssize_t ret;
233
234         do {
235                 ret = recvfrom(s, buf, len, flags, from, fromlen);
236         } while (ret == -1 && errno == EINTR);
237         return ret;
238 }
239
240 /*******************************************************************
241 A fcntl wrapper that will deal with EINTR.
242 ********************************************************************/
243
244 int sys_fcntl_ptr(int fd, int cmd, void *arg)
245 {
246         int ret;
247
248         do {
249                 ret = fcntl(fd, cmd, arg);
250         } while (ret == -1 && errno == EINTR);
251         return ret;
252 }
253
254 /*******************************************************************
255 A fcntl wrapper that will deal with EINTR.
256 ********************************************************************/
257
258 int sys_fcntl_long(int fd, int cmd, long arg)
259 {
260         int ret;
261
262         do {
263                 ret = fcntl(fd, cmd, arg);
264         } while (ret == -1 && errno == EINTR);
265         return ret;
266 }
267
268 /*******************************************************************
269 A stat() wrapper that will deal with 64 bit filesizes.
270 ********************************************************************/
271
272 int sys_stat(const char *fname,SMB_STRUCT_STAT *sbuf)
273 {
274         int ret;
275 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_STAT64)
276         ret = stat64(fname, sbuf);
277 #else
278         ret = stat(fname, sbuf);
279 #endif
280         /* we always want directories to appear zero size */
281         if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
282         return ret;
283 }
284
285 /*******************************************************************
286  An fstat() wrapper that will deal with 64 bit filesizes.
287 ********************************************************************/
288
289 int sys_fstat(int fd,SMB_STRUCT_STAT *sbuf)
290 {
291         int ret;
292 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FSTAT64)
293         ret = fstat64(fd, sbuf);
294 #else
295         ret = fstat(fd, sbuf);
296 #endif
297         /* we always want directories to appear zero size */
298         if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
299         return ret;
300 }
301
302 /*******************************************************************
303  An lstat() wrapper that will deal with 64 bit filesizes.
304 ********************************************************************/
305
306 int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf)
307 {
308         int ret;
309 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSTAT64)
310         ret = lstat64(fname, sbuf);
311 #else
312         ret = lstat(fname, sbuf);
313 #endif
314         /* we always want directories to appear zero size */
315         if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
316         return ret;
317 }
318
319 /*******************************************************************
320  An ftruncate() wrapper that will deal with 64 bit filesizes.
321 ********************************************************************/
322
323 int sys_ftruncate(int fd, SMB_OFF_T offset)
324 {
325 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FTRUNCATE64)
326         return ftruncate64(fd, offset);
327 #else
328         return ftruncate(fd, offset);
329 #endif
330 }
331
332 /*******************************************************************
333  An lseek() wrapper that will deal with 64 bit filesizes.
334 ********************************************************************/
335
336 SMB_OFF_T sys_lseek(int fd, SMB_OFF_T offset, int whence)
337 {
338 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSEEK64)
339         return lseek64(fd, offset, whence);
340 #else
341         return lseek(fd, offset, whence);
342 #endif
343 }
344
345 /*******************************************************************
346  An fseek() wrapper that will deal with 64 bit filesizes.
347 ********************************************************************/
348
349 int sys_fseek(FILE *fp, SMB_OFF_T offset, int whence)
350 {
351 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEK64)
352         return fseek64(fp, offset, whence);
353 #elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEKO64)
354         return fseeko64(fp, offset, whence);
355 #else
356         return fseek(fp, offset, whence);
357 #endif
358 }
359
360 /*******************************************************************
361  An ftell() wrapper that will deal with 64 bit filesizes.
362 ********************************************************************/
363
364 SMB_OFF_T sys_ftell(FILE *fp)
365 {
366 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELL64)
367         return (SMB_OFF_T)ftell64(fp);
368 #elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELLO64)
369         return (SMB_OFF_T)ftello64(fp);
370 #else
371         return (SMB_OFF_T)ftell(fp);
372 #endif
373 }
374
375 /*******************************************************************
376  A creat() wrapper that will deal with 64 bit filesizes.
377 ********************************************************************/
378
379 int sys_creat(const char *path, mode_t mode)
380 {
381 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_CREAT64)
382         return creat64(path, mode);
383 #else
384         /*
385          * If creat64 isn't defined then ensure we call a potential open64.
386          * JRA.
387          */
388         return sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
389 #endif
390 }
391
392 /*******************************************************************
393  An open() wrapper that will deal with 64 bit filesizes.
394 ********************************************************************/
395
396 int sys_open(const char *path, int oflag, mode_t mode)
397 {
398 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OPEN64)
399         return open64(path, oflag, mode);
400 #else
401         return open(path, oflag, mode);
402 #endif
403 }
404
405 /*******************************************************************
406  An fopen() wrapper that will deal with 64 bit filesizes.
407 ********************************************************************/
408
409 FILE *sys_fopen(const char *path, const char *type)
410 {
411 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_FOPEN64)
412         return fopen64(path, type);
413 #else
414         return fopen(path, type);
415 #endif
416 }
417
418
419 /*******************************************************************
420  A flock() wrapper that will perform the kernel flock.
421 ********************************************************************/
422
423 void kernel_flock(int fd, uint32 share_mode)
424 {
425 #if HAVE_KERNEL_SHARE_MODES
426         int kernel_mode = 0;
427         if (share_mode == FILE_SHARE_WRITE) {
428                 kernel_mode = LOCK_MAND|LOCK_WRITE;
429         } else if (share_mode == FILE_SHARE_READ) {
430                 kernel_mode = LOCK_MAND|LOCK_READ;
431         } else if (share_mode == FILE_SHARE_NONE) {
432                 kernel_mode = LOCK_MAND;
433         }
434         if (kernel_mode) {
435                 flock(fd, kernel_mode);
436         }
437 #endif
438         ;
439 }
440
441
442
443 /*******************************************************************
444  An opendir wrapper that will deal with 64 bit filesizes.
445 ********************************************************************/
446
447 SMB_STRUCT_DIR *sys_opendir(const char *name)
448 {
449 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OPENDIR64)
450         return opendir64(name);
451 #else
452         return opendir(name);
453 #endif
454 }
455
456 /*******************************************************************
457  A readdir wrapper that will deal with 64 bit filesizes.
458 ********************************************************************/
459
460 SMB_STRUCT_DIRENT *sys_readdir(SMB_STRUCT_DIR *dirp)
461 {
462 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_READDIR64)
463         return readdir64(dirp);
464 #else
465         return readdir(dirp);
466 #endif
467 }
468
469 /*******************************************************************
470  A seekdir wrapper that will deal with 64 bit filesizes.
471 ********************************************************************/
472
473 void sys_seekdir(SMB_STRUCT_DIR *dirp, long offset)
474 {
475 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_SEEKDIR64)
476         seekdir64(dirp, offset);
477 #else
478         seekdir(dirp, offset);
479 #endif
480 }
481
482 /*******************************************************************
483  A telldir wrapper that will deal with 64 bit filesizes.
484 ********************************************************************/
485
486 long sys_telldir(SMB_STRUCT_DIR *dirp)
487 {
488 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_TELLDIR64)
489         return (long)telldir64(dirp);
490 #else
491         return (long)telldir(dirp);
492 #endif
493 }
494
495 /*******************************************************************
496  A rewinddir wrapper that will deal with 64 bit filesizes.
497 ********************************************************************/
498
499 void sys_rewinddir(SMB_STRUCT_DIR *dirp)
500 {
501 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_REWINDDIR64)
502         rewinddir64(dirp);
503 #else
504         rewinddir(dirp);
505 #endif
506 }
507
508 /*******************************************************************
509  A close wrapper that will deal with 64 bit filesizes.
510 ********************************************************************/
511
512 int sys_closedir(SMB_STRUCT_DIR *dirp)
513 {
514 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_CLOSEDIR64)
515         return closedir64(dirp);
516 #else
517         return closedir(dirp);
518 #endif
519 }
520
521 /*******************************************************************
522  An mknod() wrapper that will deal with 64 bit filesizes.
523 ********************************************************************/
524
525 int sys_mknod(const char *path, mode_t mode, SMB_DEV_T dev)
526 {
527 #if defined(HAVE_MKNOD) || defined(HAVE_MKNOD64)
528 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_MKNOD64) && defined(HAVE_DEV64_T)
529         return mknod64(path, mode, dev);
530 #else
531         return mknod(path, mode, dev);
532 #endif
533 #else
534         /* No mknod system call. */
535         errno = ENOSYS;
536         return -1;
537 #endif
538 }
539
540 /*******************************************************************
541  Wrapper for realpath.
542 ********************************************************************/
543
544 char *sys_realpath(const char *path, char *resolved_path)
545 {
546 #if defined(HAVE_REALPATH)
547         return realpath(path, resolved_path);
548 #else
549         /* As realpath is not a system call we can't return ENOSYS. */
550         errno = EINVAL;
551         return NULL;
552 #endif
553 }
554
555 /*******************************************************************
556 The wait() calls vary between systems
557 ********************************************************************/
558
559 int sys_waitpid(pid_t pid,int *status,int options)
560 {
561 #ifdef HAVE_WAITPID
562         return waitpid(pid,status,options);
563 #else /* HAVE_WAITPID */
564         return wait4(pid, status, options, NULL);
565 #endif /* HAVE_WAITPID */
566 }
567
568 /*******************************************************************
569  System wrapper for getwd
570 ********************************************************************/
571
572 char *sys_getwd(char *s)
573 {
574         char *wd;
575 #ifdef HAVE_GETCWD
576         wd = (char *)getcwd(s, PATH_MAX);
577 #else
578         wd = (char *)getwd(s);
579 #endif
580         return wd;
581 }
582
583 /*******************************************************************
584 system wrapper for symlink
585 ********************************************************************/
586
587 int sys_symlink(const char *oldpath, const char *newpath)
588 {
589 #ifndef HAVE_SYMLINK
590         errno = ENOSYS;
591         return -1;
592 #else
593         return symlink(oldpath, newpath);
594 #endif
595 }
596
597 /*******************************************************************
598 system wrapper for readlink
599 ********************************************************************/
600
601 int sys_readlink(const char *path, char *buf, size_t bufsiz)
602 {
603 #ifndef HAVE_READLINK
604         errno = ENOSYS;
605         return -1;
606 #else
607         return readlink(path, buf, bufsiz);
608 #endif
609 }
610
611 /*******************************************************************
612 system wrapper for link
613 ********************************************************************/
614
615 int sys_link(const char *oldpath, const char *newpath)
616 {
617 #ifndef HAVE_LINK
618         errno = ENOSYS;
619         return -1;
620 #else
621         return link(oldpath, newpath);
622 #endif
623 }
624
625 /*******************************************************************
626  Wrapper for lchown.
627 ********************************************************************/
628
629 int sys_lchown(const char *fname,uid_t uid,gid_t gid)
630 {
631 #ifndef HAVE_LCHOWN
632         static int done;
633         if (!done) {
634                 DEBUG(1,("WARNING: no lchown!\n"));
635                 done=1;
636         }
637         errno = ENOSYS;
638         return -1;
639 #else
640         return(lchown(fname,uid,gid));
641 #endif
642 }
643
644 /*******************************************************************
645 os/2 also doesn't have chroot
646 ********************************************************************/
647 int sys_chroot(const char *dname)
648 {
649 #ifndef HAVE_CHROOT
650         static int done;
651         if (!done) {
652                 DEBUG(1,("WARNING: no chroot!\n"));
653                 done=1;
654         }
655         errno = ENOSYS;
656         return -1;
657 #else
658         return(chroot(dname));
659 #endif
660 }
661
662 #if defined(HAVE_POSIX_CAPABILITIES)
663
664 /**************************************************************************
665  Try and abstract process capabilities (for systems that have them).
666 ****************************************************************************/
667
668 /* Set the POSIX capabilities needed for the given purpose into the effective
669  * capability set of the current process. Make sure they are always removed
670  * from the inheritable set, because there is no circumstance in which our
671  * children should inherit our elevated privileges.
672  */
673 static bool set_process_capability(enum smbd_capability capability,
674                                    bool enable)
675 {
676         cap_value_t cap_vals[2] = {0};
677         int num_cap_vals = 0;
678
679         cap_t cap;
680
681 #if defined(HAVE_PRCTL) && defined(PR_GET_KEEPCAPS) && defined(PR_SET_KEEPCAPS)
682         /* On Linux, make sure that any capabilities we grab are sticky
683          * across UID changes. We expect that this would allow us to keep both
684          * the effective and permitted capability sets, but as of circa 2.6.16,
685          * only the permitted set is kept. It is a bug (which we work around)
686          * that the effective set is lost, but we still require the effective
687          * set to be kept.
688          */
689         if (!prctl(PR_GET_KEEPCAPS)) {
690                 prctl(PR_SET_KEEPCAPS, 1);
691         }
692 #endif
693
694         cap = cap_get_proc();
695         if (cap == NULL) {
696                 DEBUG(0,("set_process_capability: cap_get_proc failed: %s\n",
697                         strerror(errno)));
698                 return False;
699         }
700
701         switch (capability) {
702                 case KERNEL_OPLOCK_CAPABILITY:
703 #ifdef CAP_NETWORK_MGT
704                         /* IRIX has CAP_NETWORK_MGT for oplocks. */
705                         cap_vals[num_cap_vals++] = CAP_NETWORK_MGT;
706 #endif
707                         break;
708                 case DMAPI_ACCESS_CAPABILITY:
709 #ifdef CAP_DEVICE_MGT
710                         /* IRIX has CAP_DEVICE_MGT for DMAPI access. */
711                         cap_vals[num_cap_vals++] = CAP_DEVICE_MGT;
712 #elif CAP_MKNOD
713                         /* Linux has CAP_MKNOD for DMAPI access. */
714                         cap_vals[num_cap_vals++] = CAP_MKNOD;
715 #endif
716                         break;
717                 case LEASE_CAPABILITY:
718 #ifdef CAP_LEASE
719                         cap_vals[num_cap_vals++] = CAP_LEASE;
720 #endif
721                         break;
722         }
723
724         SMB_ASSERT(num_cap_vals <= ARRAY_SIZE(cap_vals));
725
726         if (num_cap_vals == 0) {
727                 cap_free(cap);
728                 return True;
729         }
730
731         cap_set_flag(cap, CAP_EFFECTIVE, num_cap_vals, cap_vals,
732                 enable ? CAP_SET : CAP_CLEAR);
733
734         /* We never want to pass capabilities down to our children, so make
735          * sure they are not inherited.
736          */
737         cap_set_flag(cap, CAP_INHERITABLE, num_cap_vals, cap_vals, CAP_CLEAR);
738
739         if (cap_set_proc(cap) == -1) {
740                 DEBUG(0, ("set_process_capability: cap_set_proc failed: %s\n",
741                         strerror(errno)));
742                 cap_free(cap);
743                 return False;
744         }
745
746         cap_free(cap);
747         return True;
748 }
749
750 #endif /* HAVE_POSIX_CAPABILITIES */
751
752 /****************************************************************************
753  Gain the oplock capability from the kernel if possible.
754 ****************************************************************************/
755
756 void set_effective_capability(enum smbd_capability capability)
757 {
758 #if defined(HAVE_POSIX_CAPABILITIES)
759         set_process_capability(capability, True);
760 #endif /* HAVE_POSIX_CAPABILITIES */
761 }
762
763 void drop_effective_capability(enum smbd_capability capability)
764 {
765 #if defined(HAVE_POSIX_CAPABILITIES)
766         set_process_capability(capability, False);
767 #endif /* HAVE_POSIX_CAPABILITIES */
768 }
769
770 /**************************************************************************
771  Wrapper for random().
772 ****************************************************************************/
773
774 long sys_random(void)
775 {
776 #if defined(HAVE_RANDOM)
777         return (long)random();
778 #elif defined(HAVE_RAND)
779         return (long)rand();
780 #else
781         DEBUG(0,("Error - no random function available !\n"));
782         exit(1);
783 #endif
784 }
785
786 /**************************************************************************
787  Wrapper for srandom().
788 ****************************************************************************/
789
790 void sys_srandom(unsigned int seed)
791 {
792 #if defined(HAVE_SRANDOM)
793         srandom(seed);
794 #elif defined(HAVE_SRAND)
795         srand(seed);
796 #else
797         DEBUG(0,("Error - no srandom function available !\n"));
798         exit(1);
799 #endif
800 }
801
802 /**************************************************************************
803  Returns equivalent to NGROUPS_MAX - using sysconf if needed.
804 ****************************************************************************/
805
806 int groups_max(void)
807 {
808 #if defined(SYSCONF_SC_NGROUPS_MAX)
809         int ret = sysconf(_SC_NGROUPS_MAX);
810         return (ret == -1) ? NGROUPS_MAX : ret;
811 #else
812         return NGROUPS_MAX;
813 #endif
814 }
815
816 /**************************************************************************
817  Wrap setgroups and getgroups for systems that declare getgroups() as
818  returning an array of gid_t, but actuall return an array of int.
819 ****************************************************************************/
820
821 #if defined(HAVE_BROKEN_GETGROUPS)
822 static int sys_broken_getgroups(int setlen, gid_t *gidset)
823 {
824         GID_T gid;
825         GID_T *group_list;
826         int i, ngroups;
827
828         if(setlen == 0) {
829                 return getgroups(setlen, &gid);
830         }
831
832         /*
833          * Broken case. We need to allocate a
834          * GID_T array of size setlen.
835          */
836
837         if(setlen < 0) {
838                 errno = EINVAL; 
839                 return -1;
840         } 
841
842         if (setlen == 0)
843                 setlen = groups_max();
844
845         if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
846                 DEBUG(0,("sys_getgroups: Malloc fail.\n"));
847                 return -1;
848         }
849
850         if((ngroups = getgroups(setlen, group_list)) < 0) {
851                 int saved_errno = errno;
852                 SAFE_FREE(group_list);
853                 errno = saved_errno;
854                 return -1;
855         }
856
857         for(i = 0; i < ngroups; i++)
858                 gidset[i] = (gid_t)group_list[i];
859
860         SAFE_FREE(group_list);
861         return ngroups;
862 }
863
864 static int sys_broken_setgroups(int setlen, gid_t *gidset)
865 {
866         GID_T *group_list;
867         int i ; 
868
869         if (setlen == 0)
870                 return 0 ;
871
872         if (setlen < 0 || setlen > groups_max()) {
873                 errno = EINVAL; 
874                 return -1;   
875         }
876
877         /*
878          * Broken case. We need to allocate a
879          * GID_T array of size setlen.
880          */
881
882         if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
883                 DEBUG(0,("sys_setgroups: Malloc fail.\n"));
884                 return -1;    
885         }
886  
887         for(i = 0; i < setlen; i++) 
888                 group_list[i] = (GID_T) gidset[i]; 
889
890         if(setgroups(setlen, group_list) != 0) {
891                 int saved_errno = errno;
892                 SAFE_FREE(group_list);
893                 errno = saved_errno;
894                 return -1;
895         }
896  
897         SAFE_FREE(group_list);
898         return 0 ;
899 }
900
901 #endif /* HAVE_BROKEN_GETGROUPS */
902
903 /* This is a list of systems that require the first GID passed to setgroups(2)
904  * to be the effective GID. If your system is one of these, add it here.
905  */
906 #if defined (FREEBSD) || defined (DARWINOS)
907 #define USE_BSD_SETGROUPS
908 #endif
909
910 #if defined(USE_BSD_SETGROUPS)
911 /* Depending on the particular BSD implementation, the first GID that is
912  * passed to setgroups(2) will either be ignored or will set the credential's
913  * effective GID. In either case, the right thing to do is to guarantee that
914  * gidset[0] is the effective GID.
915  */
916 static int sys_bsd_setgroups(gid_t primary_gid, int setlen, const gid_t *gidset)
917 {
918         gid_t *new_gidset = NULL;
919         int max;
920         int ret;
921
922         /* setgroups(2) will fail with EINVAL if we pass too many groups. */
923         max = groups_max();
924
925         /* No group list, just make sure we are setting the efective GID. */
926         if (setlen == 0) {
927                 return setgroups(1, &primary_gid);
928         }
929
930         /* If the primary gid is not the first array element, grow the array
931          * and insert it at the front.
932          */
933         if (gidset[0] != primary_gid) {
934                 new_gidset = SMB_MALLOC_ARRAY(gid_t, setlen + 1);
935                 if (new_gidset == NULL) {
936                         return -1;
937                 }
938
939                 memcpy(new_gidset + 1, gidset, (setlen * sizeof(gid_t)));
940                 new_gidset[0] = primary_gid;
941                 setlen++;
942         }
943
944         if (setlen > max) {
945                 DEBUG(3, ("forced to truncate group list from %d to %d\n",
946                         setlen, max));
947                 setlen = max;
948         }
949
950 #if defined(HAVE_BROKEN_GETGROUPS)
951         ret = sys_broken_setgroups(setlen, new_gidset ? new_gidset : gidset);
952 #else
953         ret = setgroups(setlen, new_gidset ? new_gidset : gidset);
954 #endif
955
956         if (new_gidset) {
957                 int errsav = errno;
958                 SAFE_FREE(new_gidset);
959                 errno = errsav;
960         }
961
962         return ret;
963 }
964
965 #endif /* USE_BSD_SETGROUPS */
966
967 /**************************************************************************
968  Wrapper for getgroups. Deals with broken (int) case.
969 ****************************************************************************/
970
971 int sys_getgroups(int setlen, gid_t *gidset)
972 {
973 #if defined(HAVE_BROKEN_GETGROUPS)
974         return sys_broken_getgroups(setlen, gidset);
975 #else
976         return getgroups(setlen, gidset);
977 #endif
978 }
979
980 /**************************************************************************
981  Wrapper for setgroups. Deals with broken (int) case and BSD case.
982 ****************************************************************************/
983
984 int sys_setgroups(gid_t UNUSED(primary_gid), int setlen, gid_t *gidset)
985 {
986 #if !defined(HAVE_SETGROUPS)
987         errno = ENOSYS;
988         return -1;
989 #endif /* HAVE_SETGROUPS */
990
991 #if defined(USE_BSD_SETGROUPS)
992         return sys_bsd_setgroups(primary_gid, setlen, gidset);
993 #elif defined(HAVE_BROKEN_GETGROUPS)
994         return sys_broken_setgroups(setlen, gidset);
995 #else
996         return setgroups(setlen, gidset);
997 #endif
998 }
999
1000 /**************************************************************************
1001  Wrappers for setpwent(), getpwent() and endpwent()
1002 ****************************************************************************/
1003
1004 void sys_setpwent(void)
1005 {
1006         setpwent();
1007 }
1008
1009 struct passwd *sys_getpwent(void)
1010 {
1011         return getpwent();
1012 }
1013
1014 void sys_endpwent(void)
1015 {
1016         endpwent();
1017 }
1018
1019 /**************************************************************************
1020  Wrappers for getpwnam(), getpwuid(), getgrnam(), getgrgid()
1021 ****************************************************************************/
1022
1023
1024 struct passwd *sys_getpwnam(const char *name)
1025 {
1026         return getpwnam(name);
1027 }
1028
1029 struct passwd *sys_getpwuid(uid_t uid)
1030 {
1031         return getpwuid(uid);
1032 }
1033
1034 struct group *sys_getgrnam(const char *name)
1035 {
1036         return getgrnam(name);
1037 }
1038
1039 struct group *sys_getgrgid(gid_t gid)
1040 {
1041         return getgrgid(gid);
1042 }
1043
1044 /**************************************************************************
1045  Extract a command into an arg list.
1046 ****************************************************************************/
1047
1048 static char **extract_args(TALLOC_CTX *mem_ctx, const char *command)
1049 {
1050         char *trunc_cmd;
1051         char *saveptr;
1052         char *ptr;
1053         int argcl;
1054         char **argl = NULL;
1055         int i;
1056
1057         if (!(trunc_cmd = talloc_strdup(mem_ctx, command))) {
1058                 DEBUG(0, ("talloc failed\n"));
1059                 goto nomem;
1060         }
1061
1062         if(!(ptr = strtok_r(trunc_cmd, " \t", &saveptr))) {
1063                 TALLOC_FREE(trunc_cmd);
1064                 errno = EINVAL;
1065                 return NULL;
1066         }
1067
1068         /*
1069          * Count the args.
1070          */
1071
1072         for( argcl = 1; ptr; ptr = strtok_r(NULL, " \t", &saveptr))
1073                 argcl++;
1074
1075         TALLOC_FREE(trunc_cmd);
1076
1077         if (!(argl = TALLOC_ARRAY(mem_ctx, char *, argcl + 1))) {
1078                 goto nomem;
1079         }
1080
1081         /*
1082          * Now do the extraction.
1083          */
1084
1085         if (!(trunc_cmd = talloc_strdup(mem_ctx, command))) {
1086                 goto nomem;
1087         }
1088
1089         ptr = strtok_r(trunc_cmd, " \t", &saveptr);
1090         i = 0;
1091
1092         if (!(argl[i++] = talloc_strdup(argl, ptr))) {
1093                 goto nomem;
1094         }
1095
1096         while((ptr = strtok_r(NULL, " \t", &saveptr)) != NULL) {
1097
1098                 if (!(argl[i++] = talloc_strdup(argl, ptr))) {
1099                         goto nomem;
1100                 }
1101         }
1102
1103         argl[i++] = NULL;
1104         return argl;
1105
1106  nomem:
1107         DEBUG(0, ("talloc failed\n"));
1108         TALLOC_FREE(trunc_cmd);
1109         TALLOC_FREE(argl);
1110         errno = ENOMEM;
1111         return NULL;
1112 }
1113
1114 /**************************************************************************
1115  Wrapper for fork. Ensures that mypid is reset. Used so we can write
1116  a sys_getpid() that only does a system call *once*.
1117 ****************************************************************************/
1118
1119 static pid_t mypid = (pid_t)-1;
1120
1121 pid_t sys_fork(void)
1122 {
1123         pid_t forkret = fork();
1124
1125         if (forkret == (pid_t)0) /* Child - reset mypid so sys_getpid does a system call. */
1126                 mypid = (pid_t) -1;
1127
1128         return forkret;
1129 }
1130
1131 /**************************************************************************
1132  Wrapper for getpid. Ensures we only do a system call *once*.
1133 ****************************************************************************/
1134
1135 pid_t sys_getpid(void)
1136 {
1137         if (mypid == (pid_t)-1)
1138                 mypid = getpid();
1139
1140         return mypid;
1141 }
1142
1143 /**************************************************************************
1144  Wrapper for popen. Safer as it doesn't search a path.
1145  Modified from the glibc sources.
1146  modified by tridge to return a file descriptor. We must kick our FILE* habit
1147 ****************************************************************************/
1148
1149 typedef struct _popen_list
1150 {
1151         int fd;
1152         pid_t child_pid;
1153         struct _popen_list *next;
1154 } popen_list;
1155
1156 static popen_list *popen_chain;
1157
1158 int sys_popen(const char *command)
1159 {
1160         int parent_end, child_end;
1161         int pipe_fds[2];
1162         popen_list *entry = NULL;
1163         char **argl = NULL;
1164
1165         if (pipe(pipe_fds) < 0)
1166                 return -1;
1167
1168         parent_end = pipe_fds[0];
1169         child_end = pipe_fds[1];
1170
1171         if (!*command) {
1172                 errno = EINVAL;
1173                 goto err_exit;
1174         }
1175
1176         if((entry = SMB_MALLOC_P(popen_list)) == NULL)
1177                 goto err_exit;
1178
1179         ZERO_STRUCTP(entry);
1180
1181         /*
1182          * Extract the command and args into a NULL terminated array.
1183          */
1184
1185         if(!(argl = extract_args(NULL, command)))
1186                 goto err_exit;
1187
1188         entry->child_pid = sys_fork();
1189
1190         if (entry->child_pid == -1) {
1191                 goto err_exit;
1192         }
1193
1194         if (entry->child_pid == 0) {
1195
1196                 /*
1197                  * Child !
1198                  */
1199
1200                 int child_std_end = STDOUT_FILENO;
1201                 popen_list *p;
1202
1203                 close(parent_end);
1204                 if (child_end != child_std_end) {
1205                         dup2 (child_end, child_std_end);
1206                         close (child_end);
1207                 }
1208
1209                 /*
1210                  * POSIX.2:  "popen() shall ensure that any streams from previous
1211                  * popen() calls that remain open in the parent process are closed
1212                  * in the new child process."
1213                  */
1214
1215                 for (p = popen_chain; p; p = p->next)
1216                         close(p->fd);
1217
1218                 execv(argl[0], argl);
1219                 _exit (127);
1220         }
1221
1222         /*
1223          * Parent.
1224          */
1225
1226         close (child_end);
1227         TALLOC_FREE(argl);
1228
1229         /* Link into popen_chain. */
1230         entry->next = popen_chain;
1231         popen_chain = entry;
1232         entry->fd = parent_end;
1233
1234         return entry->fd;
1235
1236 err_exit:
1237
1238         SAFE_FREE(entry);
1239         SAFE_FREE(argl);
1240         close(pipe_fds[0]);
1241         close(pipe_fds[1]);
1242         return -1;
1243 }
1244
1245 /**************************************************************************
1246  Wrapper for pclose. Modified from the glibc sources.
1247 ****************************************************************************/
1248
1249 int sys_pclose(int fd)
1250 {
1251         int wstatus;
1252         popen_list **ptr = &popen_chain;
1253         popen_list *entry = NULL;
1254         pid_t wait_pid;
1255         int status = -1;
1256
1257         /* Unlink from popen_chain. */
1258         for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
1259                 if ((*ptr)->fd == fd) {
1260                         entry = *ptr;
1261                         *ptr = (*ptr)->next;
1262                         status = 0;
1263                         break;
1264                 }
1265         }
1266
1267         if (status < 0 || close(entry->fd) < 0)
1268                 return -1;
1269
1270         /*
1271          * As Samba is catching and eating child process
1272          * exits we don't really care about the child exit
1273          * code, a -1 with errno = ECHILD will do fine for us.
1274          */
1275
1276         do {
1277                 wait_pid = sys_waitpid (entry->child_pid, &wstatus, 0);
1278         } while (wait_pid == -1 && errno == EINTR);
1279
1280         SAFE_FREE(entry);
1281
1282         if (wait_pid == -1)
1283                 return -1;
1284         return wstatus;
1285 }
1286
1287 /**************************************************************************
1288  Wrappers for dlopen, dlsym, dlclose.
1289 ****************************************************************************/
1290
1291 void *sys_dlopen(const char *name, int flags)
1292 {
1293 #if defined(HAVE_DLOPEN)
1294         return dlopen(name, flags);
1295 #else
1296         return NULL;
1297 #endif
1298 }
1299
1300 void *sys_dlsym(void *handle, const char *symbol)
1301 {
1302 #if defined(HAVE_DLSYM)
1303     return dlsym(handle, symbol);
1304 #else
1305     return NULL;
1306 #endif
1307 }
1308
1309 int sys_dlclose (void *handle)
1310 {
1311 #if defined(HAVE_DLCLOSE)
1312         return dlclose(handle);
1313 #else
1314         return 0;
1315 #endif
1316 }
1317
1318 const char *sys_dlerror(void)
1319 {
1320 #if defined(HAVE_DLERROR)
1321         return dlerror();
1322 #else
1323         return NULL;
1324 #endif
1325 }
1326
1327 int sys_dup2(int oldfd, int newfd) 
1328 {
1329 #if defined(HAVE_DUP2)
1330         return dup2(oldfd, newfd);
1331 #else
1332         errno = ENOSYS;
1333         return -1;
1334 #endif
1335 }
1336
1337 /**************************************************************************
1338  Wrapper for Admin Logs.
1339 ****************************************************************************/
1340
1341  void sys_adminlog(int priority, const char *format_str, ...) 
1342 {
1343         va_list ap;
1344         int ret;
1345         char *msgbuf = NULL;
1346
1347         va_start( ap, format_str );
1348         ret = vasprintf( &msgbuf, format_str, ap );
1349         va_end( ap );
1350
1351         if (ret == -1)
1352                 return;
1353
1354 #if defined(HAVE_SYSLOG)
1355         syslog( priority, "%s", msgbuf );
1356 #else
1357         DEBUG(0,("%s", msgbuf ));
1358 #endif
1359         SAFE_FREE(msgbuf);
1360 }
1361
1362 /******** Solaris EA helper function prototypes ********/
1363 #ifdef HAVE_ATTROPEN
1364 #define SOLARIS_ATTRMODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
1365 static int solaris_write_xattr(int attrfd, const char *value, size_t size);
1366 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size);
1367 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size);
1368 static int solaris_unlinkat(int attrdirfd, const char *name);
1369 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode);
1370 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode);
1371 #endif
1372
1373 /**************************************************************************
1374  Wrappers for extented attribute calls. Based on the Linux package with
1375  support for IRIX and (Net|Free)BSD also. Expand as other systems have them.
1376 ****************************************************************************/
1377
1378 ssize_t sys_getxattr (const char *path, const char *name, void *value, size_t size)
1379 {
1380 #if defined(HAVE_GETXATTR)
1381 #ifndef XATTR_ADD_OPT
1382         return getxattr(path, name, value, size);
1383 #else
1384         int options = 0;
1385         return getxattr(path, name, value, size, 0, options);
1386 #endif
1387 #elif defined(HAVE_GETEA)
1388         return getea(path, name, value, size);
1389 #elif defined(HAVE_EXTATTR_GET_FILE)
1390         char *s;
1391         ssize_t retval;
1392         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1393                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1394         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1395         /*
1396          * The BSD implementation has a nasty habit of silently truncating
1397          * the returned value to the size of the buffer, so we have to check
1398          * that the buffer is large enough to fit the returned value.
1399          */
1400         if((retval=extattr_get_file(path, attrnamespace, attrname, NULL, 0)) >= 0) {
1401                 if(retval > size) {
1402                         errno = ERANGE;
1403                         return -1;
1404                 }
1405                 if((retval=extattr_get_file(path, attrnamespace, attrname, value, size)) >= 0)
1406                         return retval;
1407         }
1408
1409         DEBUG(10,("sys_getxattr: extattr_get_file() failed with: %s\n", strerror(errno)));
1410         return -1;
1411 #elif defined(HAVE_ATTR_GET)
1412         int retval, flags = 0;
1413         int valuelength = (int)size;
1414         char *attrname = strchr(name,'.') + 1;
1415         
1416         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1417
1418         retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
1419
1420         return retval ? retval : valuelength;
1421 #elif defined(HAVE_ATTROPEN)
1422         ssize_t ret = -1;
1423         int attrfd = solaris_attropen(path, name, O_RDONLY, 0);
1424         if (attrfd >= 0) {
1425                 ret = solaris_read_xattr(attrfd, value, size);
1426                 close(attrfd);
1427         }
1428         return ret;
1429 #else
1430         errno = ENOSYS;
1431         return -1;
1432 #endif
1433 }
1434
1435 ssize_t sys_lgetxattr (const char *path, const char *name, void *value, size_t size)
1436 {
1437 #if defined(HAVE_LGETXATTR)
1438         return lgetxattr(path, name, value, size);
1439 #elif defined(HAVE_GETXATTR) && defined(XATTR_ADD_OPT)
1440         int options = XATTR_NOFOLLOW;
1441         return getxattr(path, name, value, size, 0, options);
1442 #elif defined(HAVE_LGETEA)
1443         return lgetea(path, name, value, size);
1444 #elif defined(HAVE_EXTATTR_GET_LINK)
1445         char *s;
1446         ssize_t retval;
1447         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1448                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1449         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1450
1451         if((retval=extattr_get_link(path, attrnamespace, attrname, NULL, 0)) >= 0) {
1452                 if(retval > size) {
1453                         errno = ERANGE;
1454                         return -1;
1455                 }
1456                 if((retval=extattr_get_link(path, attrnamespace, attrname, value, size)) >= 0)
1457                         return retval;
1458         }
1459         
1460         DEBUG(10,("sys_lgetxattr: extattr_get_link() failed with: %s\n", strerror(errno)));
1461         return -1;
1462 #elif defined(HAVE_ATTR_GET)
1463         int retval, flags = ATTR_DONTFOLLOW;
1464         int valuelength = (int)size;
1465         char *attrname = strchr(name,'.') + 1;
1466         
1467         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1468
1469         retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
1470
1471         return retval ? retval : valuelength;
1472 #elif defined(HAVE_ATTROPEN)
1473         ssize_t ret = -1;
1474         int attrfd = solaris_attropen(path, name, O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
1475         if (attrfd >= 0) {
1476                 ret = solaris_read_xattr(attrfd, value, size);
1477                 close(attrfd);
1478         }
1479         return ret;
1480 #else
1481         errno = ENOSYS;
1482         return -1;
1483 #endif
1484 }
1485
1486 ssize_t sys_fgetxattr (int filedes, const char *name, void *value, size_t size)
1487 {
1488 #if defined(HAVE_FGETXATTR)
1489 #ifndef XATTR_ADD_OPT
1490         return fgetxattr(filedes, name, value, size);
1491 #else
1492         int options = 0;
1493         return fgetxattr(filedes, name, value, size, 0, options);
1494 #endif
1495 #elif defined(HAVE_FGETEA)
1496         return fgetea(filedes, name, value, size);
1497 #elif defined(HAVE_EXTATTR_GET_FD)
1498         char *s;
1499         ssize_t retval;
1500         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1501                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1502         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1503
1504         if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) {
1505                 if(retval > size) {
1506                         errno = ERANGE;
1507                         return -1;
1508                 }
1509                 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0)
1510                         return retval;
1511         }
1512         
1513         DEBUG(10,("sys_fgetxattr: extattr_get_fd() failed with: %s\n", strerror(errno)));
1514         return -1;
1515 #elif defined(HAVE_ATTR_GETF)
1516         int retval, flags = 0;
1517         int valuelength = (int)size;
1518         char *attrname = strchr(name,'.') + 1;
1519         
1520         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1521
1522         retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags);
1523
1524         return retval ? retval : valuelength;
1525 #elif defined(HAVE_ATTROPEN)
1526         ssize_t ret = -1;
1527         int attrfd = solaris_openat(filedes, name, O_RDONLY|O_XATTR, 0);
1528         if (attrfd >= 0) {
1529                 ret = solaris_read_xattr(attrfd, value, size);
1530                 close(attrfd);
1531         }
1532         return ret;
1533 #else
1534         errno = ENOSYS;
1535         return -1;
1536 #endif
1537 }
1538
1539 #if defined(HAVE_EXTATTR_LIST_FILE)
1540
1541 #define EXTATTR_PREFIX(s)       (s), (sizeof((s))-1)
1542
1543 static struct {
1544         int space;
1545         const char *name;
1546         size_t len;
1547
1548 extattr[] = {
1549         { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("system.") },
1550         { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("user.") },
1551 };
1552
1553 typedef union {
1554         const char *path;
1555         int filedes;
1556 } extattr_arg;
1557
1558 static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
1559 {
1560         ssize_t list_size, total_size = 0;
1561         int i, t, len;
1562         char *buf;
1563         /* Iterate through extattr(2) namespaces */
1564         for(t = 0; t < (sizeof(extattr)/sizeof(extattr[0])); t++) {
1565                 switch(type) {
1566 #if defined(HAVE_EXTATTR_LIST_FILE)
1567                         case 0:
1568                                 list_size = extattr_list_file(arg.path, extattr[t].space, list, size);
1569                                 break;
1570 #endif
1571 #if defined(HAVE_EXTATTR_LIST_LINK)
1572                         case 1:
1573                                 list_size = extattr_list_link(arg.path, extattr[t].space, list, size);
1574                                 break;
1575 #endif
1576 #if defined(HAVE_EXTATTR_LIST_FD)
1577                         case 2:
1578                                 list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size);
1579                                 break;
1580 #endif
1581                         default:
1582                                 errno = ENOSYS;
1583                                 return -1;
1584                 }
1585                 /* Some error happend. Errno should be set by the previous call */
1586                 if(list_size < 0)
1587                         return -1;
1588                 /* No attributes */
1589                 if(list_size == 0)
1590                         continue;
1591                 /* XXX: Call with an empty buffer may be used to calculate
1592                    necessary buffer size. Unfortunately, we can't say, how
1593                    many attributes were returned, so here is the potential
1594                    problem with the emulation.
1595                 */
1596                 if(list == NULL) {
1597                         /* Take the worse case of one char attribute names - 
1598                            two bytes per name plus one more for sanity.
1599                         */
1600                         total_size += list_size + (list_size/2 + 1)*extattr[t].len;
1601                         continue;
1602                 }
1603                 /* Count necessary offset to fit namespace prefixes */
1604                 len = 0;
1605                 for(i = 0; i < list_size; i += list[i] + 1)
1606                         len += extattr[t].len;
1607
1608                 total_size += list_size + len;
1609                 /* Buffer is too small to fit the results */
1610                 if(total_size > size) {
1611                         errno = ERANGE;
1612                         return -1;
1613                 }
1614                 /* Shift results back, so we can prepend prefixes */
1615                 buf = memmove(list + len, list, list_size);
1616
1617                 for(i = 0; i < list_size; i += len + 1) {
1618                         len = buf[i];
1619                         strncpy(list, extattr[t].name, extattr[t].len + 1);
1620                         list += extattr[t].len;
1621                         strncpy(list, buf + i + 1, len);
1622                         list[len] = '\0';
1623                         list += len + 1;
1624                 }
1625                 size -= total_size;
1626         }
1627         return total_size;
1628 }
1629
1630 #endif
1631
1632 #if defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1633 static char attr_buffer[ATTR_MAX_VALUELEN];
1634
1635 static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
1636 {
1637         int retval = 0, index;
1638         attrlist_cursor_t *cursor = 0;
1639         int total_size = 0;
1640         attrlist_t * al = (attrlist_t *)attr_buffer;
1641         attrlist_ent_t *ae;
1642         size_t ent_size, left = size;
1643         char *bp = list;
1644
1645         while (True) {
1646             if (filedes)
1647                 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1648             else
1649                 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1650             if (retval) break;
1651             for (index = 0; index < al->al_count; index++) {
1652                 ae = ATTR_ENTRY(attr_buffer, index);
1653                 ent_size = strlen(ae->a_name) + sizeof("user.");
1654                 if (left >= ent_size) {
1655                     strncpy(bp, "user.", sizeof("user."));
1656                     strncat(bp, ae->a_name, ent_size - sizeof("user."));
1657                     bp += ent_size;
1658                     left -= ent_size;
1659                 } else if (size) {
1660                     errno = ERANGE;
1661                     retval = -1;
1662                     break;
1663                 }
1664                 total_size += ent_size;
1665             }
1666             if (al->al_more == 0) break;
1667         }
1668         if (retval == 0) {
1669             flags |= ATTR_ROOT;
1670             cursor = 0;
1671             while (True) {
1672                 if (filedes)
1673                     retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1674                 else
1675                     retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
1676                 if (retval) break;
1677                 for (index = 0; index < al->al_count; index++) {
1678                     ae = ATTR_ENTRY(attr_buffer, index);
1679                     ent_size = strlen(ae->a_name) + sizeof("system.");
1680                     if (left >= ent_size) {
1681                         strncpy(bp, "system.", sizeof("system."));
1682                         strncat(bp, ae->a_name, ent_size - sizeof("system."));
1683                         bp += ent_size;
1684                         left -= ent_size;
1685                     } else if (size) {
1686                         errno = ERANGE;
1687                         retval = -1;
1688                         break;
1689                     }
1690                     total_size += ent_size;
1691                 }
1692                 if (al->al_more == 0) break;
1693             }
1694         }
1695         return (ssize_t)(retval ? retval : total_size);
1696 }
1697
1698 #endif
1699
1700 ssize_t sys_listxattr (const char *path, char *list, size_t size)
1701 {
1702 #if defined(HAVE_LISTXATTR)
1703 #ifndef XATTR_ADD_OPT
1704         return listxattr(path, list, size);
1705 #else
1706         int options = 0;
1707         return listxattr(path, list, size, options);
1708 #endif
1709 #elif defined(HAVE_LISTEA)
1710         return listea(path, list, size);
1711 #elif defined(HAVE_EXTATTR_LIST_FILE)
1712         extattr_arg arg;
1713         arg.path = path;
1714         return bsd_attr_list(0, arg, list, size);
1715 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1716         return irix_attr_list(path, 0, list, size, 0);
1717 #elif defined(HAVE_ATTROPEN)
1718         ssize_t ret = -1;
1719         int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
1720         if (attrdirfd >= 0) {
1721                 ret = solaris_list_xattr(attrdirfd, list, size);
1722                 close(attrdirfd);
1723         }
1724         return ret;
1725 #else
1726         errno = ENOSYS;
1727         return -1;
1728 #endif
1729 }
1730
1731 ssize_t sys_llistxattr (const char *path, char *list, size_t size)
1732 {
1733 #if defined(HAVE_LLISTXATTR)
1734         return llistxattr(path, list, size);
1735 #elif defined(HAVE_LISTXATTR) && defined(XATTR_ADD_OPT)
1736         int options = XATTR_NOFOLLOW;
1737         return listxattr(path, list, size, options);
1738 #elif defined(HAVE_LLISTEA)
1739         return llistea(path, list, size);
1740 #elif defined(HAVE_EXTATTR_LIST_LINK)
1741         extattr_arg arg;
1742         arg.path = path;
1743         return bsd_attr_list(1, arg, list, size);
1744 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
1745         return irix_attr_list(path, 0, list, size, ATTR_DONTFOLLOW);
1746 #elif defined(HAVE_ATTROPEN)
1747         ssize_t ret = -1;
1748         int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
1749         if (attrdirfd >= 0) {
1750                 ret = solaris_list_xattr(attrdirfd, list, size);
1751                 close(attrdirfd);
1752         }
1753         return ret;
1754 #else
1755         errno = ENOSYS;
1756         return -1;
1757 #endif
1758 }
1759
1760 ssize_t sys_flistxattr (int filedes, char *list, size_t size)
1761 {
1762 #if defined(HAVE_FLISTXATTR)
1763 #ifndef XATTR_ADD_OPT
1764         return flistxattr(filedes, list, size);
1765 #else
1766         int options = 0;
1767         return flistxattr(filedes, list, size, options);
1768 #endif
1769 #elif defined(HAVE_FLISTEA)
1770         return flistea(filedes, list, size);
1771 #elif defined(HAVE_EXTATTR_LIST_FD)
1772         extattr_arg arg;
1773         arg.filedes = filedes;
1774         return bsd_attr_list(2, arg, list, size);
1775 #elif defined(HAVE_ATTR_LISTF)
1776         return irix_attr_list(NULL, filedes, list, size, 0);
1777 #elif defined(HAVE_ATTROPEN)
1778         ssize_t ret = -1;
1779         int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
1780         if (attrdirfd >= 0) {
1781                 ret = solaris_list_xattr(attrdirfd, list, size);
1782                 close(attrdirfd);
1783         }
1784         return ret;
1785 #else
1786         errno = ENOSYS;
1787         return -1;
1788 #endif
1789 }
1790
1791 int sys_removexattr (const char *path, const char *name)
1792 {
1793 #if defined(HAVE_REMOVEXATTR)
1794 #ifndef XATTR_ADD_OPT
1795         return removexattr(path, name);
1796 #else
1797         int options = 0;
1798         return removexattr(path, name, options);
1799 #endif
1800 #elif defined(HAVE_REMOVEEA)
1801         return removeea(path, name);
1802 #elif defined(HAVE_EXTATTR_DELETE_FILE)
1803         char *s;
1804         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1805                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1806         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1807
1808         return extattr_delete_file(path, attrnamespace, attrname);
1809 #elif defined(HAVE_ATTR_REMOVE)
1810         int flags = 0;
1811         char *attrname = strchr(name,'.') + 1;
1812         
1813         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1814
1815         return attr_remove(path, attrname, flags);
1816 #elif defined(HAVE_ATTROPEN)
1817         int ret = -1;
1818         int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
1819         if (attrdirfd >= 0) {
1820                 ret = solaris_unlinkat(attrdirfd, name);
1821                 close(attrdirfd);
1822         }
1823         return ret;
1824 #else
1825         errno = ENOSYS;
1826         return -1;
1827 #endif
1828 }
1829
1830 int sys_lremovexattr (const char *path, const char *name)
1831 {
1832 #if defined(HAVE_LREMOVEXATTR)
1833         return lremovexattr(path, name);
1834 #elif defined(HAVE_REMOVEXATTR) && defined(XATTR_ADD_OPT)
1835         int options = XATTR_NOFOLLOW;
1836         return removexattr(path, name, options);
1837 #elif defined(HAVE_LREMOVEEA)
1838         return lremoveea(path, name);
1839 #elif defined(HAVE_EXTATTR_DELETE_LINK)
1840         char *s;
1841         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1842                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1843         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1844
1845         return extattr_delete_link(path, attrnamespace, attrname);
1846 #elif defined(HAVE_ATTR_REMOVE)
1847         int flags = ATTR_DONTFOLLOW;
1848         char *attrname = strchr(name,'.') + 1;
1849         
1850         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1851
1852         return attr_remove(path, attrname, flags);
1853 #elif defined(HAVE_ATTROPEN)
1854         int ret = -1;
1855         int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
1856         if (attrdirfd >= 0) {
1857                 ret = solaris_unlinkat(attrdirfd, name);
1858                 close(attrdirfd);
1859         }
1860         return ret;
1861 #else
1862         errno = ENOSYS;
1863         return -1;
1864 #endif
1865 }
1866
1867 int sys_fremovexattr (int filedes, const char *name)
1868 {
1869 #if defined(HAVE_FREMOVEXATTR)
1870 #ifndef XATTR_ADD_OPT
1871         return fremovexattr(filedes, name);
1872 #else
1873         int options = 0;
1874         return fremovexattr(filedes, name, options);
1875 #endif
1876 #elif defined(HAVE_FREMOVEEA)
1877         return fremoveea(filedes, name);
1878 #elif defined(HAVE_EXTATTR_DELETE_FD)
1879         char *s;
1880         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1881                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1882         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1883
1884         return extattr_delete_fd(filedes, attrnamespace, attrname);
1885 #elif defined(HAVE_ATTR_REMOVEF)
1886         int flags = 0;
1887         char *attrname = strchr(name,'.') + 1;
1888         
1889         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
1890
1891         return attr_removef(filedes, attrname, flags);
1892 #elif defined(HAVE_ATTROPEN)
1893         int ret = -1;
1894         int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
1895         if (attrdirfd >= 0) {
1896                 ret = solaris_unlinkat(attrdirfd, name);
1897                 close(attrdirfd);
1898         }
1899         return ret;
1900 #else
1901         errno = ENOSYS;
1902         return -1;
1903 #endif
1904 }
1905
1906 int sys_setxattr (const char *path, const char *name, const void *value, size_t size, int flags)
1907 {
1908 #if defined(HAVE_SETXATTR)
1909 #ifndef XATTR_ADD_OPT
1910         return setxattr(path, name, value, size, flags);
1911 #else
1912         int options = 0;
1913         return setxattr(path, name, value, size, 0, options);
1914 #endif
1915 #elif defined(HAVE_SETEA)
1916         return setea(path, name, value, size, flags);
1917 #elif defined(HAVE_EXTATTR_SET_FILE)
1918         char *s;
1919         int retval = 0;
1920         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1921                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1922         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1923         if (flags) {
1924                 /* Check attribute existence */
1925                 retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
1926                 if (retval < 0) {
1927                         /* REPLACE attribute, that doesn't exist */
1928                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
1929                                 errno = ENOATTR;
1930                                 return -1;
1931                         }
1932                         /* Ignore other errors */
1933                 }
1934                 else {
1935                         /* CREATE attribute, that already exists */
1936                         if (flags & XATTR_CREATE) {
1937                                 errno = EEXIST;
1938                                 return -1;
1939                         }
1940                 }
1941         }
1942         retval = extattr_set_file(path, attrnamespace, attrname, value, size);
1943         return (retval < 0) ? -1 : 0;
1944 #elif defined(HAVE_ATTR_SET)
1945         int myflags = 0;
1946         char *attrname = strchr(name,'.') + 1;
1947         
1948         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
1949         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
1950         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
1951
1952         return attr_set(path, attrname, (const char *)value, size, myflags);
1953 #elif defined(HAVE_ATTROPEN)
1954         int ret = -1;
1955         int myflags = O_RDWR;
1956         int attrfd;
1957         if (flags & XATTR_CREATE) myflags |= O_EXCL;
1958         if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
1959         attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
1960         if (attrfd >= 0) {
1961                 ret = solaris_write_xattr(attrfd, value, size);
1962                 close(attrfd);
1963         }
1964         return ret;
1965 #else
1966         errno = ENOSYS;
1967         return -1;
1968 #endif
1969 }
1970
1971 int sys_lsetxattr (const char *path, const char *name, const void *value, size_t size, int flags)
1972 {
1973 #if defined(HAVE_LSETXATTR)
1974         return lsetxattr(path, name, value, size, flags);
1975 #elif defined(HAVE_SETXATTR) && defined(XATTR_ADD_OPT)
1976         int options = XATTR_NOFOLLOW;
1977         return setxattr(path, name, value, size, 0, options);
1978 #elif defined(LSETEA)
1979         return lsetea(path, name, value, size, flags);
1980 #elif defined(HAVE_EXTATTR_SET_LINK)
1981         char *s;
1982         int retval = 0;
1983         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
1984                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
1985         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
1986         if (flags) {
1987                 /* Check attribute existence */
1988                 retval = extattr_get_link(path, attrnamespace, attrname, NULL, 0);
1989                 if (retval < 0) {
1990                         /* REPLACE attribute, that doesn't exist */
1991                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
1992                                 errno = ENOATTR;
1993                                 return -1;
1994                         }
1995                         /* Ignore other errors */
1996                 }
1997                 else {
1998                         /* CREATE attribute, that already exists */
1999                         if (flags & XATTR_CREATE) {
2000                                 errno = EEXIST;
2001                                 return -1;
2002                         }
2003                 }
2004         }
2005
2006         retval = extattr_set_link(path, attrnamespace, attrname, value, size);
2007         return (retval < 0) ? -1 : 0;
2008 #elif defined(HAVE_ATTR_SET)
2009         int myflags = ATTR_DONTFOLLOW;
2010         char *attrname = strchr(name,'.') + 1;
2011         
2012         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
2013         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
2014         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
2015
2016         return attr_set(path, attrname, (const char *)value, size, myflags);
2017 #elif defined(HAVE_ATTROPEN)
2018         int ret = -1;
2019         int myflags = O_RDWR | AT_SYMLINK_NOFOLLOW;
2020         int attrfd;
2021         if (flags & XATTR_CREATE) myflags |= O_EXCL;
2022         if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
2023         attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
2024         if (attrfd >= 0) {
2025                 ret = solaris_write_xattr(attrfd, value, size);
2026                 close(attrfd);
2027         }
2028         return ret;
2029 #else
2030         errno = ENOSYS;
2031         return -1;
2032 #endif
2033 }
2034
2035 int sys_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags)
2036 {
2037 #if defined(HAVE_FSETXATTR)
2038 #ifndef XATTR_ADD_OPT
2039         return fsetxattr(filedes, name, value, size, flags);
2040 #else
2041         int options = 0;
2042         return fsetxattr(filedes, name, value, size, 0, options);
2043 #endif
2044 #elif defined(HAVE_FSETEA)
2045         return fsetea(filedes, name, value, size, flags);
2046 #elif defined(HAVE_EXTATTR_SET_FD)
2047         char *s;
2048         int retval = 0;
2049         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
2050                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
2051         const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
2052         if (flags) {
2053                 /* Check attribute existence */
2054                 retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
2055                 if (retval < 0) {
2056                         /* REPLACE attribute, that doesn't exist */
2057                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
2058                                 errno = ENOATTR;
2059                                 return -1;
2060                         }
2061                         /* Ignore other errors */
2062                 }
2063                 else {
2064                         /* CREATE attribute, that already exists */
2065                         if (flags & XATTR_CREATE) {
2066                                 errno = EEXIST;
2067                                 return -1;
2068                         }
2069                 }
2070         }
2071         retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
2072         return (retval < 0) ? -1 : 0;
2073 #elif defined(HAVE_ATTR_SETF)
2074         int myflags = 0;
2075         char *attrname = strchr(name,'.') + 1;
2076         
2077         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
2078         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
2079         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
2080
2081         return attr_setf(filedes, attrname, (const char *)value, size, myflags);
2082 #elif defined(HAVE_ATTROPEN)
2083         int ret = -1;
2084         int myflags = O_RDWR | O_XATTR;
2085         int attrfd;
2086         if (flags & XATTR_CREATE) myflags |= O_EXCL;
2087         if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
2088         attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE);
2089         if (attrfd >= 0) {
2090                 ret = solaris_write_xattr(attrfd, value, size);
2091                 close(attrfd);
2092         }
2093         return ret;
2094 #else
2095         errno = ENOSYS;
2096         return -1;
2097 #endif
2098 }
2099
2100 /**************************************************************************
2101  helper functions for Solaris' EA support
2102 ****************************************************************************/
2103 #ifdef HAVE_ATTROPEN
2104 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
2105 {
2106         struct stat sbuf;
2107
2108         if (fstat(attrfd, &sbuf) == -1) {
2109                 errno = ENOATTR;
2110                 return -1;
2111         }
2112
2113         /* This is to return the current size of the named extended attribute */
2114         if (size == 0) {
2115                 return sbuf.st_size;
2116         }
2117
2118         /* check size and read xattr */
2119         if (sbuf.st_size > size) {
2120                 errno = ERANGE;
2121                 return -1;
2122         }
2123
2124         return read(attrfd, value, sbuf.st_size);
2125 }
2126
2127 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
2128 {
2129         ssize_t len = 0;
2130         int stop = 0;
2131         DIR *dirp;
2132         struct dirent *de;
2133         int newfd = dup(attrdirfd);
2134         /* CAUTION: The originating file descriptor should not be
2135                     used again following the call to fdopendir().
2136                     For that reason we dup() the file descriptor
2137                     here to make things more clear. */
2138         dirp = fdopendir(newfd);
2139
2140         while ((de = readdir(dirp))) {
2141                 size_t listlen = strlen(de->d_name);
2142                 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
2143                         /* we don't want "." and ".." here: */
2144                         DEBUG(10,("skipped EA %s\n",de->d_name));
2145                         continue;
2146                 }
2147
2148                 if (size == 0) {
2149                         /* return the current size of the list of extended attribute names*/
2150                         len += listlen + 1;
2151                 } else {
2152                         /* check size and copy entrieŃ• + nul into list. */
2153                         if ((len + listlen + 1) > size) {
2154                                 errno = ERANGE;
2155                                 len = -1;
2156                                 break;
2157                         } else {
2158                                 safe_strcpy(list + len, de->d_name, listlen);
2159                                 len += listlen;
2160                                 list[len] = '\0';
2161                                 ++len;
2162                         }
2163                 }
2164         }
2165
2166         if (closedir(dirp) == -1) {
2167                 DEBUG(0,("closedir dirp failed: %s\n",strerror(errno)));
2168                 return -1;
2169         }
2170         return len;
2171 }
2172
2173 static int solaris_unlinkat(int attrdirfd, const char *name)
2174 {
2175         if (unlinkat(attrdirfd, name, 0) == -1) {
2176                 if (errno == ENOENT) {
2177                         errno = ENOATTR;
2178                 }
2179                 return -1;
2180         }
2181         return 0;
2182 }
2183
2184 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
2185 {
2186         int filedes = attropen(path, attrpath, oflag, mode);
2187         if (filedes == -1) {
2188                 DEBUG(10,("attropen FAILED: path: %s, name: %s, errno: %s\n",path,attrpath,strerror(errno)));
2189                 if (errno == EINVAL) {
2190                         errno = ENOTSUP;
2191                 } else {
2192                         errno = ENOATTR;
2193                 }
2194         }
2195         return filedes;
2196 }
2197
2198 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
2199 {
2200         int filedes = openat(fildes, path, oflag, mode);
2201         if (filedes == -1) {
2202                 DEBUG(10,("openat FAILED: fd: %s, path: %s, errno: %s\n",filedes,path,strerror(errno)));
2203                 if (errno == EINVAL) {
2204                         errno = ENOTSUP;
2205                 } else {
2206                         errno = ENOATTR;
2207                 }
2208         }
2209         return filedes;
2210 }
2211
2212 static int solaris_write_xattr(int attrfd, const char *value, size_t size)
2213 {
2214         if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
2215                 return 0;
2216         } else {
2217                 DEBUG(10,("solaris_write_xattr FAILED!\n"));
2218                 return -1;
2219         }
2220 }
2221 #endif /*HAVE_ATTROPEN*/
2222
2223
2224 /****************************************************************************
2225  Return the major devicenumber for UNIX extensions.
2226 ****************************************************************************/
2227                                                                                                                 
2228 uint32 unix_dev_major(SMB_DEV_T dev)
2229 {
2230 #if defined(HAVE_DEVICE_MAJOR_FN)
2231         return (uint32)major(dev);
2232 #else
2233         return (uint32)(dev >> 8);
2234 #endif
2235 }
2236                                                                                                                 
2237 /****************************************************************************
2238  Return the minor devicenumber for UNIX extensions.
2239 ****************************************************************************/
2240                                                                                                                 
2241 uint32 unix_dev_minor(SMB_DEV_T dev)
2242 {
2243 #if defined(HAVE_DEVICE_MINOR_FN)
2244         return (uint32)minor(dev);
2245 #else
2246         return (uint32)(dev & 0xff);
2247 #endif
2248 }
2249
2250 #if defined(WITH_AIO)
2251
2252 /*******************************************************************
2253  An aio_read wrapper that will deal with 64-bit sizes.
2254 ********************************************************************/
2255                                                                                                                                            
2256 int sys_aio_read(SMB_STRUCT_AIOCB *aiocb)
2257 {
2258 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_READ64)
2259         return aio_read64(aiocb);
2260 #elif defined(HAVE_AIO_READ)
2261         return aio_read(aiocb);
2262 #else
2263         errno = ENOSYS;
2264         return -1;
2265 #endif
2266 }
2267
2268 /*******************************************************************
2269  An aio_write wrapper that will deal with 64-bit sizes.
2270 ********************************************************************/
2271                                                                                                                                            
2272 int sys_aio_write(SMB_STRUCT_AIOCB *aiocb)
2273 {
2274 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_WRITE64)
2275         return aio_write64(aiocb);
2276 #elif defined(HAVE_AIO_WRITE)
2277         return aio_write(aiocb);
2278 #else
2279         errno = ENOSYS;
2280         return -1;
2281 #endif
2282 }
2283
2284 /*******************************************************************
2285  An aio_return wrapper that will deal with 64-bit sizes.
2286 ********************************************************************/
2287                                                                                                                                            
2288 ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb)
2289 {
2290 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_RETURN64)
2291         return aio_return64(aiocb);
2292 #elif defined(HAVE_AIO_RETURN)
2293         return aio_return(aiocb);
2294 #else
2295         errno = ENOSYS;
2296         return -1;
2297 #endif
2298 }
2299
2300 /*******************************************************************
2301  An aio_cancel wrapper that will deal with 64-bit sizes.
2302 ********************************************************************/
2303
2304 int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb)
2305 {
2306 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_CANCEL64)
2307         return aio_cancel64(fd, aiocb);
2308 #elif defined(HAVE_AIO_CANCEL)
2309         return aio_cancel(fd, aiocb);
2310 #else
2311         errno = ENOSYS;
2312         return -1;
2313 #endif
2314 }
2315
2316 /*******************************************************************
2317  An aio_error wrapper that will deal with 64-bit sizes.
2318 ********************************************************************/
2319
2320 int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb)
2321 {
2322 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_ERROR64)
2323         return aio_error64(aiocb);
2324 #elif defined(HAVE_AIO_ERROR)
2325         return aio_error(aiocb);
2326 #else
2327         errno = ENOSYS;
2328         return -1;
2329 #endif
2330 }
2331
2332 /*******************************************************************
2333  An aio_fsync wrapper that will deal with 64-bit sizes.
2334 ********************************************************************/
2335
2336 int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb)
2337 {
2338 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_FSYNC64)
2339         return aio_fsync64(op, aiocb);
2340 #elif defined(HAVE_AIO_FSYNC)
2341         return aio_fsync(op, aiocb);
2342 #else
2343         errno = ENOSYS;
2344         return -1;
2345 #endif
2346 }
2347
2348 /*******************************************************************
2349  An aio_fsync wrapper that will deal with 64-bit sizes.
2350 ********************************************************************/
2351
2352 int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout)
2353 {
2354 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_AIOCB64) && defined(HAVE_AIO_SUSPEND64)
2355         return aio_suspend64(cblist, n, timeout);
2356 #elif defined(HAVE_AIO_FSYNC)
2357         return aio_suspend(cblist, n, timeout);
2358 #else
2359         errno = ENOSYS;
2360         return -1;
2361 #endif
2362 }
2363 #else /* !WITH_AIO */
2364
2365 int sys_aio_read(SMB_STRUCT_AIOCB *aiocb)
2366 {
2367         errno = ENOSYS;
2368         return -1;
2369 }
2370
2371 int sys_aio_write(SMB_STRUCT_AIOCB *aiocb)
2372 {
2373         errno = ENOSYS;
2374         return -1;
2375 }
2376
2377 ssize_t sys_aio_return(SMB_STRUCT_AIOCB *aiocb)
2378 {
2379         errno = ENOSYS;
2380         return -1;
2381 }
2382
2383 int sys_aio_cancel(int fd, SMB_STRUCT_AIOCB *aiocb)
2384 {
2385         errno = ENOSYS;
2386         return -1;
2387 }
2388
2389 int sys_aio_error(const SMB_STRUCT_AIOCB *aiocb)
2390 {
2391         errno = ENOSYS;
2392         return -1;
2393 }
2394
2395 int sys_aio_fsync(int op, SMB_STRUCT_AIOCB *aiocb)
2396 {
2397         errno = ENOSYS;
2398         return -1;
2399 }
2400
2401 int sys_aio_suspend(const SMB_STRUCT_AIOCB * const cblist[], int n, const struct timespec *timeout)
2402 {
2403         errno = ENOSYS;
2404         return -1;
2405 }
2406 #endif /* WITH_AIO */
2407
2408 int sys_getpeereid( int s, uid_t *uid)
2409 {
2410 #if defined(HAVE_PEERCRED)
2411         struct ucred cred;
2412         socklen_t cred_len = sizeof(struct ucred);
2413         int ret;
2414
2415         ret = getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void *)&cred, &cred_len);
2416         if (ret != 0) {
2417                 return -1;
2418         }
2419
2420         if (cred_len != sizeof(struct ucred)) {
2421                 errno = EINVAL;
2422                 return -1;
2423         }
2424
2425         *uid = cred.uid;
2426         return 0;
2427 #else
2428         errno = ENOSYS;
2429         return -1;
2430 #endif
2431 }
2432
2433 int sys_getnameinfo(const struct sockaddr *psa,
2434                         socklen_t salen,
2435                         char *host,
2436                         size_t hostlen,
2437                         char *service,
2438                         size_t servlen,
2439                         int flags)
2440 {
2441         /*
2442          * For Solaris we must make sure salen is the
2443          * correct length for the incoming sa_family.
2444          */
2445
2446         if (salen == sizeof(struct sockaddr_storage)) {
2447                 salen = sizeof(struct sockaddr_in);
2448 #if defined(HAVE_IPV6)
2449                 if (psa->sa_family == AF_INET6) {
2450                         salen = sizeof(struct sockaddr_in6);
2451                 }
2452 #endif
2453         }
2454         return getnameinfo(psa, salen, host, hostlen, service, servlen, flags);
2455 }
2456
2457 int sys_connect(int fd, const struct sockaddr * addr)
2458 {
2459         socklen_t salen = -1;
2460
2461         if (addr->sa_family == AF_INET) {
2462             salen = sizeof(struct sockaddr_in);
2463         } else if (addr->sa_family == AF_UNIX) {
2464             salen = sizeof(struct sockaddr_un);
2465         }
2466 #if defined(HAVE_IPV6)
2467         else if (addr->sa_family == AF_INET6) {
2468             salen = sizeof(struct sockaddr_in6);
2469         }
2470 #endif
2471
2472         return connect(fd, addr, salen);
2473 }