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