Fixes to add "paranoid" option to popen. Checks some basic things.
[nivanova/samba-autobuild/.git] / source3 / lib / system.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Samba system utilities
5    Copyright (C) Andrew Tridgell 1992-1998
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 extern int DEBUGLEVEL;
25
26 /*
27    The idea is that this file will eventually have wrappers around all
28    important system calls in samba. The aims are:
29
30    - to enable easier porting by putting OS dependent stuff in here
31
32    - to allow for hooks into other "pseudo-filesystems"
33
34    - to allow easier integration of things like the japanese extensions
35
36    - to support the philosophy of Samba to expose the features of
37      the OS within the SMB model. In general whatever file/printer/variable
38      expansions/etc make sense to the OS should be acceptable to Samba.
39 */
40
41
42 /*******************************************************************
43 this replaces the normal select() system call
44 return if some data has arrived on one of the file descriptors
45 return -1 means error
46 ********************************************************************/
47 #ifndef HAVE_SELECT
48 static int pollfd(int fd)
49 {
50   int     r=0;
51
52 #ifdef HAS_RDCHK
53   r = rdchk(fd);
54 #elif defined(TCRDCHK)
55   (void)ioctl(fd, TCRDCHK, &r);
56 #else
57   (void)ioctl(fd, FIONREAD, &r);
58 #endif
59
60   return(r);
61 }
62
63 int sys_select(int maxfd, fd_set *fds,struct timeval *tval)
64 {
65   fd_set fds2;
66   int counter=0;
67   int found=0;
68
69   FD_ZERO(&fds2);
70
71   while (1) 
72   {
73     int i;
74     for (i=0;i<maxfd;i++) {
75       if (FD_ISSET(i,fds) && pollfd(i)>0) {
76         found++;
77         FD_SET(i,&fds2);
78       }
79     }
80
81     if (found) {
82       memcpy((void *)fds,(void *)&fds2,sizeof(fds2));
83       return(found);
84     }
85       
86     if (tval && tval->tv_sec < counter) return(0);
87       sleep(1);
88       counter++;
89   }
90 }
91
92 #else /* !NO_SELECT */
93 int sys_select(int maxfd, fd_set *fds,struct timeval *tval)
94 {
95 #ifdef USE_POLL
96   struct pollfd pfd[256];
97   int i;
98   int maxpoll;
99   int timeout;
100   int pollrtn;
101
102   maxpoll = 0;
103   for( i = 0; i < maxfd; i++) {
104     if(FD_ISSET(i,fds)) {
105       struct pollfd *pfdp = &pfd[maxpoll++];
106       pfdp->fd = i;
107       pfdp->events = POLLIN;
108       pfdp->revents = 0;
109     }
110   }
111
112   timeout = (tval != NULL) ? (tval->tv_sec * 1000) + (tval->tv_usec/1000) :
113                 -1;
114   errno = 0;
115   do {
116     pollrtn = poll( &pfd[0], maxpoll, timeout);
117   } while (pollrtn<0 && errno == EINTR);
118
119   FD_ZERO(fds);
120
121   for( i = 0; i < maxpoll; i++)
122     if( pfd[i].revents & POLLIN )
123       FD_SET(pfd[i].fd,fds);
124
125   return pollrtn;
126 #else /* USE_POLL */
127
128   struct timeval t2;
129   int selrtn;
130
131   do {
132     if (tval) memcpy((void *)&t2,(void *)tval,sizeof(t2));
133     errno = 0;
134     selrtn = select(maxfd,SELECT_CAST fds,NULL,NULL,tval?&t2:NULL);
135   } while (selrtn<0 && errno == EINTR);
136
137   return(selrtn);
138 }
139 #endif /* USE_POLL */
140 #endif /* NO_SELECT */
141
142 /*******************************************************************
143  A wrapper for usleep in case we don't have one.
144 ********************************************************************/
145
146 int sys_usleep(long usecs)
147 {
148 #ifndef HAVE_USLEEP
149   struct timeval tval;
150 #endif
151
152   /*
153    * We need this braindamage as the glibc usleep
154    * is not SPEC1170 complient... grumble... JRA.
155    */
156
157   if(usecs < 0 || usecs > 1000000) {
158     errno = EINVAL;
159     return -1;
160   }
161
162 #if HAVE_USLEEP
163   usleep(usecs);
164   return 0;
165 #else /* HAVE_USLEEP */
166   /*
167    * Fake it with select...
168    */
169   tval.tv_sec = 0;
170   tval.tv_usec = usecs/1000;
171   select(0,NULL,NULL,NULL,&tval);
172   return 0;
173 #endif /* HAVE_USLEEP */
174 }
175
176 /*******************************************************************
177 A stat() wrapper that will deal with 64 bit filesizes.
178 ********************************************************************/
179
180 int sys_stat(const char *fname,SMB_STRUCT_STAT *sbuf)
181 {
182         int ret;
183 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_STAT64)
184         ret = stat64(fname, sbuf);
185 #else
186         ret = stat(fname, sbuf);
187 #endif
188         /* we always want directories to appear zero size */
189         if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
190         return ret;
191 }
192
193 /*******************************************************************
194  An fstat() wrapper that will deal with 64 bit filesizes.
195 ********************************************************************/
196
197 int sys_fstat(int fd,SMB_STRUCT_STAT *sbuf)
198 {
199         int ret;
200 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FSTAT64)
201         ret = fstat64(fd, sbuf);
202 #else
203         ret = fstat(fd, sbuf);
204 #endif
205         /* we always want directories to appear zero size */
206         if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
207         return ret;
208 }
209
210 /*******************************************************************
211  An lstat() wrapper that will deal with 64 bit filesizes.
212 ********************************************************************/
213
214 int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf)
215 {
216         int ret;
217 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSTAT64)
218         ret = lstat64(fname, sbuf);
219 #else
220         ret = lstat(fname, sbuf);
221 #endif
222         /* we always want directories to appear zero size */
223         if (ret == 0 && S_ISDIR(sbuf->st_mode)) sbuf->st_size = 0;
224         return ret;
225 }
226
227 /*******************************************************************
228  An ftruncate() wrapper that will deal with 64 bit filesizes.
229 ********************************************************************/
230
231 int sys_ftruncate(int fd, SMB_OFF_T offset)
232 {
233 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_FTRUNCATE64)
234   return ftruncate64(fd, offset);
235 #else
236   return ftruncate(fd, offset);
237 #endif
238 }
239
240 /*******************************************************************
241  An lseek() wrapper that will deal with 64 bit filesizes.
242 ********************************************************************/
243
244 SMB_OFF_T sys_lseek(int fd, SMB_OFF_T offset, int whence)
245 {
246 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_LSEEK64)
247   return lseek64(fd, offset, whence);
248 #else
249   return lseek(fd, offset, whence);
250 #endif
251 }
252
253 /*******************************************************************
254  An fseek() wrapper that will deal with 64 bit filesizes.
255 ********************************************************************/
256
257 int sys_fseek(FILE *fp, SMB_OFF_T offset, int whence)
258 {
259 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEK64)
260   return fseek64(fp, offset, whence);
261 #elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FSEEKO64)
262   return fseeko64(fp, offset, whence);
263 #else
264   return fseek(fp, offset, whence);
265 #endif
266 }
267
268 /*******************************************************************
269  An ftell() wrapper that will deal with 64 bit filesizes.
270 ********************************************************************/
271
272 SMB_OFF_T sys_ftell(FILE *fp)
273 {
274 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELL64)
275   return (SMB_OFF_T)ftell64(fp);
276 #elif defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_FTELLO64)
277   return (SMB_OFF_T)ftello64(fp);
278 #else
279   return (SMB_OFF_T)ftell(fp);
280 #endif
281 }
282
283 /*******************************************************************
284  A creat() wrapper that will deal with 64 bit filesizes.
285 ********************************************************************/
286
287 int sys_creat(const char *path, mode_t mode)
288 {
289 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_CREAT64)
290   return creat64(path, mode);
291 #else
292   /*
293    * If creat64 isn't defined then ensure we call a potential open64.
294    * JRA.
295    */
296   return sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
297 #endif
298 }
299
300 /*******************************************************************
301  An open() wrapper that will deal with 64 bit filesizes.
302 ********************************************************************/
303
304 int sys_open(const char *path, int oflag, mode_t mode)
305 {
306 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OPEN64)
307   return open64(path, oflag, mode);
308 #else
309   return open(path, oflag, mode);
310 #endif
311 }
312
313 /*******************************************************************
314  An fopen() wrapper that will deal with 64 bit filesizes.
315 ********************************************************************/
316
317 FILE *sys_fopen(const char *path, const char *type)
318 {
319 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_FOPEN64)
320   return fopen64(path, type);
321 #else
322   return fopen(path, type);
323 #endif
324 }
325
326 #if defined(HAVE_MMAP)
327
328 /*******************************************************************
329  An mmap() wrapper that will deal with 64 bit filesizes.
330 ********************************************************************/
331
332 void *sys_mmap(void *addr, size_t len, int prot, int flags, int fd, SMB_OFF_T offset)
333 {
334 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(LARGE_SMB_OFF_T) && defined(HAVE_MMAP64)
335   return mmap64(addr, len, prot, flags, fd, offset);
336 #else
337   return mmap(addr, len, prot, flags, fd, offset);
338 #endif
339 }
340
341 #endif /* HAVE_MMAP */
342
343 /*******************************************************************
344  A readdir wrapper that will deal with 64 bit filesizes.
345 ********************************************************************/
346
347 SMB_STRUCT_DIRENT *sys_readdir(DIR *dirp)
348 {
349 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_READDIR64)
350   return readdir64(dirp);
351 #else
352   return readdir(dirp);
353 #endif
354 }
355
356 /*******************************************************************
357 The wait() calls vary between systems
358 ********************************************************************/
359
360 int sys_waitpid(pid_t pid,int *status,int options)
361 {
362 #ifdef HAVE_WAITPID
363   return waitpid(pid,status,options);
364 #else /* HAVE_WAITPID */
365   return wait4(pid, status, options, NULL);
366 #endif /* HAVE_WAITPID */
367 }
368
369 /*******************************************************************
370 system wrapper for getwd
371 ********************************************************************/
372 char *sys_getwd(char *s)
373 {
374     char *wd;
375 #ifdef HAVE_GETCWD
376     wd = (char *)getcwd(s, sizeof (pstring));
377 #else
378     wd = (char *)getwd(s);
379 #endif
380     return wd;
381 }
382
383 /*******************************************************************
384 chown isn't used much but OS/2 doesn't have it
385 ********************************************************************/
386
387 int sys_chown(const char *fname,uid_t uid,gid_t gid)
388 {
389 #ifndef HAVE_CHOWN
390         static int done;
391         if (!done) {
392                 DEBUG(1,("WARNING: no chown!\n"));
393                 done=1;
394         }
395 #else
396         return(chown(fname,uid,gid));
397 #endif
398 }
399
400 /*******************************************************************
401 os/2 also doesn't have chroot
402 ********************************************************************/
403 int sys_chroot(const char *dname)
404 {
405 #ifndef HAVE_CHROOT
406         static int done;
407         if (!done) {
408                 DEBUG(1,("WARNING: no chroot!\n"));
409                 done=1;
410         }
411 #else
412         return(chroot(dname));
413 #endif
414 }
415
416 /**************************************************************************
417 A wrapper for gethostbyname() that tries avoids looking up hostnames 
418 in the root domain, which can cause dial-on-demand links to come up for no
419 apparent reason.
420 ****************************************************************************/
421 struct hostent *sys_gethostbyname(const char *name)
422 {
423 #ifdef REDUCE_ROOT_DNS_LOOKUPS
424   char query[256], hostname[256];
425   char *domain;
426
427   /* Does this name have any dots in it? If so, make no change */
428
429   if (strchr(name, '.'))
430     return(gethostbyname(name));
431
432   /* Get my hostname, which should have domain name 
433      attached. If not, just do the gethostname on the
434      original string. 
435   */
436
437   gethostname(hostname, sizeof(hostname) - 1);
438   hostname[sizeof(hostname) - 1] = 0;
439   if ((domain = strchr(hostname, '.')) == NULL)
440     return(gethostbyname(name));
441
442   /* Attach domain name to query and do modified query.
443      If names too large, just do gethostname on the
444      original string.
445   */
446
447   if((strlen(name) + strlen(domain)) >= sizeof(query))
448     return(gethostbyname(name));
449
450   slprintf(query, sizeof(query)-1, "%s%s", name, domain);
451   return(gethostbyname(query));
452 #else /* REDUCE_ROOT_DNS_LOOKUPS */
453   return(gethostbyname(name));
454 #endif /* REDUCE_ROOT_DNS_LOOKUPS */
455 }
456
457
458 /**************************************************************************
459  Try and abstract process capabilities (for systems that have them).
460 ****************************************************************************/
461
462 BOOL set_process_capability( uint32 cap_flag, BOOL enable )
463 {
464 #if defined(HAVE_IRIX_SPECIFIC_CAPABILITIES)
465   if(cap_flag == KERNEL_OPLOCK_CAPABILITY)
466   {
467     cap_t cap = cap_get_proc();
468
469     if (cap == NULL) {
470       DEBUG(0,("set_process_capability: cap_get_proc failed. Error was %s\n",
471             strerror(errno)));
472       return False;
473     }
474
475     if(enable)
476       cap->cap_effective |= CAP_NETWORK_MGT;
477     else
478       cap->cap_effective &= ~CAP_NETWORK_MGT;
479
480     if (cap_set_proc(cap) == -1) {
481       DEBUG(0,("set_process_capability: cap_set_proc failed. Error was %s\n",
482             strerror(errno)));
483       cap_free(cap);
484       return False;
485     }
486
487     cap_free(cap);
488
489     DEBUG(10,("set_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
490   }
491 #endif
492   return True;
493 }
494
495 /**************************************************************************
496  Try and abstract inherited process capabilities (for systems that have them).
497 ****************************************************************************/
498
499 BOOL set_inherited_process_capability( uint32 cap_flag, BOOL enable )
500 {
501 #if defined(HAVE_IRIX_SPECIFIC_CAPABILITIES)
502   if(cap_flag == KERNEL_OPLOCK_CAPABILITY)
503   {
504     cap_t cap = cap_get_proc();
505
506     if (cap == NULL) {
507       DEBUG(0,("set_inherited_process_capability: cap_get_proc failed. Error was %s\n",
508             strerror(errno)));
509       return False;
510     }
511
512     if(enable)
513       cap->cap_inheritable |= CAP_NETWORK_MGT;
514     else
515       cap->cap_inheritable &= ~CAP_NETWORK_MGT;
516
517     if (cap_set_proc(cap) == -1) {
518       DEBUG(0,("set_inherited_process_capability: cap_set_proc failed. Error was %s\n", 
519             strerror(errno)));
520       cap_free(cap);
521       return False;
522     }
523
524     cap_free(cap);
525
526     DEBUG(10,("set_inherited_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
527   }
528 #endif
529   return True;
530 }
531
532 /**************************************************************************
533  Wrapper for random().
534 ****************************************************************************/
535
536 long sys_random(void)
537 {
538 #if defined(HAVE_RANDOM)
539   return (long)random();
540 #elif defined(HAVE_RAND)
541   return (long)rand();
542 #else
543   DEBUG(0,("Error - no random function available !\n"));
544   exit(1);
545 #endif
546 }
547
548 /**************************************************************************
549  Wrapper for srandom().
550 ****************************************************************************/
551
552 void sys_srandom(unsigned int seed)
553 {
554 #if defined(HAVE_SRANDOM)
555   srandom(seed);
556 #elif defined(HAVE_SRAND)
557   srand(seed);
558 #else
559   DEBUG(0,("Error - no srandom function available !\n"));
560   exit(1);
561 #endif
562 }
563
564 /**************************************************************************
565  Returns equivalent to NGROUPS_MAX - using sysconf if needed.
566 ****************************************************************************/
567
568 int groups_max(void)
569 {
570 #if defined(SYSCONF_SC_NGROUPS_MAX)
571   int ret = sysconf(_SC_NGROUPS_MAX);
572   return (ret == -1) ? NGROUPS_MAX : ret;
573 #else
574   return NGROUPS_MAX;
575 #endif
576 }
577
578 /**************************************************************************
579  Wrapper for getgroups. Deals with broken (int) case.
580 ****************************************************************************/
581
582 int sys_getgroups(int setlen, gid_t *gidset)
583 {
584 #if !defined(HAVE_BROKEN_GETGROUPS)
585   return getgroups(setlen, gidset);
586 #else
587
588   GID_T gid;
589   GID_T *group_list;
590   int i, ngroups;
591
592   if(setlen == 0) {
593     return getgroups(setlen, &gid);
594   }
595
596   /*
597    * Broken case. We need to allocate a
598    * GID_T array of size setlen.
599    */
600
601   if(setlen < 0) {
602     errno = EINVAL; 
603     return -1;
604   } 
605
606   if (setlen == 0)
607     setlen = groups_max();
608
609   if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
610     DEBUG(0,("sys_getgroups: Malloc fail.\n"));
611     return -1;
612   }
613
614   if((ngroups = getgroups(setlen, group_list)) < 0) {
615     int saved_errno = errno;
616     free((char *)group_list);
617     errno = saved_errno;
618     return -1;
619   }
620
621   for(i = 0; i < ngroups; i++)
622     gidset[i] = (gid_t)group_list[i];
623
624   free((char *)group_list);
625   return ngroups;
626 #endif /* HAVE_BROKEN_GETGROUPS */
627 }
628
629 #ifdef HAVE_SETGROUPS
630
631 /**************************************************************************
632  Wrapper for setgroups. Deals with broken (int) case. Automatically used
633  if we have broken getgroups.
634 ****************************************************************************/
635
636 int sys_setgroups(int setlen, gid_t *gidset)
637 {
638 #if !defined(HAVE_BROKEN_GETGROUPS)
639   return setgroups(setlen, gidset);
640 #else
641
642   GID_T *group_list;
643   int i ; 
644
645   if (setlen == 0)
646     return 0 ;
647
648   if (setlen < 0 || setlen > groups_max()) {
649     errno = EINVAL; 
650     return -1;   
651   }
652
653   /*
654    * Broken case. We need to allocate a
655    * GID_T array of size setlen.
656    */
657
658   if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
659     DEBUG(0,("sys_setgroups: Malloc fail.\n"));
660     return -1;    
661   }
662  
663   for(i = 0; i < setlen; i++) 
664     group_list[i] = (GID_T) gidset[i]; 
665
666   if(setgroups(setlen, group_list) != 0) {
667     int saved_errno = errno;
668     free((char *)group_list);
669     errno = saved_errno;
670     return -1;
671   }
672  
673   free((char *)group_list);
674   return 0 ;
675 #endif /* HAVE_BROKEN_GETGROUPS */
676 }
677
678 #endif /* HAVE_SETGROUPS */
679
680 /*
681  * We only wrap pw_name and pw_passwd for now as these
682  * are the only potentially modified fields.
683  */
684
685 /**************************************************************************
686  Helper function for getpwnam/getpwuid wrappers.
687 ****************************************************************************/
688
689 static struct passwd *setup_pwret(struct passwd *pass)
690 {
691         static pstring pw_name;
692         static pstring pw_passwd;
693         static struct passwd pw_ret;
694
695         if (pass == NULL)
696         {
697                 return NULL;
698         }
699
700         memcpy((char *)&pw_ret, pass, sizeof(struct passwd));
701
702         if (pass->pw_name)
703         {
704                 pw_ret.pw_name = pw_name;
705                 pstrcpy(pw_ret.pw_name, pass->pw_name);
706         }
707
708         if (pass->pw_passwd)
709         {
710                 pw_ret.pw_passwd = pw_passwd;
711                 pstrcpy(pw_ret.pw_passwd, pass->pw_passwd);
712         }
713
714         return &pw_ret;
715 }
716
717 /**************************************************************************
718  Wrapper for getpwnam(). Always returns a static that can be modified.
719 ****************************************************************************/
720
721 struct passwd *sys_getpwnam(const char *name)
722 {
723         return setup_pwret(getpwnam(name));
724 }
725
726 /**************************************************************************
727  Wrapper for getpwuid(). Always returns a static that can be modified.
728 ****************************************************************************/
729
730 struct passwd *sys_getpwuid(uid_t uid)
731 {
732         return setup_pwret(getpwuid(uid));
733 }
734
735 /**************************************************************************
736  The following are the UNICODE versions of *all* system interface functions
737  called within Samba. Ok, ok, the exceptions are the gethostbyXX calls,
738  which currently are left as ascii as they are not used other than in name
739  resolution.
740 ****************************************************************************/
741
742 /**************************************************************************
743  Wide stat. Just narrow and call sys_xxx.
744 ****************************************************************************/
745
746 int wsys_stat(const smb_ucs2_t *wfname,SMB_STRUCT_STAT *sbuf)
747 {
748         pstring fname;
749         return sys_stat(unicode_to_unix(fname,wfname,sizeof(fname)), sbuf);
750 }
751
752 /**************************************************************************
753  Wide lstat. Just narrow and call sys_xxx.
754 ****************************************************************************/
755
756 int wsys_lstat(const smb_ucs2_t *wfname,SMB_STRUCT_STAT *sbuf)
757 {
758         pstring fname;
759         return sys_lstat(unicode_to_unix(fname,wfname,sizeof(fname)), sbuf);
760 }
761
762 /**************************************************************************
763  Wide creat. Just narrow and call sys_xxx.
764 ****************************************************************************/
765
766 int wsys_creat(const smb_ucs2_t *wfname, mode_t mode)
767 {
768         pstring fname;
769         return sys_creat(unicode_to_unix(fname,wfname,sizeof(fname)), mode);
770 }
771
772 /**************************************************************************
773  Wide open. Just narrow and call sys_xxx.
774 ****************************************************************************/
775
776 int wsys_open(const smb_ucs2_t *wfname, int oflag, mode_t mode)
777 {
778         pstring fname;
779         return sys_open(unicode_to_unix(fname,wfname,sizeof(fname)), oflag, mode);
780 }
781
782 /**************************************************************************
783  Wide fopen. Just narrow and call sys_xxx.
784 ****************************************************************************/
785
786 FILE *wsys_fopen(const smb_ucs2_t *wfname, const char *type)
787 {
788         pstring fname;
789         return sys_fopen(unicode_to_unix(fname,wfname,sizeof(fname)), type);
790 }
791
792 /**************************************************************************
793  Wide opendir. Just narrow and call sys_xxx.
794 ****************************************************************************/
795
796 DIR *wsys_opendir(const smb_ucs2_t *wfname)
797 {
798         pstring fname;
799         return opendir(unicode_to_unix(fname,wfname,sizeof(fname)));
800 }
801
802 /**************************************************************************
803  Wide readdir. Return a structure pointer containing a wide filename.
804 ****************************************************************************/
805
806 SMB_STRUCT_WDIRENT *wsys_readdir(DIR *dirp)
807 {
808         static SMB_STRUCT_WDIRENT retval;
809         SMB_STRUCT_DIRENT *dirval = sys_readdir(dirp);
810
811         if(!dirval)
812                 return NULL;
813
814         /*
815          * The only POSIX defined member of this struct is d_name.
816          */
817
818         unix_to_unicode(retval.d_name,dirval->d_name,sizeof(retval.d_name));
819
820         return &retval;
821 }
822
823 /**************************************************************************
824  Wide getwd. Call sys_xxx and widen. Assumes s points to a wpstring.
825 ****************************************************************************/
826
827 smb_ucs2_t *wsys_getwd(smb_ucs2_t *s)
828 {
829         pstring fname;
830         char *p = sys_getwd(fname);
831
832         if(!p)
833                 return NULL;
834
835         return unix_to_unicode(s, p, sizeof(wpstring));
836 }
837
838 /**************************************************************************
839  Wide chown. Just narrow and call sys_xxx.
840 ****************************************************************************/
841
842 int wsys_chown(const smb_ucs2_t *wfname, uid_t uid, gid_t gid)
843 {
844         pstring fname;
845         return chown(unicode_to_unix(fname,wfname,sizeof(fname)), uid, gid);
846 }
847
848 /**************************************************************************
849  Wide chroot. Just narrow and call sys_xxx.
850 ****************************************************************************/
851
852 int wsys_chroot(const smb_ucs2_t *wfname)
853 {
854         pstring fname;
855         return chroot(unicode_to_unix(fname,wfname,sizeof(fname)));
856 }
857
858 /**************************************************************************
859  Wide getpwnam. Return a structure pointer containing wide names.
860 ****************************************************************************/
861
862 SMB_STRUCT_WPASSWD *wsys_getpwnam(const smb_ucs2_t *wname)
863 {
864         static SMB_STRUCT_WPASSWD retval;
865         fstring name;
866         struct passwd *pwret = sys_getpwnam(unicode_to_unix(name,wname,sizeof(name)));
867
868         if(!pwret)
869                 return NULL;
870
871         unix_to_unicode(retval.pw_name, pwret->pw_name, sizeof(retval.pw_name));
872         retval.pw_passwd = pwret->pw_passwd;
873         retval.pw_uid = pwret->pw_uid;
874         retval.pw_gid = pwret->pw_gid;
875         unix_to_unicode(retval.pw_gecos, pwret->pw_gecos, sizeof(retval.pw_gecos));
876         unix_to_unicode(retval.pw_dir, pwret->pw_dir, sizeof(retval.pw_dir));
877         unix_to_unicode(retval.pw_shell, pwret->pw_shell, sizeof(retval.pw_shell));
878
879         return &retval;
880 }
881
882 /**************************************************************************
883  Wide getpwuid. Return a structure pointer containing wide names.
884 ****************************************************************************/
885
886 SMB_STRUCT_WPASSWD *wsys_getpwuid(uid_t uid)
887 {
888         static SMB_STRUCT_WPASSWD retval;
889         struct passwd *pwret = sys_getpwuid(uid);
890
891         if(!pwret)
892                 return NULL;
893
894         unix_to_unicode(retval.pw_name, pwret->pw_name, sizeof(retval.pw_name));
895         retval.pw_passwd = pwret->pw_passwd;
896         retval.pw_uid = pwret->pw_uid;
897         retval.pw_gid = pwret->pw_gid;
898         unix_to_unicode(retval.pw_gecos, pwret->pw_gecos, sizeof(retval.pw_gecos));
899         unix_to_unicode(retval.pw_dir, pwret->pw_dir, sizeof(retval.pw_dir));
900         unix_to_unicode(retval.pw_shell, pwret->pw_shell, sizeof(retval.pw_shell));
901
902         return &retval;
903 }
904
905 /**************************************************************************
906  Extract a command into an arg list. Uses a static pstring for storage.
907  Caller frees returned arg list (which contains pointers into the static pstring).
908 ****************************************************************************/
909
910 static char **extract_args(const char *command)
911 {
912         static pstring trunc_cmd;
913         char *ptr;
914         int argcl;
915         char **argl = NULL;
916         int i;
917
918         pstrcpy(trunc_cmd, command);
919
920         if(!(ptr = strtok(trunc_cmd, " \t"))) {
921                 errno = EINVAL;
922                 return NULL;
923         }
924
925         /*
926          * Count the args.
927          */
928
929         for( argcl = 1; ptr; ptr = strtok(NULL, " \t"))
930                 argcl++;
931
932         if((argl = (char **)malloc((argcl + 1) * sizeof(char *))) == NULL)
933                 return NULL;
934
935         /*
936          * Now do the extraction.
937          */
938
939         pstrcpy(trunc_cmd, command);
940
941         ptr = strtok(trunc_cmd, " \t");
942         i = 0;
943         argl[i++] = ptr;
944
945         while((ptr = strtok(NULL, " \t")) != NULL)
946                 argl[i++] = ptr;
947
948         argl[i++] = NULL;
949         return argl;
950 }
951
952 /**************************************************************************
953  Wrapper for popen. Safer as it doesn't search a path.
954  Modified from the glibc sources.
955 ****************************************************************************/
956
957 typedef struct _popen_list
958 {
959         FILE *fp;
960         pid_t child_pid;
961         struct _popen_list *next;
962 } popen_list;
963
964 static popen_list *popen_chain;
965
966 FILE *sys_popen(const char *command, const char *mode, BOOL paranoid)
967 {
968         int parent_end, child_end;
969         int pipe_fds[2];
970     popen_list *entry = NULL;
971         char **argl = NULL;
972
973         if (pipe(pipe_fds) < 0)
974                 return NULL;
975
976         if (mode[0] == 'r' && mode[1] == '\0') {
977                 parent_end = pipe_fds[0];
978                 child_end = pipe_fds[1];
979     } else if (mode[0] == 'w' && mode[1] == '\0') {
980                 parent_end = pipe_fds[1];
981                 child_end = pipe_fds[0];
982     } else {
983                 errno = EINVAL;
984                 goto err_exit;
985     }
986
987         if (!*command) {
988                 errno = EINVAL;
989                 goto err_exit;
990         }
991
992         if((entry = (popen_list *)malloc(sizeof(popen_list))) == NULL)
993                 goto err_exit;
994
995         /*
996          * Extract the command and args into a NULL terminated array.
997          */
998
999         if(!(argl = extract_args(command)))
1000                 goto err_exit;
1001
1002         if(paranoid) {
1003                 /*
1004                  * Do some basic paranioa checks. Do a stat on the parent
1005                  * directory and ensure it's not world writable. Do a stat
1006                  * on the file itself and ensure it's owned by root and not
1007                  * world writable. Note this does *not* prevent symlink races,
1008                  * but is a generic "don't let the admin screw themselves"
1009                  * check.
1010                  */
1011
1012                 SMB_STRUCT_STAT st;
1013                 pstring dir_name;
1014                 char *ptr = strrchr(argl[0], '/');
1015         
1016                 if(sys_stat(argl[0], &st) != 0)
1017                         goto err_exit;
1018
1019                 if((st.st_uid != (uid_t)0) || (st.st_mode & S_IWOTH)) {
1020                         errno = EACCES;
1021                         goto err_exit;
1022                 }
1023                 
1024                 if(!ptr) {
1025                         /*
1026                          * No '/' in name - use current directory.
1027                          */
1028                         pstrcpy(dir_name, ".");
1029                 } else {
1030
1031                         /*
1032                          * Copy into a pstring and do the checks
1033                          * again (in case we were length tuncated).
1034                          */
1035
1036                         pstrcpy(dir_name, argl[0]);
1037                         ptr = strrchr(dir_name, '/');
1038                         if(!ptr) {
1039                                 errno = EINVAL;
1040                                 goto err_exit;
1041                         }
1042                         if(strcmp(dir_name, "/") != 0)
1043                                 *ptr = '\0';
1044                         if(!dir_name[0])
1045                                 pstrcpy(dir_name, ".");
1046                 }
1047
1048                 if(sys_stat(argl[0], &st) != 0)
1049                         goto err_exit;
1050
1051                 if(!S_ISDIR(st.st_mode) || (st.st_mode & S_IWOTH)) {
1052                         errno = EACCES;
1053                         goto err_exit;
1054                 }
1055         }
1056
1057         entry->child_pid = fork();
1058
1059         if (entry->child_pid == -1) {
1060
1061                 /*
1062                  * Error !
1063                  */
1064
1065                 goto err_exit;
1066         }
1067
1068         if (entry->child_pid == 0) {
1069
1070                 /*
1071                  * Child !
1072                  */
1073
1074                 int child_std_end = (mode[0] == 'r') ? STDOUT_FILENO : STDIN_FILENO;
1075                 popen_list *p;
1076
1077                 close(parent_end);
1078                 if (child_end != child_std_end) {
1079                         dup2 (child_end, child_std_end);
1080                         close (child_end);
1081                 }
1082
1083                 /*
1084                  * POSIX.2:  "popen() shall ensure that any streams from previous
1085                  * popen() calls that remain open in the parent process are closed
1086                  * in the new child process."
1087                  */
1088
1089                 for (p = popen_chain; p; p = p->next)
1090                         close(fileno(p->fp));
1091
1092                 execv(argl[0], argl);
1093                 _exit (127);
1094         }
1095
1096         /*
1097          * Parent.
1098          */
1099
1100         close (child_end);
1101         free((char *)argl);
1102
1103         /*
1104          * Create the FILE * representing this fd.
1105          */
1106     entry->fp = fdopen(parent_end, mode);
1107
1108         /* Link into popen_chain. */
1109         entry->next = popen_chain;
1110         popen_chain = entry;
1111
1112         return entry->fp;
1113
1114 err_exit:
1115
1116         if(entry)
1117                 free((char *)entry);
1118         if(argl)
1119                 free((char *)argl);
1120         close(pipe_fds[0]);
1121         close(pipe_fds[1]);
1122         return NULL;
1123 }
1124
1125 /**************************************************************************
1126  Wrapper for pclose. Modified from the glibc sources.
1127 ****************************************************************************/
1128
1129 int sys_pclose( FILE *fp)
1130 {
1131         int wstatus;
1132         popen_list **ptr = &popen_chain;
1133         popen_list *entry = NULL;
1134         pid_t wait_pid;
1135         int status = -1;
1136
1137         /* Unlink from popen_chain. */
1138         for ( ; *ptr != NULL; ptr = &(*ptr)->next) {
1139                 if ((*ptr)->fp == fp) {
1140                         entry = *ptr;
1141                         *ptr = (*ptr)->next;
1142                         status = 0;
1143                         break;
1144                 }
1145         }
1146
1147         if (status < 0 || close(fileno(entry->fp)) < 0)
1148                 return -1;
1149
1150         /*
1151          * As Samba is catching and eating child process
1152          * exits we don't really care about the child exit
1153          * code, a -1 with errno = ECHILD will do fine for us.
1154          */
1155
1156         do {
1157                 wait_pid = sys_waitpid (entry->child_pid, &wstatus, 0);
1158         } while (wait_pid == -1 && errno == EINTR);
1159
1160         free((char *)entry);
1161
1162         if (wait_pid == -1)
1163                 return -1;
1164         return wstatus;
1165 }