patch from Alexander Bokovoy needed for dlopen on bsd systems
[sfrench/samba-autobuild/.git] / source / 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-2002
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 /*
25    The idea is that this file will eventually have wrappers around all
26    important system calls in samba. The aims are:
27
28    - to enable easier porting by putting OS dependent stuff in here
29
30    - to allow for hooks into other "pseudo-filesystems"
31
32    - to allow easier integration of things like the japanese extensions
33
34    - to support the philosophy of Samba to expose the features of
35      the OS within the SMB model. In general whatever file/printer/variable
36      expansions/etc make sense to the OS should be acceptable to Samba.
37 */
38
39
40
41 /*******************************************************************
42  A wrapper for usleep in case we don't have one.
43 ********************************************************************/
44
45 int sys_usleep(long usecs)
46 {
47 #ifndef HAVE_USLEEP
48         struct timeval tval;
49 #endif
50
51         /*
52          * We need this braindamage as the glibc usleep
53          * is not SPEC1170 complient... grumble... JRA.
54          */
55
56         if(usecs < 0 || usecs > 1000000) {
57                 errno = EINVAL;
58                 return -1;
59         }
60
61 #if HAVE_USLEEP
62         usleep(usecs);
63         return 0;
64 #else /* HAVE_USLEEP */
65         /*
66          * Fake it with select...
67          */
68         tval.tv_sec = 0;
69         tval.tv_usec = usecs/1000;
70         select(0,NULL,NULL,NULL,&tval);
71         return 0;
72 #endif /* HAVE_USLEEP */
73 }
74
75 /*******************************************************************
76 A read wrapper that will deal with EINTR.
77 ********************************************************************/
78
79 ssize_t sys_read(int fd, void *buf, size_t count)
80 {
81         ssize_t ret;
82
83         do {
84                 ret = read(fd, buf, count);
85         } while (ret == -1 && errno == EINTR);
86         return ret;
87 }
88
89 /*******************************************************************
90 A write wrapper that will deal with EINTR.
91 ********************************************************************/
92
93 ssize_t sys_write(int fd, const void *buf, size_t count)
94 {
95         ssize_t ret;
96
97         do {
98                 ret = write(fd, buf, count);
99         } while (ret == -1 && errno == EINTR);
100         return ret;
101 }
102
103 /*******************************************************************
104 A send wrapper that will deal with EINTR.
105 ********************************************************************/
106
107 ssize_t sys_send(int s, const void *msg, size_t len, int flags)
108 {
109         ssize_t ret;
110
111         do {
112                 ret = send(s, msg, len, flags);
113         } while (ret == -1 && errno == EINTR);
114         return ret;
115 }
116
117 /*******************************************************************
118 A sendto wrapper that will deal with EINTR.
119 ********************************************************************/
120
121 ssize_t sys_sendto(int s,  const void *msg, size_t len, int flags, const struct sockaddr *to, socklen_t tolen)
122 {
123         ssize_t ret;
124
125         do {
126                 ret = sendto(s, msg, len, flags, to, tolen);
127         } while (ret == -1 && errno == EINTR);
128         return ret;
129 }
130
131 /*******************************************************************
132 A recvfrom wrapper that will deal with EINTR.
133 ********************************************************************/
134
135 ssize_t sys_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
136 {
137         ssize_t ret;
138
139         do {
140                 ret = recvfrom(s, buf, len, flags, from, fromlen);
141         } while (ret == -1 && errno == EINTR);
142         return ret;
143 }
144
145 /*******************************************************************
146 A fcntl wrapper that will deal with EINTR.
147 ********************************************************************/
148
149 int sys_fcntl_ptr(int fd, int cmd, void *arg)
150 {
151         int ret;
152
153         do {
154                 ret = fcntl(fd, cmd, arg);
155         } while (ret == -1 && errno == EINTR);
156         return ret;
157 }
158
159 /*******************************************************************
160 A fcntl wrapper that will deal with EINTR.
161 ********************************************************************/
162
163 int sys_fcntl_long(int fd, int cmd, long arg)
164 {
165         int ret;
166
167         do {
168                 ret = fcntl(fd, cmd, arg);
169         } while (ret == -1 && errno == EINTR);
170         return ret;
171 }
172
173 /*******************************************************************
174 A stat() wrapper that will deal with 64 bit filesizes.
175 ********************************************************************/
176
177 int sys_stat(const char *fname,SMB_STRUCT_STAT *sbuf)
178 {
179         int ret;
180 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_STAT64)
181         ret = stat64(fname, sbuf);
182 #else
183         ret = stat(fname, sbuf);
184 #endif
185         /* we always want directories to appear zero size */
186         if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
187         return ret;
188 }
189
190 /*******************************************************************
191  An fstat() wrapper that will deal with 64 bit filesizes.
192 ********************************************************************/
193
194 int sys_fstat(int fd,SMB_STRUCT_STAT *sbuf)
195 {
196         int ret;
197 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FSTAT64)
198         ret = fstat64(fd, sbuf);
199 #else
200         ret = fstat(fd, sbuf);
201 #endif
202         /* we always want directories to appear zero size */
203         if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
204         return ret;
205 }
206
207 /*******************************************************************
208  An lstat() wrapper that will deal with 64 bit filesizes.
209 ********************************************************************/
210
211 int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf)
212 {
213         int ret;
214 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSTAT64)
215         ret = lstat64(fname, sbuf);
216 #else
217         ret = lstat(fname, sbuf);
218 #endif
219         /* we always want directories to appear zero size */
220         if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
221         return ret;
222 }
223
224 /*******************************************************************
225  An ftruncate() wrapper that will deal with 64 bit filesizes.
226 ********************************************************************/
227
228 int sys_ftruncate(int fd, SMB_OFF_T offset)
229 {
230 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FTRUNCATE64)
231         return ftruncate64(fd, offset);
232 #else
233         return ftruncate(fd, offset);
234 #endif
235 }
236
237 /*******************************************************************
238  An lseek() wrapper that will deal with 64 bit filesizes.
239 ********************************************************************/
240
241 SMB_OFF_T sys_lseek(int fd, SMB_OFF_T offset, int whence)
242 {
243 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSEEK64)
244         return lseek64(fd, offset, whence);
245 #else
246         return lseek(fd, offset, whence);
247 #endif
248 }
249
250 /*******************************************************************
251  An fseek() wrapper that will deal with 64 bit filesizes.
252 ********************************************************************/
253
254 int sys_fseek(FILE *fp, SMB_OFF_T offset, int whence)
255 {
256 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEK64)
257         return fseek64(fp, offset, whence);
258 #elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEKO64)
259         return fseeko64(fp, offset, whence);
260 #else
261         return fseek(fp, offset, whence);
262 #endif
263 }
264
265 /*******************************************************************
266  An ftell() wrapper that will deal with 64 bit filesizes.
267 ********************************************************************/
268
269 SMB_OFF_T sys_ftell(FILE *fp)
270 {
271 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELL64)
272         return (SMB_OFF_T)ftell64(fp);
273 #elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELLO64)
274         return (SMB_OFF_T)ftello64(fp);
275 #else
276         return (SMB_OFF_T)ftell(fp);
277 #endif
278 }
279
280 /*******************************************************************
281  A creat() wrapper that will deal with 64 bit filesizes.
282 ********************************************************************/
283
284 int sys_creat(const char *path, mode_t mode)
285 {
286 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_CREAT64)
287         return creat64(path, mode);
288 #else
289         /*
290          * If creat64 isn't defined then ensure we call a potential open64.
291          * JRA.
292          */
293         return sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
294 #endif
295 }
296
297 /*******************************************************************
298  An open() wrapper that will deal with 64 bit filesizes.
299 ********************************************************************/
300
301 int sys_open(const char *path, int oflag, mode_t mode)
302 {
303 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OPEN64)
304         return open64(path, oflag, mode);
305 #else
306         return open(path, oflag, mode);
307 #endif
308 }
309
310 /*******************************************************************
311  An fopen() wrapper that will deal with 64 bit filesizes.
312 ********************************************************************/
313
314 FILE *sys_fopen(const char *path, const char *type)
315 {
316 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_FOPEN64)
317         return fopen64(path, type);
318 #else
319         return fopen(path, type);
320 #endif
321 }
322
323 /*******************************************************************
324  A readdir wrapper that will deal with 64 bit filesizes.
325 ********************************************************************/
326
327 SMB_STRUCT_DIRENT *sys_readdir(DIR *dirp)
328 {
329 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_READDIR64)
330         return readdir64(dirp);
331 #else
332         return readdir(dirp);
333 #endif
334 }
335
336 /*******************************************************************
337  An mknod() wrapper that will deal with 64 bit filesizes.
338 ********************************************************************/
339
340 int sys_mknod(const char *path, mode_t mode, SMB_DEV_T dev)
341 {
342 #if defined(HAVE_MKNOD) || defined(HAVE_MKNOD64)
343 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_MKNOD64) && defined(HAVE_DEV64_T)
344         return mknod64(path, mode, dev);
345 #else
346         return mknod(path, mode, dev);
347 #endif
348 #else
349         /* No mknod system call. */
350         errno = ENOSYS;
351         return -1;
352 #endif
353 }
354
355 /*******************************************************************
356  Wrapper for realpath.
357 ********************************************************************/
358
359 char *sys_realpath(const char *path, char *resolved_path)
360 {
361 #if defined(HAVE_REALPATH)
362         return realpath(path, resolved_path);
363 #else
364         /* As realpath is not a system call we can't return ENOSYS. */
365         errno = EINVAL;
366         return NULL;
367 #endif
368 }
369
370 /*******************************************************************
371 The wait() calls vary between systems
372 ********************************************************************/
373
374 int sys_waitpid(pid_t pid,int *status,int options)
375 {
376 #ifdef HAVE_WAITPID
377         return waitpid(pid,status,options);
378 #else /* HAVE_WAITPID */
379         return wait4(pid, status, options, NULL);
380 #endif /* HAVE_WAITPID */
381 }
382
383 /*******************************************************************
384  System wrapper for getwd
385 ********************************************************************/
386
387 char *sys_getwd(char *s)
388 {
389         char *wd;
390 #ifdef HAVE_GETCWD
391         wd = (char *)getcwd(s, sizeof (pstring));
392 #else
393         wd = (char *)getwd(s);
394 #endif
395         return wd;
396 }
397
398 /*******************************************************************
399 system wrapper for symlink
400 ********************************************************************/
401
402 int sys_symlink(const char *oldpath, const char *newpath)
403 {
404 #ifndef HAVE_SYMLINK
405         errno = ENOSYS;
406         return -1;
407 #else
408         return symlink(oldpath, newpath);
409 #endif
410 }
411
412 /*******************************************************************
413 system wrapper for readlink
414 ********************************************************************/
415
416 int sys_readlink(const char *path, char *buf, size_t bufsiz)
417 {
418 #ifndef HAVE_READLINK
419         errno = ENOSYS;
420         return -1;
421 #else
422         return readlink(path, buf, bufsiz);
423 #endif
424 }
425
426 /*******************************************************************
427 system wrapper for link
428 ********************************************************************/
429
430 int sys_link(const char *oldpath, const char *newpath)
431 {
432 #ifndef HAVE_LINK
433         errno = ENOSYS;
434         return -1;
435 #else
436         return link(oldpath, newpath);
437 #endif
438 }
439
440 /*******************************************************************
441 chown isn't used much but OS/2 doesn't have it
442 ********************************************************************/
443
444 int sys_chown(const char *fname,uid_t uid,gid_t gid)
445 {
446 #ifndef HAVE_CHOWN
447         static int done;
448         if (!done) {
449                 DEBUG(1,("WARNING: no chown!\n"));
450                 done=1;
451         }
452 #else
453         return(chown(fname,uid,gid));
454 #endif
455 }
456
457 /*******************************************************************
458 os/2 also doesn't have chroot
459 ********************************************************************/
460 int sys_chroot(const char *dname)
461 {
462 #ifndef HAVE_CHROOT
463         static int done;
464         if (!done) {
465                 DEBUG(1,("WARNING: no chroot!\n"));
466                 done=1;
467         }
468         errno = ENOSYS;
469         return -1;
470 #else
471         return(chroot(dname));
472 #endif
473 }
474
475 /**************************************************************************
476 A wrapper for gethostbyname() that tries avoids looking up hostnames 
477 in the root domain, which can cause dial-on-demand links to come up for no
478 apparent reason.
479 ****************************************************************************/
480
481 struct hostent *sys_gethostbyname(const char *name)
482 {
483 #ifdef REDUCE_ROOT_DNS_LOOKUPS
484         char query[256], hostname[256];
485         char *domain;
486
487         /* Does this name have any dots in it? If so, make no change */
488
489         if (strchr_m(name, '.'))
490                 return(gethostbyname(name));
491
492         /* Get my hostname, which should have domain name 
493                 attached. If not, just do the gethostname on the
494                 original string. 
495         */
496
497         gethostname(hostname, sizeof(hostname) - 1);
498         hostname[sizeof(hostname) - 1] = 0;
499         if ((domain = strchr_m(hostname, '.')) == NULL)
500                 return(gethostbyname(name));
501
502         /* Attach domain name to query and do modified query.
503                 If names too large, just do gethostname on the
504                 original string.
505         */
506
507         if((strlen(name) + strlen(domain)) >= sizeof(query))
508                 return(gethostbyname(name));
509
510         slprintf(query, sizeof(query)-1, "%s%s", name, domain);
511         return(gethostbyname(query));
512 #else /* REDUCE_ROOT_DNS_LOOKUPS */
513         return(gethostbyname(name));
514 #endif /* REDUCE_ROOT_DNS_LOOKUPS */
515 }
516
517
518 #if defined(HAVE_IRIX_SPECIFIC_CAPABILITIES)
519 /**************************************************************************
520  Try and abstract process capabilities (for systems that have them).
521 ****************************************************************************/
522 static BOOL set_process_capability( uint32 cap_flag, BOOL enable )
523 {
524         if(cap_flag == KERNEL_OPLOCK_CAPABILITY) {
525                 cap_t cap = cap_get_proc();
526
527                 if (cap == NULL) {
528                         DEBUG(0,("set_process_capability: cap_get_proc failed. Error was %s\n",
529                                 strerror(errno)));
530                         return False;
531                 }
532
533                 if(enable)
534                         cap->cap_effective |= CAP_NETWORK_MGT;
535                 else
536                         cap->cap_effective &= ~CAP_NETWORK_MGT;
537
538                 if (cap_set_proc(cap) == -1) {
539                         DEBUG(0,("set_process_capability: cap_set_proc failed. Error was %s\n",
540                                 strerror(errno)));
541                         cap_free(cap);
542                         return False;
543                 }
544
545                 cap_free(cap);
546
547                 DEBUG(10,("set_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
548         }
549         return True;
550 }
551
552 /**************************************************************************
553  Try and abstract inherited process capabilities (for systems that have them).
554 ****************************************************************************/
555
556 static BOOL set_inherited_process_capability( uint32 cap_flag, BOOL enable )
557 {
558         if(cap_flag == KERNEL_OPLOCK_CAPABILITY) {
559                 cap_t cap = cap_get_proc();
560
561                 if (cap == NULL) {
562                         DEBUG(0,("set_inherited_process_capability: cap_get_proc failed. Error was %s\n",
563                                 strerror(errno)));
564                         return False;
565                 }
566
567                 if(enable)
568                         cap->cap_inheritable |= CAP_NETWORK_MGT;
569                 else
570                         cap->cap_inheritable &= ~CAP_NETWORK_MGT;
571
572                 if (cap_set_proc(cap) == -1) {
573                         DEBUG(0,("set_inherited_process_capability: cap_set_proc failed. Error was %s\n", 
574                                 strerror(errno)));
575                         cap_free(cap);
576                         return False;
577                 }
578
579                 cap_free(cap);
580
581                 DEBUG(10,("set_inherited_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
582         }
583         return True;
584 }
585 #endif
586
587 /****************************************************************************
588  Gain the oplock capability from the kernel if possible.
589 ****************************************************************************/
590
591 void oplock_set_capability(BOOL this_process, BOOL inherit)
592 {
593 #if HAVE_KERNEL_OPLOCKS_IRIX
594         set_process_capability(KERNEL_OPLOCK_CAPABILITY,this_process);
595         set_inherited_process_capability(KERNEL_OPLOCK_CAPABILITY,inherit);
596 #endif
597 }
598
599 /**************************************************************************
600  Wrapper for random().
601 ****************************************************************************/
602
603 long sys_random(void)
604 {
605 #if defined(HAVE_RANDOM)
606         return (long)random();
607 #elif defined(HAVE_RAND)
608         return (long)rand();
609 #else
610         DEBUG(0,("Error - no random function available !\n"));
611         exit(1);
612 #endif
613 }
614
615 /**************************************************************************
616  Wrapper for srandom().
617 ****************************************************************************/
618
619 void sys_srandom(unsigned int seed)
620 {
621 #if defined(HAVE_SRANDOM)
622         srandom(seed);
623 #elif defined(HAVE_SRAND)
624         srand(seed);
625 #else
626         DEBUG(0,("Error - no srandom function available !\n"));
627         exit(1);
628 #endif
629 }
630
631 /**************************************************************************
632  Returns equivalent to NGROUPS_MAX - using sysconf if needed.
633 ****************************************************************************/
634
635 int groups_max(void)
636 {
637 #if defined(SYSCONF_SC_NGROUPS_MAX)
638         int ret = sysconf(_SC_NGROUPS_MAX);
639         return (ret == -1) ? NGROUPS_MAX : ret;
640 #else
641         return NGROUPS_MAX;
642 #endif
643 }
644
645 /**************************************************************************
646  Wrapper for getgroups. Deals with broken (int) case.
647 ****************************************************************************/
648
649 int sys_getgroups(int setlen, gid_t *gidset)
650 {
651 #if !defined(HAVE_BROKEN_GETGROUPS)
652         return getgroups(setlen, gidset);
653 #else
654
655         GID_T gid;
656         GID_T *group_list;
657         int i, ngroups;
658
659         if(setlen == 0) {
660                 return getgroups(setlen, &gid);
661         }
662
663         /*
664          * Broken case. We need to allocate a
665          * GID_T array of size setlen.
666          */
667
668         if(setlen < 0) {
669                 errno = EINVAL; 
670                 return -1;
671         } 
672
673         if (setlen == 0)
674                 setlen = groups_max();
675
676         if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
677                 DEBUG(0,("sys_getgroups: Malloc fail.\n"));
678                 return -1;
679         }
680
681         if((ngroups = getgroups(setlen, group_list)) < 0) {
682                 int saved_errno = errno;
683                 SAFE_FREE(group_list);
684                 errno = saved_errno;
685                 return -1;
686         }
687
688         for(i = 0; i < ngroups; i++)
689                 gidset[i] = (gid_t)group_list[i];
690
691         SAFE_FREE(group_list);
692         return ngroups;
693 #endif /* HAVE_BROKEN_GETGROUPS */
694 }
695
696 #ifdef HAVE_SETGROUPS
697
698 /**************************************************************************
699  Wrapper for setgroups. Deals with broken (int) case. Automatically used
700  if we have broken getgroups.
701 ****************************************************************************/
702
703 int sys_setgroups(int setlen, gid_t *gidset)
704 {
705 #if !defined(HAVE_BROKEN_GETGROUPS)
706         return setgroups(setlen, gidset);
707 #else
708
709         GID_T *group_list;
710         int i ; 
711
712         if (setlen == 0)
713                 return 0 ;
714
715         if (setlen < 0 || setlen > groups_max()) {
716                 errno = EINVAL; 
717                 return -1;   
718         }
719
720         /*
721          * Broken case. We need to allocate a
722          * GID_T array of size setlen.
723          */
724
725         if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
726                 DEBUG(0,("sys_setgroups: Malloc fail.\n"));
727                 return -1;    
728         }
729  
730         for(i = 0; i < setlen; i++) 
731                 group_list[i] = (GID_T) gidset[i]; 
732
733         if(setgroups(setlen, group_list) != 0) {
734                 int saved_errno = errno;
735                 SAFE_FREE(group_list);
736                 errno = saved_errno;
737                 return -1;
738         }
739  
740         SAFE_FREE(group_list);
741         return 0 ;
742 #endif /* HAVE_BROKEN_GETGROUPS */
743 }
744
745 #endif /* HAVE_SETGROUPS */
746
747 /*
748  * We only wrap pw_name and pw_passwd for now as these
749  * are the only potentially modified fields.
750  */
751
752 /**************************************************************************
753  Helper function for getpwnam/getpwuid wrappers.
754 ****************************************************************************/
755
756 struct saved_pw {
757         fstring         pw_name;
758         fstring         pw_passwd;
759         fstring         pw_gecos;
760         pstring         pw_dir;
761         pstring         pw_shell;
762         struct passwd pass;
763 };
764
765 static struct saved_pw pw_mod; /* This is the structure returned - can be modified. */
766 static struct saved_pw pw_cache; /* This is the structure saved - used to check cache. */
767
768 static int num_lookups; /* Counter so we don't always use cache. */
769 #ifndef PW_RET_CACHE_MAX_LOOKUPS
770 #define PW_RET_CACHE_MAX_LOOKUPS 100
771 #endif
772
773 static void copy_pwent(struct saved_pw *dst, struct passwd *pass)
774 {
775         memcpy((char *)&dst->pass, pass, sizeof(struct passwd));
776
777         fstrcpy(dst->pw_name, pass->pw_name);
778         dst->pass.pw_name = dst->pw_name;
779
780         fstrcpy(dst->pw_passwd, pass->pw_passwd);
781         dst->pass.pw_passwd = dst->pw_passwd;
782
783         fstrcpy(dst->pw_gecos, pass->pw_gecos);
784         dst->pass.pw_gecos = dst->pw_gecos;
785
786         pstrcpy(dst->pw_dir, pass->pw_dir);
787         dst->pass.pw_dir = dst->pw_dir;
788
789         pstrcpy(dst->pw_shell, pass->pw_shell);
790         dst->pass.pw_shell = dst->pw_shell;
791 }
792
793 static struct passwd *setup_pwret(struct passwd *pass)
794 {
795         if (pass == NULL) {
796                 /* Clear the caches. */
797                 memset(&pw_cache, '\0', sizeof(struct saved_pw));
798                 memset(&pw_mod, '\0', sizeof(struct saved_pw));
799                 num_lookups = 0;
800                 return NULL;
801         }
802
803         copy_pwent( &pw_mod, pass);
804
805         if (pass != &pw_cache.pass) {
806
807                 /* If it's a cache miss we must also refill the cache. */
808
809                 copy_pwent( &pw_cache, pass);
810                 num_lookups = 1;
811
812         } else {
813
814                 /* Cache hit. */
815
816                 num_lookups++;
817                 num_lookups = (num_lookups % PW_RET_CACHE_MAX_LOOKUPS);
818         }
819
820         return &pw_mod.pass;
821 }
822
823 /**************************************************************************
824  Wrappers for setpwent(), getpwent() and endpwent()
825 ****************************************************************************/
826
827 void sys_setpwent(void)
828 {
829         setup_pwret(NULL); /* Clear cache. */
830         setpwent();
831 }
832
833 struct passwd *sys_getpwent(void)
834 {
835         return setup_pwret(getpwent());
836 }
837
838 void sys_endpwent(void)
839 {
840         setup_pwret(NULL); /* Clear cache. */
841         endpwent();
842 }
843
844 /**************************************************************************
845  Wrapper for getpwnam(). Always returns a static that can be modified.
846 ****************************************************************************/
847
848 struct passwd *sys_getpwnam(const char *name)
849 {
850         if (!name || !name[0])
851                 return NULL;
852
853         /* check for a cache hit first */
854         if (num_lookups && pw_cache.pass.pw_name && !strcmp(name, pw_cache.pass.pw_name)) {
855                 return setup_pwret(&pw_cache.pass);
856         }
857
858         return setup_pwret(getpwnam(name));
859 }
860
861 /**************************************************************************
862  Wrapper for getpwuid(). Always returns a static that can be modified.
863 ****************************************************************************/
864
865 struct passwd *sys_getpwuid(uid_t uid)
866 {
867         if (num_lookups && pw_cache.pass.pw_name && (uid == pw_cache.pass.pw_uid)) {
868                 return setup_pwret(&pw_cache.pass);
869         }
870         
871         return setup_pwret(getpwuid(uid));
872 }
873
874 #if 0 /* NOT CURRENTLY USED - JRA */
875 /**************************************************************************
876  The following are the UNICODE versions of *all* system interface functions
877  called within Samba. Ok, ok, the exceptions are the gethostbyXX calls,
878  which currently are left as ascii as they are not used other than in name
879  resolution.
880 ****************************************************************************/
881
882 /**************************************************************************
883  Wide stat. Just narrow and call sys_xxx.
884 ****************************************************************************/
885
886 int wsys_stat(const smb_ucs2_t *wfname,SMB_STRUCT_STAT *sbuf)
887 {
888         pstring fname;
889         return sys_stat(unicode_to_unix(fname,wfname,sizeof(fname)), sbuf);
890 }
891
892 /**************************************************************************
893  Wide lstat. Just narrow and call sys_xxx.
894 ****************************************************************************/
895
896 int wsys_lstat(const smb_ucs2_t *wfname,SMB_STRUCT_STAT *sbuf)
897 {
898         pstring fname;
899         return sys_lstat(unicode_to_unix(fname,wfname,sizeof(fname)), sbuf);
900 }
901
902 /**************************************************************************
903  Wide creat. Just narrow and call sys_xxx.
904 ****************************************************************************/
905
906 int wsys_creat(const smb_ucs2_t *wfname, mode_t mode)
907 {
908         pstring fname;
909         return sys_creat(unicode_to_unix(fname,wfname,sizeof(fname)), mode);
910 }
911
912 /**************************************************************************
913  Wide open. Just narrow and call sys_xxx.
914 ****************************************************************************/
915
916 int wsys_open(const smb_ucs2_t *wfname, int oflag, mode_t mode)
917 {
918         pstring fname;
919         return sys_open(unicode_to_unix(fname,wfname,sizeof(fname)), oflag, mode);
920 }
921
922 /**************************************************************************
923  Wide fopen. Just narrow and call sys_xxx.
924 ****************************************************************************/
925
926 FILE *wsys_fopen(const smb_ucs2_t *wfname, const char *type)
927 {
928         pstring fname;
929         return sys_fopen(unicode_to_unix(fname,wfname,sizeof(fname)), type);
930 }
931
932 /**************************************************************************
933  Wide opendir. Just narrow and call sys_xxx.
934 ****************************************************************************/
935
936 DIR *wsys_opendir(const smb_ucs2_t *wfname)
937 {
938         pstring fname;
939         return opendir(unicode_to_unix(fname,wfname,sizeof(fname)));
940 }
941
942 /**************************************************************************
943  Wide readdir. Return a structure pointer containing a wide filename.
944 ****************************************************************************/
945
946 SMB_STRUCT_WDIRENT *wsys_readdir(DIR *dirp)
947 {
948         static SMB_STRUCT_WDIRENT retval;
949         SMB_STRUCT_DIRENT *dirval = sys_readdir(dirp);
950
951         if(!dirval)
952                 return NULL;
953
954         /*
955          * The only POSIX defined member of this struct is d_name.
956          */
957
958         unix_to_unicode(retval.d_name,dirval->d_name,sizeof(retval.d_name));
959
960         return &retval;
961 }
962
963 /**************************************************************************
964  Wide getwd. Call sys_xxx and widen. Assumes s points to a wpstring.
965 ****************************************************************************/
966
967 smb_ucs2_t *wsys_getwd(smb_ucs2_t *s)
968 {
969         pstring fname;
970         char *p = sys_getwd(fname);
971
972         if(!p)
973                 return NULL;
974
975         return unix_to_unicode(s, p, sizeof(wpstring));
976 }
977
978 /**************************************************************************
979  Wide chown. Just narrow and call sys_xxx.
980 ****************************************************************************/
981
982 int wsys_chown(const smb_ucs2_t *wfname, uid_t uid, gid_t gid)
983 {
984         pstring fname;
985         return chown(unicode_to_unix(fname,wfname,sizeof(fname)), uid, gid);
986 }
987
988 /**************************************************************************
989  Wide chroot. Just narrow and call sys_xxx.
990 ****************************************************************************/
991
992 int wsys_chroot(const smb_ucs2_t *wfname)
993 {
994         pstring fname;
995         return chroot(unicode_to_unix(fname,wfname,sizeof(fname)));
996 }
997
998 /**************************************************************************
999  Wide getpwnam. Return a structure pointer containing wide names.
1000 ****************************************************************************/
1001
1002 SMB_STRUCT_WPASSWD *wsys_getpwnam(const smb_ucs2_t *wname)
1003 {
1004         static SMB_STRUCT_WPASSWD retval;
1005         fstring name;
1006         struct passwd *pwret = sys_getpwnam(unicode_to_unix(name,wname,sizeof(name)));
1007
1008         if(!pwret)
1009                 return NULL;
1010
1011         unix_to_unicode(retval.pw_name, pwret->pw_name, sizeof(retval.pw_name));
1012         retval.pw_passwd = pwret->pw_passwd;
1013         retval.pw_uid = pwret->pw_uid;
1014         retval.pw_gid = pwret->pw_gid;
1015         unix_to_unicode(retval.pw_gecos, pwret->pw_gecos, sizeof(retval.pw_gecos));
1016         unix_to_unicode(retval.pw_dir, pwret->pw_dir, sizeof(retval.pw_dir));
1017         unix_to_unicode(retval.pw_shell, pwret->pw_shell, sizeof(retval.pw_shell));
1018
1019         return &retval;
1020 }
1021
1022 /**************************************************************************
1023  Wide getpwuid. Return a structure pointer containing wide names.
1024 ****************************************************************************/
1025
1026 SMB_STRUCT_WPASSWD *wsys_getpwuid(uid_t uid)
1027 {
1028         static SMB_STRUCT_WPASSWD retval;
1029         struct passwd *pwret = sys_getpwuid(uid);
1030
1031         if(!pwret)
1032                 return NULL;
1033
1034         unix_to_unicode(retval.pw_name, pwret->pw_name, sizeof(retval.pw_name));
1035         retval.pw_passwd = pwret->pw_passwd;
1036         retval.pw_uid = pwret->pw_uid;
1037         retval.pw_gid = pwret->pw_gid;
1038         unix_to_unicode(retval.pw_gecos, pwret->pw_gecos, sizeof(retval.pw_gecos));
1039         unix_to_unicode(retval.pw_dir, pwret->pw_dir, sizeof(retval.pw_dir));
1040         unix_to_unicode(retval.pw_shell, pwret->pw_shell, sizeof(retval.pw_shell));
1041
1042         return &retval;
1043 }
1044 #endif /* NOT CURRENTLY USED - JRA */
1045
1046 /**************************************************************************
1047  Extract a command into an arg list. Uses a static pstring for storage.
1048  Caller frees returned arg list (which contains pointers into the static pstring).
1049 ****************************************************************************/
1050
1051 static char **extract_args(const char *command)
1052 {
1053         static pstring trunc_cmd;
1054         char *ptr;
1055         int argcl;
1056         char **argl = NULL;
1057         int i;
1058
1059         pstrcpy(trunc_cmd, command);
1060
1061         if(!(ptr = strtok(trunc_cmd, " \t"))) {
1062                 errno = EINVAL;
1063                 return NULL;
1064         }
1065
1066         /*
1067          * Count the args.
1068          */
1069
1070         for( argcl = 1; ptr; ptr = strtok(NULL, " \t"))
1071                 argcl++;
1072
1073         if((argl = (char **)malloc((argcl + 1) * sizeof(char *))) == NULL)
1074                 return NULL;
1075
1076         /*
1077          * Now do the extraction.
1078          */
1079
1080         pstrcpy(trunc_cmd, command);
1081
1082         ptr = strtok(trunc_cmd, " \t");
1083         i = 0;
1084         argl[i++] = ptr;
1085
1086         while((ptr = strtok(NULL, " \t")) != NULL)
1087                 argl[i++] = ptr;
1088
1089         argl[i++] = NULL;
1090         return argl;
1091 }
1092
1093 /**************************************************************************
1094  Wrapper for fork. Ensures that mypid is reset. Used so we can write
1095  a sys_getpid() that only does a system call *once*.
1096 ****************************************************************************/
1097
1098 static pid_t mypid = (pid_t)-1;
1099
1100 pid_t sys_fork(void)
1101 {
1102         pid_t forkret = fork();
1103
1104         if (forkret == (pid_t)0) /* Child - reset mypid so sys_getpid does a system call. */
1105                 mypid = (pid_t) -1;
1106
1107         return forkret;
1108 }
1109
1110 /**************************************************************************
1111  Wrapper for getpid. Ensures we only do a system call *once*.
1112 ****************************************************************************/
1113
1114 pid_t sys_getpid(void)
1115 {
1116         if (mypid == (pid_t)-1)
1117                 mypid = getpid();
1118
1119         return mypid;
1120 }
1121
1122 /**************************************************************************
1123  Wrapper for popen. Safer as it doesn't search a path.
1124  Modified from the glibc sources.
1125  modified by tridge to return a file descriptor. We must kick our FILE* habit
1126 ****************************************************************************/
1127
1128 typedef struct _popen_list
1129 {
1130         int fd;
1131         pid_t child_pid;
1132         struct _popen_list *next;
1133 } popen_list;
1134
1135 static popen_list *popen_chain;
1136
1137 int sys_popen(const char *command)
1138 {
1139         int parent_end, child_end;
1140         int pipe_fds[2];
1141         popen_list *entry = NULL;
1142         char **argl = NULL;
1143
1144         if (pipe(pipe_fds) < 0)
1145                 return -1;
1146
1147         parent_end = pipe_fds[0];
1148         child_end = pipe_fds[1];
1149
1150         if (!*command) {
1151                 errno = EINVAL;
1152                 goto err_exit;
1153         }
1154
1155         if((entry = (popen_list *)malloc(sizeof(popen_list))) == NULL)
1156                 goto err_exit;
1157
1158         ZERO_STRUCTP(entry);
1159
1160         /*
1161          * Extract the command and args into a NULL terminated array.
1162          */
1163
1164         if(!(argl = extract_args(command)))
1165                 goto err_exit;
1166
1167         entry->child_pid = sys_fork();
1168
1169         if (entry->child_pid == -1) {
1170                 goto err_exit;
1171         }
1172
1173         if (entry->child_pid == 0) {
1174
1175                 /*
1176                  * Child !
1177                  */
1178
1179                 int child_std_end = STDOUT_FILENO;
1180                 popen_list *p;
1181
1182                 close(parent_end);
1183                 if (child_end != child_std_end) {
1184                         dup2 (child_end, child_std_end);
1185                         close (child_end);
1186                 }
1187
1188                 /*
1189                  * POSIX.2:  "popen() shall ensure that any streams from previous
1190                  * popen() calls that remain open in the parent process are closed
1191                  * in the new child process."
1192                  */
1193
1194                 for (p = popen_chain; p; p = p->next)
1195                         close(p->fd);
1196
1197                 execv(argl[0], argl);
1198                 _exit (127);
1199         }
1200
1201         /*
1202          * Parent.
1203          */
1204
1205         close (child_end);
1206         SAFE_FREE(argl);
1207
1208         /* Link into popen_chain. */
1209         entry->next = popen_chain;
1210         popen_chain = entry;
1211         entry->fd = parent_end;
1212
1213         return entry->fd;
1214
1215 err_exit:
1216
1217         SAFE_FREE(entry);
1218         SAFE_FREE(argl);
1219         close(pipe_fds[0]);
1220         close(pipe_fds[1]);
1221         return -1;
1222 }
1223
1224 /**************************************************************************
1225  Wrapper for pclose. Modified from the glibc sources.
1226 ****************************************************************************/
1227
1228 int sys_pclose(int fd)
1229 {
1230         int wstatus;
1231         popen_list **ptr = &popen_chain;
1232         popen_list *entry = NULL;
1233         pid_t wait_pid;
1234         int status = -1;
1235
1236         /* Unlink from popen_chain. */
1237         for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
1238                 if ((*ptr)->fd == fd) {
1239                         entry = *ptr;
1240                         *ptr = (*ptr)->next;
1241                         status = 0;
1242                         break;
1243                 }
1244         }
1245
1246         if (status < 0 || close(entry->fd) < 0)
1247                 return -1;
1248
1249         /*
1250          * As Samba is catching and eating child process
1251          * exits we don't really care about the child exit
1252          * code, a -1 with errno = ECHILD will do fine for us.
1253          */
1254
1255         do {
1256                 wait_pid = sys_waitpid (entry->child_pid, &wstatus, 0);
1257         } while (wait_pid == -1 && errno == EINTR);
1258
1259         SAFE_FREE(entry);
1260
1261         if (wait_pid == -1)
1262                 return -1;
1263         return wstatus;
1264 }
1265
1266 /**************************************************************************
1267  Wrappers for dlopen, dlsym, dlclose.
1268 ****************************************************************************/
1269
1270 void *sys_dlopen(const char *name, int flags)
1271 {
1272 #if defined(HAVE_DLOPEN)
1273         return dlopen(name, flags);
1274 #else
1275         return NULL;
1276 #endif
1277 }
1278
1279 void *sys_dlsym(void *handle, char *symbol)
1280 {
1281 #if defined(HAVE_DLSYM)
1282     return dlsym(handle, symbol);
1283 #else
1284     return NULL;
1285 #endif
1286 }
1287
1288 int sys_dlclose (void *handle)
1289 {
1290 #if defined(HAVE_DLCLOSE)
1291         return dlclose(handle);
1292 #else
1293         return 0;
1294 #endif
1295 }
1296
1297 const char *sys_dlerror(void)
1298 {
1299 #if defined(HAVE_DLERROR)
1300         return dlerror();
1301 #else
1302         return NULL;
1303 #endif
1304 }
1305
1306 /**************************************************************************
1307  Wrapper for Admin Logs.
1308 ****************************************************************************/
1309
1310 void sys_adminlog(int priority, const char *format_str, ...)
1311 {
1312         va_list ap;
1313         int ret;
1314         char **msgbuf = NULL;
1315
1316         if (!lp_admin_log())
1317                 return;
1318
1319         va_start( ap, format_str );
1320         ret = vasprintf( msgbuf, format_str, ap );
1321         va_end( ap );
1322
1323         if (ret == -1)
1324                 return;
1325
1326 #if defined(HAVE_SYSLOG)
1327         syslog( priority, "%s", *msgbuf );
1328 #else
1329         DEBUG(0,("%s", *msgbuf ));
1330 #endif
1331         SAFE_FREE(*msgbuf);
1332 }