mods to allow inter-domain trust accounts to be added to SAM database
[samba.git] / source3 / lib / util.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Samba utility functions
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 #if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
25 #ifdef WITH_NISPLUS_HOME
26 #include <rpcsvc/nis.h>
27 #else
28 #include "rpcsvc/ypclnt.h"
29 #endif
30 #endif
31
32 #ifdef WITH_SSL
33 #include <ssl.h>
34 #undef Realloc  /* SSLeay defines this and samba has a function of this name */
35 extern SSL  *ssl;
36 extern int  sslFd;
37 #endif  /* WITH_SSL */
38
39 pstring scope = "";
40
41 extern int DEBUGLEVEL;
42
43 int Protocol = PROTOCOL_COREPLUS;
44
45 /* a default finfo structure to ensure all fields are sensible */
46 file_info def_finfo = {-1,0,0,0,0,0,0,""};
47
48 /* the client file descriptor */
49 extern int Client;
50
51 /* this is used by the chaining code */
52 int chain_size = 0;
53
54 int trans_num = 0;
55
56 /*
57    case handling on filenames 
58 */
59 int case_default = CASE_LOWER;
60
61 /* the following control case operations - they are put here so the
62    client can link easily */
63 BOOL case_sensitive;
64 BOOL case_preserve;
65 BOOL use_mangled_map = False;
66 BOOL short_case_preserve;
67 BOOL case_mangle;
68
69 fstring remote_machine="";
70 fstring local_machine="";
71 fstring remote_arch="UNKNOWN";
72 static enum remote_arch_types ra_type = RA_UNKNOWN;
73 fstring remote_proto="UNKNOWN";
74 pstring myhostname="";
75 pstring user_socket_options="";   
76
77 pstring sesssetup_user="";
78 pstring samlogon_user="";
79
80 BOOL sam_logon_in_ssb = False;
81
82 pstring global_myname = "";
83 fstring global_myworkgroup = "";
84 char **my_netbios_names;
85
86 static char *filename_dos(char *path,char *buf);
87
88
89 /*************************************************************
90  initialise password databases, domain names, domain sid.
91 **************************************************************/
92 BOOL init_myworkgroup(void)
93 {
94         fstrcpy(global_myworkgroup, lp_workgroup());
95
96         if (strequal(global_myworkgroup,"*"))
97         {
98                 DEBUG(0,("ERROR: a workgroup name of * is no longer supported\n"));
99                 return False;
100         }
101         return True;
102 }
103
104 /****************************************************************************
105   find a suitable temporary directory. The result should be copied immediately
106   as it may be overwritten by a subsequent call
107   ****************************************************************************/
108 char *tmpdir(void)
109 {
110   char *p;
111   if ((p = getenv("TMPDIR"))) {
112     return p;
113   }
114   return "/tmp";
115 }
116
117 /****************************************************************************
118 determine whether we are in the specified group
119 ****************************************************************************/
120
121 BOOL in_group(gid_t group, gid_t current_gid, int ngroups, gid_t *groups)
122 {
123         int i;
124
125         if (group == current_gid) return(True);
126
127         for (i=0;i<ngroups;i++)
128                 if (group == groups[i])
129                         return(True);
130
131         return(False);
132 }
133
134
135 /****************************************************************************
136 gets either a hex number (0xNNN) or decimal integer (NNN).
137 ****************************************************************************/
138 uint32 get_number(const char *tmp)
139 {
140         if (strnequal(tmp, "0x", 2))
141         {
142                 return strtoul(tmp, (char**)NULL, 16);
143         }
144         else
145         {
146                 return strtoul(tmp, (char**)NULL, 10);
147         }
148 }
149
150 /****************************************************************************
151 like atoi but gets the value up to the separater character
152 ****************************************************************************/
153 char *Atoic(char *p, int *n, char *c)
154 {
155         if (!isdigit(*p))
156         {
157                 DEBUG(5, ("Atoic: malformed number\n"));
158                 return NULL;
159         }
160
161         (*n) = (int)get_number(p);
162
163         if (strnequal(p, "0x", 2))
164         {
165                 p += 2;
166         }
167
168         while ((*p) && isdigit(*p))
169         {
170                 p++;
171         }
172
173         if (strchr(c, *p) == NULL)
174         {
175                 DEBUG(5, ("Atoic: no separator characters (%s) not found\n", c));
176                 return NULL;
177         }
178
179         return p;
180 }
181
182 uint32 *add_num_to_list(uint32 **num, int *count, int val)
183 {
184         (*num) = Realloc((*num), ((*count)+1) * sizeof(uint32));
185         if ((*num) == NULL)
186         {
187                 return NULL;
188         }
189         (*num)[(*count)] = val;
190         (*count)++;
191
192         return (*num);
193 }
194
195 /*************************************************************************
196  reads a list of numbers
197  *************************************************************************/
198 char *get_numlist(char *p, uint32 **num, int *count)
199 {
200         int val;
201
202         if (num == NULL || count == NULL)
203         {
204                 return NULL;
205         }
206
207         (*count) = 0;
208         (*num  ) = NULL;
209
210         while ((p = Atoic(p, &val, ":,")) != NULL && (*p) != ':')
211         {
212                 if (add_num_to_list(num, count, val) == NULL)
213                 {
214                         return NULL;
215                 }
216                 p++;
217         }
218
219         return p;
220 }
221
222 /*******************************************************************
223 copy an IP address from one buffer to another
224 ********************************************************************/
225 void putip(void *dest,void *src)
226 {
227   memcpy(dest,src,4);
228 }
229
230
231 #define TRUNCATE_NETBIOS_NAME 1
232
233 /*******************************************************************
234  convert, possibly using a stupid microsoft-ism which has destroyed
235  the transport independence of netbios (for CIFS vendors that usually
236  use the Win95-type methods, not for NT to NT communication, which uses
237  DCE/RPC and therefore full-length unicode strings...) a dns name into
238  a netbios name.
239
240  the netbios name (NOT necessarily null-terminated) is truncated to 15
241  characters.
242
243  ******************************************************************/
244 char *dns_to_netbios_name(char *dns_name)
245 {
246         static char netbios_name[16];
247         int i;
248         StrnCpy(netbios_name, dns_name, 15);
249         netbios_name[15] = 0;
250         
251 #ifdef TRUNCATE_NETBIOS_NAME
252         /* ok.  this is because of a stupid microsoft-ism.  if the called host
253            name contains a '.', microsoft clients expect you to truncate the
254            netbios name up to and including the '.'  this even applies, by
255            mistake, to workgroup (domain) names, which is _really_ daft.
256          */
257         for (i = 15; i >= 0; i--)
258         {
259                 if (netbios_name[i] == '.')
260                 {
261                         netbios_name[i] = 0;
262                         break;
263                 }
264         }
265 #endif /* TRUNCATE_NETBIOS_NAME */
266
267         return netbios_name;
268 }
269
270
271 /****************************************************************************
272 interpret the weird netbios "name". Return the name type
273 ****************************************************************************/
274 static int name_interpret(char *in,char *out)
275 {
276   int ret;
277   int len = (*in++) / 2;
278
279   *out=0;
280
281   if (len > 30 || len<1) return(0);
282
283   while (len--)
284     {
285       if (in[0] < 'A' || in[0] > 'P' || in[1] < 'A' || in[1] > 'P') {
286         *out = 0;
287         return(0);
288       }
289       *out = ((in[0]-'A')<<4) + (in[1]-'A');
290       in += 2;
291       out++;
292     }
293   *out = 0;
294   ret = out[-1];
295
296 #ifdef NETBIOS_SCOPE
297   /* Handle any scope names */
298   while(*in) 
299     {
300       *out++ = '.'; /* Scope names are separated by periods */
301       len = *(unsigned char *)in++;
302       StrnCpy(out, in, len);
303       out += len;
304       *out=0;
305       in += len;
306     }
307 #endif
308   return(ret);
309 }
310
311 /****************************************************************************
312 mangle a name into netbios format
313
314   Note:  <Out> must be (33 + strlen(scope) + 2) bytes long, at minimum.
315 ****************************************************************************/
316 int name_mangle( char *In, char *Out, char name_type )
317   {
318   int   i;
319   int   c;
320   int   len;
321   char  buf[20];
322   char *p = Out;
323
324   /* Safely copy the input string, In, into buf[]. */
325   (void)memset( buf, 0, 20 );
326   if (strcmp(In,"*") == 0)
327     buf[0] = '*';
328   else
329     (void)slprintf( buf, sizeof(buf) - 1, "%-15.15s%c", In, name_type );
330
331   /* Place the length of the first field into the output buffer. */
332   p[0] = 32;
333   p++;
334
335   /* Now convert the name to the rfc1001/1002 format. */
336   for( i = 0; i < 16; i++ )
337     {
338     c = toupper( buf[i] );
339     p[i*2]     = ( (c >> 4) & 0x000F ) + 'A';
340     p[(i*2)+1] = (c & 0x000F) + 'A';
341     }
342   p += 32;
343   p[0] = '\0';
344
345   /* Add the scope string. */
346   for( i = 0, len = 0; NULL != scope; i++, len++ )
347     {
348     switch( scope[i] )
349       {
350       case '\0':
351         p[0]     = len;
352         if( len > 0 )
353           p[len+1] = 0;
354         return( name_len(Out) );
355       case '.':
356         p[0] = len;
357         p   += (len + 1);
358         len  = 0;
359         break;
360       default:
361         p[len+1] = scope[i];
362         break;
363       }
364     }
365
366   return( name_len(Out) );
367   } /* name_mangle */
368
369 /*******************************************************************
370   check if a file exists
371 ********************************************************************/
372 BOOL file_exist(char *fname,SMB_STRUCT_STAT *sbuf)
373 {
374   SMB_STRUCT_STAT st;
375   if (!sbuf) sbuf = &st;
376   
377   if (sys_stat(fname,sbuf) != 0) 
378     return(False);
379
380   return(S_ISREG(sbuf->st_mode));
381 }
382
383 /*******************************************************************
384   rename a unix file
385 ********************************************************************/
386 int file_rename(char *from, char *to)
387 {
388         int rcode = rename (from, to);
389
390         if (errno == EXDEV) 
391         {
392                 /* Rename across filesystems needed. */
393                 rcode = copy_reg (from, to);        
394         }
395         return rcode;
396 }
397
398 /*******************************************************************
399 check a files mod time
400 ********************************************************************/
401 time_t file_modtime(char *fname)
402 {
403   SMB_STRUCT_STAT st;
404   
405   if (sys_stat(fname,&st) != 0) 
406     return(0);
407
408   return(st.st_mtime);
409 }
410
411 /*******************************************************************
412   check if a directory exists
413 ********************************************************************/
414 BOOL directory_exist(char *dname,SMB_STRUCT_STAT *st)
415 {
416   SMB_STRUCT_STAT st2;
417   BOOL ret;
418
419   if (!st) st = &st2;
420
421   if (sys_stat(dname,st) != 0) 
422     return(False);
423
424   ret = S_ISDIR(st->st_mode);
425   if(!ret)
426     errno = ENOTDIR;
427   return ret;
428 }
429
430 /*******************************************************************
431 returns the size in bytes of the named file
432 ********************************************************************/
433 SMB_OFF_T file_size(char *file_name)
434 {
435   SMB_STRUCT_STAT buf;
436   buf.st_size = 0;
437   if(sys_stat(file_name,&buf) != 0)
438     return (SMB_OFF_T)-1;
439   return(buf.st_size);
440 }
441
442 /*******************************************************************
443 return a string representing an attribute for a file
444 ********************************************************************/
445 char *attrib_string(uint16 mode)
446 {
447   static fstring attrstr;
448
449   attrstr[0] = 0;
450
451   if (mode & aVOLID) fstrcat(attrstr,"V");
452   if (mode & aDIR) fstrcat(attrstr,"D");
453   if (mode & aARCH) fstrcat(attrstr,"A");
454   if (mode & aHIDDEN) fstrcat(attrstr,"H");
455   if (mode & aSYSTEM) fstrcat(attrstr,"S");
456   if (mode & aRONLY) fstrcat(attrstr,"R");        
457
458   return(attrstr);
459 }
460
461 /****************************************************************************
462   make a file into unix format
463 ****************************************************************************/
464 void unix_format(char *fname)
465 {
466   string_replace(fname,'\\','/');
467 }
468
469 /****************************************************************************
470   make a file into dos format
471 ****************************************************************************/
472 void dos_format(char *fname)
473 {
474   string_replace(fname,'/','\\');
475 }
476
477 /*******************************************************************
478   show a smb message structure
479 ********************************************************************/
480 void show_msg(char *buf)
481 {
482         int i;
483         int bcc=0;
484
485         if (DEBUGLEVEL < 5) return;
486
487         DEBUG(5,("size=%d\nsmb_com=0x%x\nsmb_rcls=%d\nsmb_reh=%d\nsmb_err=%d\nsmb_flg=%d\nsmb_flg2=%d\n",
488                         smb_len(buf),
489                         (int)CVAL(buf,smb_com),
490                         (int)CVAL(buf,smb_rcls),
491                         (int)CVAL(buf,smb_reh),
492                         (int)SVAL(buf,smb_err),
493                         (int)CVAL(buf,smb_flg),
494                         (int)SVAL(buf,smb_flg2)));
495         DEBUG(5,("smb_tid=%d\nsmb_pid=%d\nsmb_uid=%d\nsmb_mid=%d\nsmt_wct=%d\n",
496                         (int)SVAL(buf,smb_tid),
497                         (int)SVAL(buf,smb_pid),
498                         (int)SVAL(buf,smb_uid),
499                         (int)SVAL(buf,smb_mid),
500                         (int)CVAL(buf,smb_wct)));
501
502         for (i=0;i<(int)CVAL(buf,smb_wct);i++)
503         {
504                 DEBUG(5,("smb_vwv[%d]=%d (0x%X)\n",i,
505                         SVAL(buf,smb_vwv+2*i),SVAL(buf,smb_vwv+2*i)));
506         }
507
508         bcc = (int)SVAL(buf,smb_vwv+2*(CVAL(buf,smb_wct)));
509
510         DEBUG(5,("smb_bcc=%d\n",bcc));
511
512         if (DEBUGLEVEL < 10) return;
513
514         if (DEBUGLEVEL < 50)
515         {
516                 bcc = MIN(bcc, 512);
517         }
518
519         dump_data(10, smb_buf(buf), bcc);
520 }
521 /*******************************************************************
522   return the length of an smb packet
523 ********************************************************************/
524 int smb_len(char *buf)
525 {
526   return( PVAL(buf,3) | (PVAL(buf,2)<<8) | ((PVAL(buf,1)&1)<<16) );
527 }
528
529 /*******************************************************************
530   set the length of an smb packet
531 ********************************************************************/
532 void _smb_setlen(char *buf,int len)
533 {
534   buf[0] = 0;
535   buf[1] = (len&0x10000)>>16;
536   buf[2] = (len&0xFF00)>>8;
537   buf[3] = len&0xFF;
538 }
539
540 /*******************************************************************
541   set the length and marker of an smb packet
542 ********************************************************************/
543 void smb_setlen(char *buf,int len)
544 {
545   _smb_setlen(buf,len);
546
547   CVAL(buf,4) = 0xFF;
548   CVAL(buf,5) = 'S';
549   CVAL(buf,6) = 'M';
550   CVAL(buf,7) = 'B';
551 }
552
553 /*******************************************************************
554   setup the word count and byte count for a smb message
555 ********************************************************************/
556 int set_message(char *buf,int num_words,int num_bytes,BOOL zero)
557 {
558   if (zero)
559     bzero(buf + smb_size,num_words*2 + num_bytes);
560   CVAL(buf,smb_wct) = num_words;
561   SSVAL(buf,smb_vwv + num_words*SIZEOFWORD,num_bytes);  
562   smb_setlen(buf,smb_size + num_words*2 + num_bytes - 4);
563   return (smb_size + num_words*2 + num_bytes);
564 }
565
566 /*******************************************************************
567 return the number of smb words
568 ********************************************************************/
569 static int smb_numwords(char *buf)
570 {
571   return (CVAL(buf,smb_wct));
572 }
573
574 /*******************************************************************
575 return the size of the smb_buf region of a message
576 ********************************************************************/
577 int smb_buflen(char *buf)
578 {
579   return(SVAL(buf,smb_vwv0 + smb_numwords(buf)*2));
580 }
581
582 /*******************************************************************
583   return a pointer to the smb_buf data area
584 ********************************************************************/
585 static int smb_buf_ofs(char *buf)
586 {
587   return (smb_size + CVAL(buf,smb_wct)*2);
588 }
589
590 /*******************************************************************
591   return a pointer to the smb_buf data area
592 ********************************************************************/
593 char *smb_buf(char *buf)
594 {
595   return (buf + smb_buf_ofs(buf));
596 }
597
598 /*******************************************************************
599 return the SMB offset into an SMB buffer
600 ********************************************************************/
601 int smb_offset(char *p,char *buf)
602 {
603   return(PTR_DIFF(p,buf+4) + chain_size);
604 }
605
606
607
608 /*******************************************************************
609 reduce a file name, removing .. elements.
610 ********************************************************************/
611 void dos_clean_name(char *s)
612 {
613   char *p=NULL;
614
615   DEBUG(3,("dos_clean_name [%s]\n",s));
616
617   /* remove any double slashes */
618   string_sub(s, "\\\\", "\\");
619
620   while ((p = strstr(s,"\\..\\")) != NULL)
621     {
622       pstring s1;
623
624       *p = 0;
625       pstrcpy(s1,p+3);
626
627       if ((p=strrchr(s,'\\')) != NULL)
628         *p = 0;
629       else
630         *s = 0;
631       pstrcat(s,s1);
632     }  
633
634   trim_string(s,NULL,"\\..");
635
636   string_sub(s, "\\.\\", "\\");
637 }
638
639 /*******************************************************************
640 reduce a file name, removing .. elements. 
641 ********************************************************************/
642 void unix_clean_name(char *s)
643 {
644   char *p=NULL;
645
646   DEBUG(3,("unix_clean_name [%s]\n",s));
647
648   /* remove any double slashes */
649   string_sub(s, "//","/");
650
651   /* Remove leading ./ characters */
652   if(strncmp(s, "./", 2) == 0) {
653     trim_string(s, "./", NULL);
654     if(*s == 0)
655       pstrcpy(s,"./");
656   }
657
658   while ((p = strstr(s,"/../")) != NULL)
659     {
660       pstring s1;
661
662       *p = 0;
663       pstrcpy(s1,p+3);
664
665       if ((p=strrchr(s,'/')) != NULL)
666         *p = 0;
667       else
668         *s = 0;
669       pstrcat(s,s1);
670     }  
671
672   trim_string(s,NULL,"/..");
673 }
674
675 /*******************************************************************
676 reduce a file name, removing .. elements and checking that 
677 it is below dir in the heirachy. This uses GetWd() and so must be run
678 on the system that has the referenced file system.
679
680 widelinks are allowed if widelinks is true
681 ********************************************************************/
682
683 BOOL reduce_name(char *s,char *dir,BOOL widelinks)
684 {
685 #ifndef REDUCE_PATHS
686   return True;
687 #else
688   pstring dir2;
689   pstring wd;
690   pstring base_name;
691   pstring newname;
692   char *p=NULL;
693   BOOL relative = (*s != '/');
694
695   *dir2 = *wd = *base_name = *newname = 0;
696
697   if (widelinks)
698     {
699       unix_clean_name(s);
700       /* can't have a leading .. */
701       if (strncmp(s,"..",2) == 0 && (s[2]==0 || s[2]=='/'))
702         {
703           DEBUG(3,("Illegal file name? (%s)\n",s));
704           return(False);
705         }
706
707       if (strlen(s) == 0)
708         pstrcpy(s,"./");
709
710       return(True);
711     }
712   
713   DEBUG(3,("reduce_name [%s] [%s]\n",s,dir));
714
715   /* remove any double slashes */
716   string_sub(s,"//","/");
717
718   pstrcpy(base_name,s);
719   p = strrchr(base_name,'/');
720
721   if (!p)
722     return(True);
723
724   if (!dos_GetWd(wd))
725     {
726       DEBUG(0,("couldn't getwd for %s %s\n",s,dir));
727       return(False);
728     }
729
730   if (dos_ChDir(dir) != 0)
731     {
732       DEBUG(0,("couldn't chdir to %s\n",dir));
733       return(False);
734     }
735
736   if (!dos_GetWd(dir2))
737     {
738       DEBUG(0,("couldn't getwd for %s\n",dir));
739       dos_ChDir(wd);
740       return(False);
741     }
742
743
744     if (p && (p != base_name))
745       {
746         *p = 0;
747         if (strcmp(p+1,".")==0)
748           p[1]=0;
749         if (strcmp(p+1,"..")==0)
750           *p = '/';
751       }
752
753   if (dos_ChDir(base_name) != 0)
754     {
755       dos_ChDir(wd);
756       DEBUG(3,("couldn't chdir for %s %s basename=%s\n",s,dir,base_name));
757       return(False);
758     }
759
760   if (!dos_GetWd(newname))
761     {
762       dos_ChDir(wd);
763       DEBUG(2,("couldn't get wd for %s %s\n",s,dir2));
764       return(False);
765     }
766
767   if (p && (p != base_name))
768     {
769       pstrcat(newname,"/");
770       pstrcat(newname,p+1);
771     }
772
773   {
774     size_t l = strlen(dir2);    
775     if (dir2[l-1] == '/')
776       l--;
777
778     if (strncmp(newname,dir2,l) != 0)
779       {
780         dos_ChDir(wd);
781         DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n",s,dir2,newname,l));
782         return(False);
783       }
784
785     if (relative)
786       {
787         if (newname[l] == '/')
788           pstrcpy(s,newname + l + 1);
789         else
790           pstrcpy(s,newname+l);
791       }
792     else
793       pstrcpy(s,newname);
794   }
795
796   dos_ChDir(wd);
797
798   if (strlen(s) == 0)
799     pstrcpy(s,"./");
800
801   DEBUG(3,("reduced to %s\n",s));
802   return(True);
803 #endif
804 }
805
806 /****************************************************************************
807 expand some *s 
808 ****************************************************************************/
809 static void expand_one(char *Mask,int len)
810 {
811   char *p1;
812   while ((p1 = strchr(Mask,'*')) != NULL)
813     {
814       int lfill = (len+1) - strlen(Mask);
815       int l1= (p1 - Mask);
816       pstring tmp;
817       pstrcpy(tmp,Mask);  
818       memset(tmp+l1,'?',lfill);
819       pstrcpy(tmp + l1 + lfill,Mask + l1 + 1);  
820       pstrcpy(Mask,tmp);      
821     }
822 }
823
824 /****************************************************************************
825 parse out a directory name from a path name. Assumes dos style filenames.
826 ****************************************************************************/
827 static void dirname_dos(char *path,char *buf)
828 {
829         split_at_last_component(path, buf, '\\', NULL);
830 }
831
832
833 /****************************************************************************
834 expand a wildcard expression, replacing *s with ?s
835 ****************************************************************************/
836 void expand_mask(char *Mask,BOOL doext)
837 {
838   pstring mbeg,mext;
839   pstring dirpart;
840   pstring filepart;
841   BOOL hasdot = False;
842   char *p1;
843   BOOL absolute = (*Mask == '\\');
844
845   *mbeg = *mext = *dirpart = *filepart = 0;
846
847   /* parse the directory and filename */
848   if (strchr(Mask,'\\'))
849     dirname_dos(Mask,dirpart);
850
851   filename_dos(Mask,filepart);
852
853   pstrcpy(mbeg,filepart);
854   if ((p1 = strchr(mbeg,'.')) != NULL)
855     {
856       hasdot = True;
857       *p1 = 0;
858       p1++;
859       pstrcpy(mext,p1);
860     }
861   else
862     {
863       pstrcpy(mext,"");
864       if (strlen(mbeg) > 8)
865         {
866           pstrcpy(mext,mbeg + 8);
867           mbeg[8] = 0;
868         }
869     }
870
871   if (*mbeg == 0)
872     pstrcpy(mbeg,"????????");
873   if ((*mext == 0) && doext && !hasdot)
874     pstrcpy(mext,"???");
875
876   if (strequal(mbeg,"*") && *mext==0) 
877     pstrcpy(mext,"*");
878
879   /* expand *'s */
880   expand_one(mbeg,8);
881   if (*mext)
882     expand_one(mext,3);
883
884   pstrcpy(Mask,dirpart);
885   if (*dirpart || absolute) pstrcat(Mask,"\\");
886   pstrcat(Mask,mbeg);
887   pstrcat(Mask,".");
888   pstrcat(Mask,mext);
889
890   DEBUG(6,("Mask expanded to [%s]\n",Mask));
891 }  
892
893
894
895 /****************************************************************************
896   make a dir struct
897 ****************************************************************************/
898 void make_dir_struct(char *buf,char *mask,char *fname,SMB_OFF_T size,int mode,time_t date)
899 {  
900   char *p;
901   pstring mask2;
902
903   pstrcpy(mask2,mask);
904
905   if ((mode & aDIR) != 0)
906     size = 0;
907
908   memset(buf+1,' ',11);
909   if ((p = strchr(mask2,'.')) != NULL)
910     {
911       *p = 0;
912       memcpy(buf+1,mask2,MIN(strlen(mask2),8));
913       memcpy(buf+9,p+1,MIN(strlen(p+1),3));
914       *p = '.';
915     }
916   else
917     memcpy(buf+1,mask2,MIN(strlen(mask2),11));
918
919   bzero(buf+21,DIR_STRUCT_SIZE-21);
920   CVAL(buf,21) = mode;
921   put_dos_date(buf,22,date);
922   SSVAL(buf,26,size & 0xFFFF);
923   SSVAL(buf,28,(size >> 16)&0xFFFF);
924   StrnCpy(buf+30,fname,12);
925   if (!case_sensitive)
926     strupper(buf+30);
927   DEBUG(8,("put name [%s] into dir struct\n",buf+30));
928 }
929
930
931 /*******************************************************************
932 close the low 3 fd's and open dev/null in their place
933 ********************************************************************/
934 void close_low_fds(void)
935 {
936   int fd;
937   int i;
938   close(0); close(1); close(2);
939   /* try and use up these file descriptors, so silly
940      library routines writing to stdout etc won't cause havoc */
941   for (i=0;i<3;i++) {
942     fd = sys_open("/dev/null",O_RDWR,0);
943     if (fd < 0) fd = sys_open("/dev/null",O_WRONLY,0);
944     if (fd < 0) {
945       DEBUG(0,("Can't open /dev/null\n"));
946       return;
947     }
948     if (fd != i) {
949       DEBUG(0,("Didn't get file descriptor %d\n",i));
950       return;
951     }
952   }
953 }
954
955 /****************************************************************************
956 Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
957 else
958 if SYSV use O_NDELAY
959 if BSD use FNDELAY
960 ****************************************************************************/
961 int set_blocking(int fd, BOOL set)
962 {
963   int val;
964 #ifdef O_NONBLOCK
965 #define FLAG_TO_SET O_NONBLOCK
966 #else
967 #ifdef SYSV
968 #define FLAG_TO_SET O_NDELAY
969 #else /* BSD */
970 #define FLAG_TO_SET FNDELAY
971 #endif
972 #endif
973
974   if((val = fcntl(fd, F_GETFL, 0)) == -1)
975         return -1;
976   if(set) /* Turn blocking on - ie. clear nonblock flag */
977         val &= ~FLAG_TO_SET;
978   else
979     val |= FLAG_TO_SET;
980   return fcntl( fd, F_SETFL, val);
981 #undef FLAG_TO_SET
982 }
983
984
985 /*******************************************************************
986 find the difference in milliseconds between two struct timeval
987 values
988 ********************************************************************/
989 int TvalDiff(struct timeval *tvalold,struct timeval *tvalnew)
990 {
991   return((tvalnew->tv_sec - tvalold->tv_sec)*1000 + 
992          ((int)tvalnew->tv_usec - (int)tvalold->tv_usec)/1000);  
993 }
994
995
996
997 /****************************************************************************
998 transfer some data between two fd's
999 ****************************************************************************/
1000 SMB_OFF_T transfer_file(int infd,int outfd,SMB_OFF_T n,char *header,int headlen,int align)
1001 {
1002   static char *buf=NULL;  
1003   static int size=0;
1004   char *buf1,*abuf;
1005   SMB_OFF_T total = 0;
1006
1007   DEBUG(4,("transfer_file n=%.0f  (head=%d) called\n",(double)n,headlen));
1008
1009   if (size == 0) {
1010     size = lp_readsize();
1011     size = MAX(size,1024);
1012   }
1013
1014   while (!buf && size>0) {
1015     buf = (char *)Realloc(buf,size+8);
1016     if (!buf) size /= 2;
1017   }
1018
1019   if (!buf) {
1020     DEBUG(0,("Can't allocate transfer buffer!\n"));
1021     exit(1);
1022   }
1023
1024   abuf = buf + (align%8);
1025
1026   if (header)
1027     n += headlen;
1028
1029   while (n > 0)
1030   {
1031     int s = (int)MIN(n,(SMB_OFF_T)size);
1032     int ret,ret2=0;
1033
1034     ret = 0;
1035
1036     if (header && (headlen >= MIN(s,1024))) {
1037       buf1 = header;
1038       s = headlen;
1039       ret = headlen;
1040       headlen = 0;
1041       header = NULL;
1042     } else {
1043       buf1 = abuf;
1044     }
1045
1046     if (header && headlen > 0)
1047     {
1048       ret = MIN(headlen,size);
1049       memcpy(buf1,header,ret);
1050       headlen -= ret;
1051       header += ret;
1052       if (headlen <= 0) header = NULL;
1053     }
1054
1055     if (s > ret)
1056       ret += read(infd,buf1+ret,s-ret);
1057
1058     if (ret > 0)
1059     {
1060       ret2 = (outfd>=0?write_data(outfd,buf1,ret):ret);
1061       if (ret2 > 0) total += ret2;
1062       /* if we can't write then dump excess data */
1063       if (ret2 != ret)
1064         transfer_file(infd,-1,n-(ret+headlen),NULL,0,0);
1065     }
1066     if (ret <= 0 || ret2 != ret)
1067       return(total);
1068     n -= ret;
1069   }
1070   return(total);
1071 }
1072
1073
1074
1075 /****************************************************************************
1076 find a pointer to a netbios name
1077 ****************************************************************************/
1078 static char *name_ptr(char *buf,int ofs)
1079 {
1080   unsigned char c = *(unsigned char *)(buf+ofs);
1081
1082   if ((c & 0xC0) == 0xC0)
1083     {
1084       uint16 l;
1085       char p[2];
1086       memcpy(p,buf+ofs,2);
1087       p[0] &= ~0xC0;
1088       l = RSVAL(p,0);
1089       DEBUG(5,("name ptr to pos %d from %d is %s\n",l,ofs,buf+l));
1090       return(buf + l);
1091     }
1092   else
1093     return(buf+ofs);
1094 }  
1095
1096 /****************************************************************************
1097 extract a netbios name from a buf
1098 ****************************************************************************/
1099 int name_extract(char *buf,int ofs,char *name)
1100 {
1101   char *p = name_ptr(buf,ofs);
1102   int d = PTR_DIFF(p,buf+ofs);
1103   pstrcpy(name,"");
1104   if (d < -50 || d > 50) return(0);
1105   return(name_interpret(p,name));
1106 }
1107   
1108 /****************************************************************************
1109 return the total storage length of a mangled name
1110 ****************************************************************************/
1111 int name_len(char *s1)
1112 {
1113         /* NOTE: this argument _must_ be unsigned */
1114         unsigned char *s = (unsigned char *)s1;
1115         int len;
1116
1117         /* If the two high bits of the byte are set, return 2. */
1118         if (0xC0 == (*s & 0xC0))
1119                 return(2);
1120
1121         /* Add up the length bytes. */
1122         for (len = 1; (*s); s += (*s) + 1) {
1123                 len += *s + 1;
1124                 SMB_ASSERT(len < 80);
1125         }
1126
1127         return(len);
1128 } /* name_len */
1129
1130
1131 /*******************************************************************
1132 sleep for a specified number of milliseconds
1133 ********************************************************************/
1134 void msleep(int t)
1135 {
1136   int tdiff=0;
1137   struct timeval tval,t1,t2;  
1138   fd_set fds;
1139
1140   GetTimeOfDay(&t1);
1141   GetTimeOfDay(&t2);
1142   
1143   while (tdiff < t) {
1144     tval.tv_sec = (t-tdiff)/1000;
1145     tval.tv_usec = 1000*((t-tdiff)%1000);
1146  
1147     FD_ZERO(&fds);
1148     errno = 0;
1149     sys_select(0,&fds,&tval);
1150
1151     GetTimeOfDay(&t2);
1152     tdiff = TvalDiff(&t1,&t2);
1153   }
1154 }
1155
1156
1157 /*********************************************************
1158 * Recursive routine that is called by unix_mask_match.
1159 * Does the actual matching. This is the 'original code' 
1160 * used by the unix matcher.
1161 *********************************************************/
1162 static BOOL unix_do_match(char *str, char *regexp, int case_sig)
1163 {
1164   char *p;
1165
1166   for( p = regexp; *p && *str; ) {
1167     switch(*p) {
1168     case '?':
1169       str++; p++;
1170       break;
1171
1172     case '*':
1173       /* Look for a character matching 
1174          the one after the '*' */
1175       p++;
1176       if(!*p)
1177         return True; /* Automatic match */
1178       while(*str) {
1179         while(*str && (case_sig ? (*p != *str) : (toupper(*p)!=toupper(*str))))
1180           str++;
1181         if(unix_do_match(str,p,case_sig))
1182           return True;
1183         if(!*str)
1184           return False;
1185         else
1186           str++;
1187       }
1188       return False;
1189
1190     default:
1191       if(case_sig) {
1192         if(*str != *p)
1193           return False;
1194       } else {
1195         if(toupper(*str) != toupper(*p))
1196           return False;
1197       }
1198       str++, p++;
1199       break;
1200     }
1201   }
1202   if(!*p && !*str)
1203     return True;
1204
1205   if (!*p && str[0] == '.' && str[1] == 0)
1206     return(True);
1207   
1208   if (!*str && *p == '?')
1209     {
1210       while (*p == '?') p++;
1211       return(!*p);
1212     }
1213
1214   if(!*str && (*p == '*' && p[1] == '\0'))
1215     return True;
1216   return False;
1217 }
1218
1219
1220 /*********************************************************
1221 * Routine to match a given string with a regexp - uses
1222 * simplified regexp that takes * and ? only. Case can be
1223 * significant or not.
1224 * This is the 'original code' used by the unix matcher.
1225 *********************************************************/
1226
1227 static BOOL unix_mask_match(char *str, char *regexp, int case_sig,BOOL trans2)
1228 {
1229   char *p;
1230   pstring p1, p2;
1231   fstring ebase,eext,sbase,sext;
1232
1233   BOOL matched;
1234
1235   /* Make local copies of str and regexp */
1236   StrnCpy(p1,regexp,sizeof(pstring)-1);
1237   StrnCpy(p2,str,sizeof(pstring)-1);
1238
1239   if (!strchr(p2,'.')) {
1240     pstrcat(p2,".");
1241   }
1242
1243   /* Remove any *? and ** as they are meaningless */
1244   for(p = p1; *p; p++)
1245     while( *p == '*' && (p[1] == '?' ||p[1] == '*'))
1246       (void)pstrcpy( &p[1], &p[2]);
1247
1248   if (strequal(p1,"*")) return(True);
1249
1250   DEBUG(8,("unix_mask_match str=<%s> regexp=<%s>, case_sig = %d\n", p2, p1, case_sig));
1251
1252   if (trans2) {
1253     fstrcpy(ebase,p1);
1254     fstrcpy(sbase,p2);
1255   } else {
1256     if ((p=strrchr(p1,'.'))) {
1257       *p = 0;
1258       fstrcpy(ebase,p1);
1259       fstrcpy(eext,p+1);
1260     } else {
1261       fstrcpy(ebase,p1);
1262       eext[0] = 0;
1263     }
1264
1265   if (!strequal(p2,".") && !strequal(p2,"..") && (p=strrchr(p2,'.'))) {
1266     *p = 0;
1267     fstrcpy(sbase,p2);
1268     fstrcpy(sext,p+1);
1269   } else {
1270     fstrcpy(sbase,p2);
1271     fstrcpy(sext,"");
1272   }
1273   }
1274
1275   matched = unix_do_match(sbase,ebase,case_sig) && 
1276     (trans2 || unix_do_match(sext,eext,case_sig));
1277
1278   DEBUG(8,("unix_mask_match returning %d\n", matched));
1279
1280   return matched;
1281 }
1282
1283 /*********************************************************
1284 * Recursive routine that is called by mask_match.
1285 * Does the actual matching. Returns True if matched,
1286 * False if failed. This is the 'new' NT style matcher.
1287 *********************************************************/
1288
1289 BOOL do_match(char *str, char *regexp, int case_sig)
1290 {
1291   char *p;
1292
1293   for( p = regexp; *p && *str; ) {
1294     switch(*p) {
1295     case '?':
1296       str++; p++;
1297       break;
1298
1299     case '*':
1300       /* Look for a character matching 
1301          the one after the '*' */
1302       p++;
1303       if(!*p)
1304         return True; /* Automatic match */
1305       while(*str) {
1306         while(*str && (case_sig ? (*p != *str) : (toupper(*p)!=toupper(*str))))
1307           str++;
1308         /* Now eat all characters that match, as
1309            we want the *last* character to match. */
1310         while(*str && (case_sig ? (*p == *str) : (toupper(*p)==toupper(*str))))
1311           str++;
1312         str--; /* We've eaten the match char after the '*' */
1313         if(do_match(str,p,case_sig)) {
1314           return True;
1315         }
1316         if(!*str) {
1317           return False;
1318         } else {
1319           str++;
1320         }
1321       }
1322       return False;
1323
1324     default:
1325       if(case_sig) {
1326         if(*str != *p) {
1327           return False;
1328         }
1329       } else {
1330         if(toupper(*str) != toupper(*p)) {
1331           return False;
1332         }
1333       }
1334       str++, p++;
1335       break;
1336     }
1337   }
1338
1339   if(!*p && !*str)
1340     return True;
1341
1342   if (!*p && str[0] == '.' && str[1] == 0) {
1343     return(True);
1344   }
1345   
1346   if (!*str && *p == '?') {
1347     while (*p == '?')
1348       p++;
1349     return(!*p);
1350   }
1351
1352   if(!*str && (*p == '*' && p[1] == '\0')) {
1353     return True;
1354   }
1355  
1356   return False;
1357 }
1358
1359
1360 /*********************************************************
1361 * Routine to match a given string with a regexp - uses
1362 * simplified regexp that takes * and ? only. Case can be
1363 * significant or not.
1364 * The 8.3 handling was rewritten by Ums Harald <Harald.Ums@pro-sieben.de>
1365 * This is the new 'NT style' matcher.
1366 *********************************************************/
1367
1368 BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2)
1369 {
1370   char *p;
1371   pstring t_pattern, t_filename, te_pattern, te_filename;
1372   fstring ebase,eext,sbase,sext;
1373
1374   BOOL matched = False;
1375
1376   /* Make local copies of str and regexp */
1377   pstrcpy(t_pattern,regexp);
1378   pstrcpy(t_filename,str);
1379
1380 #if 0
1381   /* 
1382    * Not sure if this is a good idea. JRA.
1383    */
1384   if(trans2 && is_8_3(t_pattern,False) && is_8_3(t_filename,False))
1385     trans2 = False;
1386 #endif
1387
1388 #if 0
1389   if (!strchr(t_filename,'.')) {
1390     pstrcat(t_filename,".");
1391   }
1392 #endif
1393
1394   /* Remove any *? and ** as they are meaningless */
1395   string_sub(t_pattern, "*?", "*");
1396   string_sub(t_pattern, "**", "*");
1397
1398   if (strequal(t_pattern,"*"))
1399     return(True);
1400
1401   DEBUG(8,("mask_match str=<%s> regexp=<%s>, case_sig = %d\n", t_filename, t_pattern, case_sig));
1402
1403   if(trans2) {
1404     /*
1405      * Match each component of the regexp, split up by '.'
1406      * characters.
1407      */
1408     char *fp, *rp, *cp2, *cp1;
1409     BOOL last_wcard_was_star = False;
1410     int num_path_components, num_regexp_components;
1411
1412     pstrcpy(te_pattern,t_pattern);
1413     pstrcpy(te_filename,t_filename);
1414     /*
1415      * Remove multiple "*." patterns.
1416      */
1417     string_sub(te_pattern, "*.*.", "*.");
1418     num_regexp_components = count_chars(te_pattern, '.');
1419     num_path_components = count_chars(te_filename, '.');
1420
1421     /* 
1422      * Check for special 'hack' case of "DIR a*z". - needs to match a.b.c...z
1423      */
1424     if(num_regexp_components == 0)
1425       matched = do_match( te_filename, te_pattern, case_sig);
1426     else {
1427       for( cp1 = te_pattern, cp2 = te_filename; cp1;) {
1428         fp = strchr(cp2, '.');
1429         if(fp)
1430           *fp = '\0';
1431         rp = strchr(cp1, '.');
1432         if(rp)
1433           *rp = '\0';
1434
1435         if(cp1[strlen(cp1)-1] == '*')
1436           last_wcard_was_star = True;
1437         else
1438           last_wcard_was_star = False;
1439
1440         if(!do_match(cp2, cp1, case_sig))
1441           break;
1442
1443         cp1 = rp ? rp + 1 : NULL;
1444         cp2 = fp ? fp + 1 : "";
1445
1446         if(last_wcard_was_star || ((cp1 != NULL) && (*cp1 == '*'))) {
1447           /* Eat the extra path components. */
1448           int i;
1449
1450           for(i = 0; i < num_path_components - num_regexp_components; i++) {
1451             fp = strchr(cp2, '.');
1452             if(fp)
1453               *fp = '\0';
1454
1455             if((cp1 != NULL) && do_match( cp2, cp1, case_sig)) {
1456               cp2 = fp ? fp + 1 : "";
1457               break;
1458             }
1459             cp2 = fp ? fp + 1 : "";
1460           }
1461           num_path_components -= i;
1462         }
1463       } 
1464       if(cp1 == NULL && ((*cp2 == '\0') || last_wcard_was_star))
1465         matched = True;
1466     }
1467   } else {
1468
1469     /* -------------------------------------------------
1470      * Behaviour of Win95
1471      * for 8.3 filenames and 8.3 Wildcards
1472      * -------------------------------------------------
1473      */
1474     if (strequal (t_filename, ".")) {
1475       /*
1476        *  Patterns:  *.*  *. ?. ?  are valid
1477        *
1478        */
1479       if(strequal(t_pattern, "*.*") || strequal(t_pattern, "*.") ||
1480          strequal(t_pattern, "?.") || strequal(t_pattern, "?"))
1481         matched = True;
1482     } else if (strequal (t_filename, "..")) {
1483       /*
1484        *  Patterns:  *.*  *. ?. ? *.? are valid
1485        *
1486        */
1487       if(strequal(t_pattern, "*.*") || strequal(t_pattern, "*.") ||
1488          strequal(t_pattern, "?.") || strequal(t_pattern, "?") ||
1489          strequal(t_pattern, "*.?") || strequal(t_pattern, "?.*"))
1490         matched = True;
1491     } else {
1492
1493       if ((p = strrchr (t_pattern, '.'))) {
1494         /*
1495          * Wildcard has a suffix.
1496          */
1497         *p = 0;
1498         fstrcpy (ebase, t_pattern);
1499         if (p[1]) {
1500           fstrcpy (eext, p + 1);
1501         } else {
1502           /* pattern ends in DOT: treat as if there is no DOT */
1503           *eext = 0;
1504           if (strequal (ebase, "*"))
1505             return (True);
1506         }
1507       } else {
1508         /*
1509          * No suffix for wildcard.
1510          */
1511         fstrcpy (ebase, t_pattern);
1512         eext[0] = 0;
1513       }
1514
1515       p = strrchr (t_filename, '.');
1516       if (p && (p[1] == 0)      ) {
1517         /*
1518          * Filename has an extension of '.' only.
1519          */
1520         *p = 0; /* nuke dot at end of string */
1521         p = 0;  /* and treat it as if there is no extension */
1522       }
1523
1524       if (p) {
1525         /*
1526          * Filename has an extension.
1527          */
1528         *p = 0;
1529         fstrcpy (sbase, t_filename);
1530         fstrcpy (sext, p + 1);
1531         if (*eext) {
1532           matched = do_match(sbase, ebase, case_sig)
1533                     && do_match(sext, eext, case_sig);
1534         } else {
1535           /* pattern has no extension */
1536           /* Really: match complete filename with pattern ??? means exactly 3 chars */
1537           matched = do_match(str, ebase, case_sig);
1538         }
1539       } else {
1540         /* 
1541          * Filename has no extension.
1542          */
1543         fstrcpy (sbase, t_filename);
1544         fstrcpy (sext, "");
1545         if (*eext) {
1546           /* pattern has extension */
1547           matched = do_match(sbase, ebase, case_sig)
1548                     && do_match(sext, eext, case_sig);
1549         } else {
1550           matched = do_match(sbase, ebase, case_sig);
1551 #ifdef EMULATE_WEIRD_W95_MATCHING
1552           /*
1553            * Even Microsoft has some problems
1554            * Behaviour Win95 -> local disk 
1555            * is different from Win95 -> smb drive from Nt 4.0
1556            * This branch would reflect the Win95 local disk behaviour
1557            */
1558           if (!matched) {
1559             /* a? matches aa and a in w95 */
1560             fstrcat (sbase, ".");
1561             matched = do_match(sbase, ebase, case_sig);
1562           }
1563 #endif
1564         }
1565       }
1566     }
1567   }
1568
1569   DEBUG(8,("mask_match returning %d\n", matched));
1570
1571   return matched;
1572 }
1573
1574 /****************************************************************************
1575 become a daemon, discarding the controlling terminal
1576 ****************************************************************************/
1577 void become_daemon(void)
1578 {
1579         if (fork()) {
1580                 _exit(0);
1581         }
1582
1583   /* detach from the terminal */
1584 #ifdef HAVE_SETSID
1585         setsid();
1586 #elif defined(TIOCNOTTY)
1587         {
1588                 int i = sys_open("/dev/tty", O_RDWR, 0);
1589                 if (i != -1) {
1590                         ioctl(i, (int) TIOCNOTTY, (char *)0);      
1591                         close(i);
1592                 }
1593         }
1594 #endif /* HAVE_SETSID */
1595
1596         /* Close fd's 0,1,2. Needed if started by rsh */
1597         close_low_fds();
1598 }
1599
1600
1601 /****************************************************************************
1602 put up a yes/no prompt
1603 ****************************************************************************/
1604 BOOL yesno(char *p)
1605 {
1606   pstring ans;
1607   printf("%s",p);
1608
1609   if (!fgets(ans,sizeof(ans)-1,stdin))
1610     return(False);
1611
1612   if (*ans == 'y' || *ans == 'Y')
1613     return(True);
1614
1615   return(False);
1616 }
1617
1618
1619
1620 /****************************************************************************
1621 set the length of a file from a filedescriptor.
1622 Returns 0 on success, -1 on failure.
1623 ****************************************************************************/
1624 int set_filelen(int fd, SMB_OFF_T len)
1625 {
1626 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
1627    extend a file with ftruncate. Provide alternate implementation
1628    for this */
1629
1630 #ifdef HAVE_FTRUNCATE_EXTEND
1631   return sys_ftruncate(fd, len);
1632 #else
1633   SMB_STRUCT_STAT st;
1634   char c = 0;
1635   SMB_OFF_T currpos = sys_lseek(fd, (SMB_OFF_T)0, SEEK_CUR);
1636
1637   if(currpos == -1)
1638     return -1;
1639   /* Do an fstat to see if the file is longer than
1640      the requested size (call ftruncate),
1641      or shorter, in which case seek to len - 1 and write 1
1642      byte of zero */
1643   if(sys_fstat(fd, &st)<0)
1644     return -1;
1645
1646 #ifdef S_ISFIFO
1647   if (S_ISFIFO(st.st_mode)) return 0;
1648 #endif
1649
1650   if(st.st_size == len)
1651     return 0;
1652   if(st.st_size > len)
1653     return sys_ftruncate(fd, len);
1654
1655   if(sys_lseek(fd, len-1, SEEK_SET) != len -1)
1656     return -1;
1657   if(write(fd, &c, 1)!=1)
1658     return -1;
1659   /* Seek to where we were */
1660   if(sys_lseek(fd, currpos, SEEK_SET) != currpos)
1661     return -1;
1662   return 0;
1663 #endif
1664 }
1665
1666
1667 #ifdef HPUX
1668 /****************************************************************************
1669 this is a version of setbuffer() for those machines that only have setvbuf
1670 ****************************************************************************/
1671  void setbuffer(FILE *f,char *buf,int bufsize)
1672 {
1673   setvbuf(f,buf,_IOFBF,bufsize);
1674 }
1675 #endif
1676
1677
1678 /****************************************************************************
1679 parse out a filename from a path name. Assumes dos style filenames.
1680 ****************************************************************************/
1681 static char *filename_dos(char *path,char *buf)
1682 {
1683   char *p = strrchr(path,'\\');
1684
1685   if (!p)
1686     pstrcpy(buf,path);
1687   else
1688     pstrcpy(buf,p+1);
1689
1690   return(buf);
1691 }
1692
1693
1694
1695 /****************************************************************************
1696 expand a pointer to be a particular size
1697 ****************************************************************************/
1698 void *Realloc(void *p,size_t size)
1699 {
1700   void *ret=NULL;
1701
1702   if (size == 0) {
1703     if (p) free(p);
1704     DEBUG(5,("Realloc asked for 0 bytes\n"));
1705     return NULL;
1706   }
1707
1708   if (!p)
1709     ret = (void *)malloc(size);
1710   else
1711     ret = (void *)realloc(p,size);
1712
1713 #ifdef MEM_MAN
1714   {
1715         extern FILE *dbf;
1716         smb_mem_write_info(ret, dbf);
1717   }
1718 #endif
1719
1720   if (!ret)
1721     DEBUG(0,("Memory allocation error: failed to expand to %d bytes\n",size));
1722
1723   return(ret);
1724 }
1725
1726
1727 /****************************************************************************
1728 get my own name and IP
1729 ****************************************************************************/
1730 BOOL get_myname(char *my_name,struct in_addr *ip)
1731 {
1732   struct hostent *hp;
1733   pstring hostname;
1734
1735   *hostname = 0;
1736
1737   /* get my host name */
1738   if (gethostname(hostname, MAXHOSTNAMELEN) == -1) 
1739     {
1740       DEBUG(0,("gethostname failed\n"));
1741       return False;
1742     } 
1743
1744   /* get host info */
1745   if ((hp = Get_Hostbyname(hostname)) == 0) 
1746     {
1747       DEBUG(0,( "Get_Hostbyname: Unknown host %s\n",hostname));
1748       return False;
1749     }
1750
1751   if (my_name)
1752     {
1753       /* split off any parts after an initial . */
1754       char *p = strchr(hostname,'.');
1755       if (p) *p = 0;
1756
1757       fstrcpy(my_name,hostname);
1758     }
1759
1760   if (ip)
1761     putip((char *)ip,(char *)hp->h_addr);
1762
1763   return(True);
1764 }
1765
1766
1767 /****************************************************************************
1768 true if two IP addresses are equal
1769 ****************************************************************************/
1770 BOOL ip_equal(struct in_addr ip1,struct in_addr ip2)
1771 {
1772   uint32 a1,a2;
1773   a1 = ntohl(ip1.s_addr);
1774   a2 = ntohl(ip2.s_addr);
1775   return(a1 == a2);
1776 }
1777
1778
1779 /****************************************************************************
1780 interpret a protocol description string, with a default
1781 ****************************************************************************/
1782 int interpret_protocol(char *str,int def)
1783 {
1784   if (strequal(str,"NT1"))
1785     return(PROTOCOL_NT1);
1786   if (strequal(str,"LANMAN2"))
1787     return(PROTOCOL_LANMAN2);
1788   if (strequal(str,"LANMAN1"))
1789     return(PROTOCOL_LANMAN1);
1790   if (strequal(str,"CORE"))
1791     return(PROTOCOL_CORE);
1792   if (strequal(str,"COREPLUS"))
1793     return(PROTOCOL_COREPLUS);
1794   if (strequal(str,"CORE+"))
1795     return(PROTOCOL_COREPLUS);
1796   
1797   DEBUG(0,("Unrecognised protocol level %s\n",str));
1798   
1799   return(def);
1800 }
1801
1802
1803 /****************************************************************************
1804 interpret an internet address or name into an IP address in 4 byte form
1805 ****************************************************************************/
1806 uint32 interpret_addr(char *str)
1807 {
1808   struct hostent *hp;
1809   uint32 res;
1810   int i;
1811   BOOL pure_address = True;
1812
1813   if (strcmp(str,"0.0.0.0") == 0) return(0);
1814   if (strcmp(str,"255.255.255.255") == 0) return(0xFFFFFFFF);
1815
1816   for (i=0; pure_address && str[i]; i++)
1817     if (!(isdigit((int)str[i]) || str[i] == '.')) 
1818       pure_address = False;
1819
1820   /* if it's in the form of an IP address then get the lib to interpret it */
1821   if (pure_address) {
1822     res = inet_addr(str);
1823   } else {
1824     /* otherwise assume it's a network name of some sort and use 
1825        Get_Hostbyname */
1826     if ((hp = Get_Hostbyname(str)) == 0) {
1827       DEBUG(3,("Get_Hostbyname: Unknown host. %s\n",str));
1828       return 0;
1829     }
1830     if(hp->h_addr == NULL) {
1831       DEBUG(3,("Get_Hostbyname: host address is invalid for host %s\n",str));
1832       return 0;
1833     }
1834     putip((char *)&res,(char *)hp->h_addr);
1835   }
1836
1837   if (res == (uint32)-1) return(0);
1838
1839   return(res);
1840 }
1841
1842 /*******************************************************************
1843   a convenient addition to interpret_addr()
1844   ******************************************************************/
1845 struct in_addr *interpret_addr2(char *str)
1846 {
1847   static struct in_addr ret;
1848   uint32 a = interpret_addr(str);
1849   ret.s_addr = a;
1850   return(&ret);
1851 }
1852
1853 /*******************************************************************
1854   check if an IP is the 0.0.0.0
1855   ******************************************************************/
1856 BOOL zero_ip(struct in_addr ip)
1857 {
1858   uint32 a;
1859   putip((char *)&a,(char *)&ip);
1860   return(a == 0);
1861 }
1862
1863
1864 /*******************************************************************
1865  matchname - determine if host name matches IP address 
1866  ******************************************************************/
1867 BOOL matchname(char *remotehost,struct in_addr  addr)
1868 {
1869   struct hostent *hp;
1870   int     i;
1871   
1872   if ((hp = Get_Hostbyname(remotehost)) == 0) {
1873     DEBUG(0,("Get_Hostbyname(%s): lookup failure", remotehost));
1874     return False;
1875   } 
1876
1877   /*
1878    * Make sure that gethostbyname() returns the "correct" host name.
1879    * Unfortunately, gethostbyname("localhost") sometimes yields
1880    * "localhost.domain". Since the latter host name comes from the
1881    * local DNS, we just have to trust it (all bets are off if the local
1882    * DNS is perverted). We always check the address list, though.
1883    */
1884   
1885   if (strcasecmp(remotehost, hp->h_name)
1886       && strcasecmp(remotehost, "localhost")) {
1887     DEBUG(0,("host name/name mismatch: %s != %s",
1888              remotehost, hp->h_name));
1889     return False;
1890   }
1891         
1892   /* Look up the host address in the address list we just got. */
1893   for (i = 0; hp->h_addr_list[i]; i++) {
1894     if (memcmp(hp->h_addr_list[i], (caddr_t) & addr, sizeof(addr)) == 0)
1895       return True;
1896   }
1897
1898   /*
1899    * The host name does not map to the original host address. Perhaps
1900    * someone has compromised a name server. More likely someone botched
1901    * it, but that could be dangerous, too.
1902    */
1903   
1904   DEBUG(0,("host name/address mismatch: %s != %s",
1905            inet_ntoa(addr), hp->h_name));
1906   return False;
1907 }
1908
1909
1910 #if (defined(HAVE_NETGROUP) && defined(WITH_AUTOMOUNT))
1911 /******************************************************************
1912  Remove any mount options such as -rsize=2048,wsize=2048 etc.
1913  Based on a fix from <Thomas.Hepper@icem.de>.
1914 *******************************************************************/
1915
1916 static void strip_mount_options( pstring *str)
1917 {
1918   if (**str == '-')
1919   { 
1920     char *p = *str;
1921     while(*p && !isspace(*p))
1922       p++;
1923     while(*p && isspace(*p))
1924       p++;
1925     if(*p) {
1926       pstring tmp_str;
1927
1928       pstrcpy(tmp_str, p);
1929       pstrcpy(*str, tmp_str);
1930     }
1931   }
1932 }
1933
1934 /*******************************************************************
1935  Patch from jkf@soton.ac.uk
1936  Split Luke's automount_server into YP lookup and string splitter
1937  so can easily implement automount_path(). 
1938  As we may end up doing both, cache the last YP result. 
1939 *******************************************************************/
1940
1941 #ifdef WITH_NISPLUS_HOME
1942 static char *automount_lookup(char *user_name)
1943 {
1944   static fstring last_key = "";
1945   static pstring last_value = "";
1946  
1947   char *nis_map = (char *)lp_nis_home_map_name();
1948  
1949   char nis_domain[NIS_MAXNAMELEN + 1];
1950   char buffer[NIS_MAXATTRVAL + 1];
1951   nis_result *result;
1952   nis_object *object;
1953   entry_obj  *entry;
1954  
1955   strncpy(nis_domain, (char *)nis_local_directory(), NIS_MAXNAMELEN);
1956   nis_domain[NIS_MAXNAMELEN] = '\0';
1957  
1958   DEBUG(5, ("NIS+ Domain: %s\n", nis_domain));
1959  
1960   if (strcmp(user_name, last_key))
1961   {
1962     slprintf(buffer, sizeof(buffer)-1, "[%s=%s]%s.%s", "key", user_name, nis_map, nis_domain);
1963     DEBUG(5, ("NIS+ querystring: %s\n", buffer));
1964  
1965     if (result = nis_list(buffer, RETURN_RESULT, NULL, NULL))
1966     {
1967        if (result->status != NIS_SUCCESS)
1968       {
1969         DEBUG(3, ("NIS+ query failed: %s\n", nis_sperrno(result->status)));
1970         fstrcpy(last_key, ""); pstrcpy(last_value, "");
1971       }
1972       else
1973       {
1974         object = result->objects.objects_val;
1975         if (object->zo_data.zo_type == ENTRY_OBJ)
1976         {
1977            entry = &object->zo_data.objdata_u.en_data;
1978            DEBUG(5, ("NIS+ entry type: %s\n", entry->en_type));
1979            DEBUG(3, ("NIS+ result: %s\n", entry->en_cols.en_cols_val[1].ec_value.ec_value_val));
1980  
1981            pstrcpy(last_value, entry->en_cols.en_cols_val[1].ec_value.ec_value_val);
1982            string_sub(last_value, "&", user_name);
1983            fstrcpy(last_key, user_name);
1984         }
1985       }
1986     }
1987     nis_freeresult(result);
1988   }
1989
1990   strip_mount_options(&last_value);
1991
1992   DEBUG(4, ("NIS+ Lookup: %s resulted in %s\n", user_name, last_value));
1993   return last_value;
1994 }
1995 #else /* WITH_NISPLUS_HOME */
1996 static char *automount_lookup(char *user_name)
1997 {
1998   static fstring last_key = "";
1999   static pstring last_value = "";
2000
2001   int nis_error;        /* returned by yp all functions */
2002   char *nis_result;     /* yp_match inits this */
2003   int nis_result_len;  /* and set this */
2004   char *nis_domain;     /* yp_get_default_domain inits this */
2005   char *nis_map = (char *)lp_nis_home_map_name();
2006
2007   if ((nis_error = yp_get_default_domain(&nis_domain)) != 0)
2008   {
2009     DEBUG(3, ("YP Error: %s\n", yperr_string(nis_error)));
2010     return last_value;
2011   }
2012
2013   DEBUG(5, ("NIS Domain: %s\n", nis_domain));
2014
2015   if (!strcmp(user_name, last_key))
2016   {
2017     nis_result = last_value;
2018     nis_result_len = strlen(last_value);
2019     nis_error = 0;
2020   }
2021   else
2022   {
2023     if ((nis_error = yp_match(nis_domain, nis_map,
2024                               user_name, strlen(user_name),
2025                               &nis_result, &nis_result_len)) != 0)
2026     {
2027       DEBUG(3, ("YP Error: \"%s\" while looking up \"%s\" in map \"%s\"\n", 
2028                yperr_string(nis_error), user_name, nis_map));
2029     }
2030     if (!nis_error && nis_result_len >= sizeof(pstring))
2031     {
2032       nis_result_len = sizeof(pstring)-1;
2033     }
2034     fstrcpy(last_key, user_name);
2035     strncpy(last_value, nis_result, nis_result_len);
2036     last_value[nis_result_len] = '\0';
2037   }
2038
2039   strip_mount_options(&last_value);
2040
2041   DEBUG(4, ("YP Lookup: %s resulted in %s\n", user_name, last_value));
2042   return last_value;
2043 }
2044 #endif /* WITH_NISPLUS_HOME */
2045 #endif
2046
2047 /*******************************************************************
2048  Patch from jkf@soton.ac.uk
2049  This is Luke's original function with the NIS lookup code
2050  moved out to a separate function.
2051 *******************************************************************/
2052 static char *automount_server(char *user_name)
2053 {
2054         static pstring server_name;
2055
2056         /* use the local machine name as the default */
2057         /* this will be the default if WITH_AUTOMOUNT is not used or fails */
2058         pstrcpy(server_name, local_machine);
2059
2060 #if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
2061
2062         if (lp_nis_home_map())
2063         {
2064                 int home_server_len;
2065                 char *automount_value = automount_lookup(user_name);
2066                 home_server_len = strcspn(automount_value,":");
2067                 DEBUG(5, ("NIS lookup succeeded.  Home server length: %d\n",home_server_len));
2068                 if (home_server_len > sizeof(pstring))
2069                 {
2070                         home_server_len = sizeof(pstring);
2071                 }
2072                 strncpy(server_name, automount_value, home_server_len);
2073                 server_name[home_server_len] = '\0';
2074         }
2075 #endif
2076
2077         DEBUG(4,("Home server: %s\n", server_name));
2078
2079         return server_name;
2080 }
2081
2082 /*******************************************************************
2083  Patch from jkf@soton.ac.uk
2084  Added this to implement %p (NIS auto-map version of %H)
2085 *******************************************************************/
2086 static char *automount_path(char *user_name)
2087 {
2088         static pstring server_path;
2089
2090         /* use the passwd entry as the default */
2091         /* this will be the default if WITH_AUTOMOUNT is not used or fails */
2092         /* pstrcpy() copes with get_home_dir() returning NULL */
2093         pstrcpy(server_path, get_home_dir(user_name));
2094
2095 #if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
2096
2097         if (lp_nis_home_map())
2098         {
2099                 char *home_path_start;
2100                 char *automount_value = automount_lookup(user_name);
2101                 home_path_start = strchr(automount_value,':');
2102                 if (home_path_start != NULL)
2103                 {
2104                   DEBUG(5, ("NIS lookup succeeded.  Home path is: %s\n",
2105                         home_path_start?(home_path_start+1):""));
2106                   pstrcpy(server_path, home_path_start+1);
2107                 }
2108         }
2109 #endif
2110
2111         DEBUG(4,("Home server path: %s\n", server_path));
2112
2113         return server_path;
2114 }
2115
2116
2117 /*******************************************************************
2118 sub strings with useful parameters
2119 Rewritten by Stefaan A Eeckels <Stefaan.Eeckels@ecc.lu> and
2120 Paul Rippin <pr3245@nopc.eurostat.cec.be>
2121 ********************************************************************/
2122 void standard_sub_basic(char *str)
2123 {
2124         char *s, *p;
2125         char pidstr[10];
2126         struct passwd *pass;
2127         char *username = sam_logon_in_ssb ? samlogon_user : sesssetup_user;
2128
2129         for (s = str ; s && *s && (p = strchr(s,'%')); s = p )
2130         {
2131                 switch (*(p+1))
2132                 {
2133                         case 'G' :
2134                         {
2135                                 if ((pass = Get_Pwnam(username,False))!=NULL)
2136                                 {
2137                                         string_sub(p,"%G",gidtoname(pass->pw_gid));
2138                                 }
2139                                 else
2140                                 {
2141                                         p += 2;
2142                                 }
2143                                 break;
2144                         }
2145                         case 'N' : string_sub(p,"%N", automount_server(username)); break;
2146                         case 'I' : string_sub(p,"%I", client_addr(Client)); break;
2147                         case 'L' : string_sub(p,"%L", local_machine); break;
2148                         case 'M' : string_sub(p,"%M", client_name(Client)); break;
2149                         case 'R' : string_sub(p,"%R", remote_proto); break;
2150                         case 'T' : string_sub(p,"%T", timestring()); break;
2151                         case 'U' : string_sub(p,"%U", username); break;
2152                         case 'a' : string_sub(p,"%a", remote_arch); break;
2153                         case 'd' :
2154                         {
2155                                 slprintf(pidstr,sizeof(pidstr) - 1, "%d",(int)getpid());
2156                                 string_sub(p,"%d", pidstr);
2157                                 break;
2158                         }
2159                         case 'h' : string_sub(p,"%h", myhostname); break;
2160                         case 'm' : string_sub(p,"%m", remote_machine); break;
2161                         case 'v' : string_sub(p,"%v", VERSION); break;
2162                         case '$' : /* Expand environment variables */
2163                         {
2164                                 /* Contributed by Branko Cibej <branko.cibej@hermes.si> */
2165                                 fstring envname;
2166                                 char *envval;
2167                                 char *q, *r;
2168                                 int copylen;
2169
2170                                 if (*(p+2) != '(')
2171                                 {
2172                                         p+=2;
2173                                         break;
2174                                 }
2175                                 if ((q = strchr(p,')')) == NULL)
2176                                 {
2177                                         DEBUG(0,("standard_sub_basic: Unterminated environment \
2178                                         variable [%s]\n", p));
2179                                         p+=2;
2180                                         break;
2181                                 }
2182
2183                                 r = p+3;
2184                                 copylen = MIN((q-r),(sizeof(envname)-1));
2185                                 strncpy(envname,r,copylen);
2186                                 envname[copylen] = '\0';
2187
2188                                 if ((envval = getenv(envname)) == NULL)
2189                                 {
2190                                         DEBUG(0,("standard_sub_basic: Environment variable [%s] not set\n",
2191                                         envname));
2192                                         p+=2;
2193                                         break;
2194                                 }
2195
2196                                 copylen = MIN((q+1-p),(sizeof(envname)-1));
2197                                 strncpy(envname,p,copylen);
2198                                 envname[copylen] = '\0';
2199                                 string_sub(p,envname,envval);
2200                                 break;
2201                         }
2202                         case '\0': p++; break; /* don't run off end if last character is % */
2203                         default  : p+=2; break;
2204                 }
2205         }
2206         return;
2207 }
2208
2209
2210 /****************************************************************************
2211 do some standard substitutions in a string
2212 ****************************************************************************/
2213 void standard_sub(connection_struct *conn,char *str)
2214 {
2215         char *p, *s, *home;
2216
2217         for (s=str; (p=strchr(s, '%'));s=p)
2218         {
2219                 switch (*(p+1))
2220                 {
2221                         case 'H': 
2222                                 if ((home = get_home_dir(conn->user)) != NULL) {
2223                                         string_sub(p,"%H",home);
2224                                 } else {
2225                                         p += 2;
2226                                 }
2227                                 break;
2228                                 
2229                         /* Patch from jkf@soton.ac.uk Left the %N (NIS
2230                          * server name) in standard_sub_basic as it is
2231                          * a feature for logon servers, hence uses the
2232                          * username.  The %p (NIS server path) code is
2233                          * here as it is used instead of the default
2234                          * "path =" string in [homes] and so needs the
2235                          * service name, not the username.  */
2236                         case 'p': string_sub(p,"%p", automount_path(lp_servicename(SNUM(conn)))); break;
2237                         case 'P': string_sub(p,"%P",conn->connectpath); break; 
2238                         case 'S': string_sub(p,"%S", lp_servicename(SNUM(conn))); break; 
2239                         case 'g': string_sub(p,"%g", gidtoname(conn->gid)); break;
2240                         case 'u': string_sub(p,"%u", conn->user); break;
2241                                 
2242                         case '\0': p++; break; /* don't run off the end of the string */ 
2243                         default  : p+=2; break;
2244                 }
2245         }
2246         
2247         standard_sub_basic(str);
2248 }
2249
2250
2251
2252 /*******************************************************************
2253 are two IPs on the same subnet?
2254 ********************************************************************/
2255 BOOL same_net(struct in_addr ip1,struct in_addr ip2,struct in_addr mask)
2256 {
2257   uint32 net1,net2,nmask;
2258
2259   nmask = ntohl(mask.s_addr);
2260   net1  = ntohl(ip1.s_addr);
2261   net2  = ntohl(ip2.s_addr);
2262             
2263   return((net1 & nmask) == (net2 & nmask));
2264 }
2265
2266
2267 /****************************************************************************
2268 a wrapper for gethostbyname() that tries with all lower and all upper case 
2269 if the initial name fails
2270 ****************************************************************************/
2271 struct hostent *Get_Hostbyname(const char *name)
2272 {
2273   char *name2 = strdup(name);
2274   struct hostent *ret;
2275
2276   if (!name2)
2277     {
2278       DEBUG(0,("Memory allocation error in Get_Hostbyname! panic\n"));
2279       exit(0);
2280     }
2281
2282    
2283   /* 
2284    * This next test is redundent and causes some systems (with
2285    * broken isalnum() calls) problems.
2286    * JRA.
2287    */
2288
2289 #if 0
2290   if (!isalnum(*name2))
2291     {
2292       free(name2);
2293       return(NULL);
2294     }
2295 #endif /* 0 */
2296
2297   ret = sys_gethostbyname(name2);
2298   if (ret != NULL)
2299     {
2300       free(name2);
2301       return(ret);
2302     }
2303
2304   /* try with all lowercase */
2305   strlower(name2);
2306   ret = sys_gethostbyname(name2);
2307   if (ret != NULL)
2308     {
2309       free(name2);
2310       return(ret);
2311     }
2312
2313   /* try with all uppercase */
2314   strupper(name2);
2315   ret = sys_gethostbyname(name2);
2316   if (ret != NULL)
2317     {
2318       free(name2);
2319       return(ret);
2320     }
2321   
2322   /* nothing works :-( */
2323   free(name2);
2324   return(NULL);
2325 }
2326
2327
2328 /****************************************************************************
2329 check if a process exists. Does this work on all unixes?
2330 ****************************************************************************/
2331
2332 BOOL process_exists(int pid)
2333 {
2334         return(kill(pid,0) == 0 || errno != ESRCH);
2335 }
2336
2337
2338 /****************************************************************************
2339 Setup the groups a user belongs to.
2340 ****************************************************************************/
2341 int get_unixgroups(char *user, uid_t uid, gid_t gid, int *p_ngroups, gid_t **p_groups)
2342 {
2343         int i,ngroups;
2344         gid_t grp = 0;
2345         gid_t *groups = NULL;
2346
2347         if (-1 == initgroups(user,gid))
2348         {
2349                 if (getuid() == 0)
2350                 {
2351                         DEBUG(0,("Unable to initgroups!\n"));
2352                         if (gid < 0 || gid > 16000 || uid < 0 || uid > 16000)
2353                         {
2354                                 DEBUG(0,("This is probably a problem with the account %s\n", user));
2355                         }
2356                 }
2357                 return -1;
2358         }
2359
2360         ngroups = sys_getgroups(0,&grp);
2361         if (ngroups <= 0)
2362         {
2363                 ngroups = 32;
2364         }
2365
2366         if((groups = (gid_t *)malloc(sizeof(gid_t)*ngroups)) == NULL)
2367         {
2368                 DEBUG(0,("get_unixgroups malloc fail !\n"));
2369                 return -1;
2370         }
2371
2372         ngroups = sys_getgroups(ngroups,groups);
2373
2374         (*p_ngroups) = ngroups;
2375         (*p_groups) = groups;
2376
2377         DEBUG( 3, ( "%s is in %d groups: ", user, ngroups ) );
2378         for (i = 0; i < ngroups; i++ )
2379         {
2380                 DEBUG( 3, ( "%s%d", (i ? ", " : ""), (int)groups[i] ) );
2381         }
2382         DEBUG( 3, ( "\n" ) );
2383
2384         return 0;
2385 }
2386
2387 /****************************************************************************
2388 get all unix groups.  copying group members is hideous on memory, so it's
2389 NOT done here.  however, names of unix groups _are_ string-allocated so
2390 free_unix_grps() must be called.
2391 ****************************************************************************/
2392 BOOL get_unix_grps(int *p_ngroups, struct group **p_groups)
2393 {
2394         struct group *grp;
2395
2396         DEBUG(10,("get_unix_grps\n"));
2397
2398         if (p_ngroups == NULL || *p_groups == NULL)
2399         {
2400                 return False;
2401         }
2402
2403         (*p_ngroups) = 0;
2404         (*p_groups) = NULL;
2405
2406         setgrent();
2407
2408         while ((grp = getgrent()) != NULL)
2409         {
2410                 struct group *copy_grp;
2411                 
2412                 (*p_groups) = (struct group*)Realloc((*p_groups), (size_t)((*p_ngroups)+1) * sizeof(struct group));
2413                 if ((*p_groups) == NULL)
2414                 {
2415                         (*p_ngroups) = 0;
2416                         endgrent();
2417                         
2418                         return False;
2419                 }
2420
2421                 copy_grp = &(*p_groups)[*p_ngroups];
2422                 memcpy(copy_grp, grp, sizeof(*grp));
2423                 copy_grp->gr_name = strdup(copy_grp->gr_name);
2424                 copy_grp->gr_mem  = NULL;
2425
2426                 (*p_ngroups)++;
2427         }
2428
2429         endgrent();
2430
2431         DEBUG(10,("get_unix_grps: %d groups\n", (*p_ngroups)));
2432         return True;
2433 }
2434
2435 /****************************************************************************
2436 free memory associated with unix groups.
2437 ****************************************************************************/
2438 void free_unix_grps(int ngroups, struct group *p_groups)
2439 {
2440         int i;
2441
2442         if (p_groups == NULL)
2443         {
2444                 return;
2445         }
2446
2447         for (i = 0; i < ngroups; i++)
2448         {
2449                 if (p_groups[i].gr_name != NULL)
2450                 {
2451                         free(p_groups[i].gr_name);
2452                 }
2453         }
2454
2455         free(p_groups);
2456 }
2457
2458 /*******************************************************************
2459 turn a uid into a user name
2460 ********************************************************************/
2461 char *uidtoname(uid_t uid)
2462 {
2463   static char name[40];
2464   struct passwd *pass = getpwuid(uid);
2465   if (pass) return(pass->pw_name);
2466   slprintf(name, sizeof(name) - 1, "%d",(int)uid);
2467   return(name);
2468 }
2469
2470
2471 /*******************************************************************
2472 turn a gid into a group name
2473 ********************************************************************/
2474
2475 char *gidtoname(gid_t gid)
2476 {
2477         static char name[40];
2478         struct group *grp = getgrgid(gid);
2479         if (grp) return(grp->gr_name);
2480         slprintf(name,sizeof(name) - 1, "%d",(int)gid);
2481         return(name);
2482 }
2483
2484 /*******************************************************************
2485 turn a group name into a gid
2486 ********************************************************************/
2487
2488 BOOL nametogid(const char *name, gid_t *gid)
2489 {
2490         struct group *grp = getgrnam(name);
2491         if (grp)
2492         {
2493                 *gid = grp->gr_gid;
2494                 return True;
2495         }
2496         else if (isdigit(name[0]))
2497         {
2498                 *gid = (gid_t)get_number(name);
2499                 return True;
2500         }
2501         else
2502         {
2503                 return False;
2504         }
2505 }
2506
2507 /*******************************************************************
2508 turn a user name into a uid
2509 ********************************************************************/
2510 BOOL nametouid(const char *name, uid_t *uid)
2511 {
2512         struct passwd *pass = Get_Pwnam(name, False);
2513         if (pass)
2514         {
2515                 *uid = pass->pw_uid;
2516                 return True;
2517         }
2518         else if (isdigit(name[0]))
2519         {
2520                 *uid = (uid_t)get_number(name);
2521                 return True;
2522         }
2523         else
2524         {
2525                 return False;
2526         }
2527 }
2528
2529 /*******************************************************************
2530 something really nasty happened - panic!
2531 ********************************************************************/
2532 void smb_panic(char *why)
2533 {
2534         char *cmd = lp_panic_action();
2535         if (cmd && *cmd) {
2536                 system(cmd);
2537         }
2538         DEBUG(0,("PANIC: %s\n", why));
2539         dbgflush();
2540         abort();
2541 }
2542
2543
2544 /*******************************************************************
2545 a readdir wrapper which just returns the file name
2546 ********************************************************************/
2547 char *readdirname(DIR *p)
2548 {
2549         struct dirent *ptr;
2550         char *dname;
2551
2552         if (!p) return(NULL);
2553   
2554         ptr = (struct dirent *)readdir(p);
2555         if (!ptr) return(NULL);
2556
2557         dname = ptr->d_name;
2558
2559 #ifdef NEXT2
2560         if (telldir(p) < 0) return(NULL);
2561 #endif
2562
2563 #ifdef HAVE_BROKEN_READDIR
2564         /* using /usr/ucb/cc is BAD */
2565         dname = dname - 2;
2566 #endif
2567
2568         {
2569                 static pstring buf;
2570                 memcpy(buf, dname, NAMLEN(ptr)+1);
2571                 dname = buf;
2572         }
2573
2574         return(dname);
2575 }
2576
2577 /*******************************************************************
2578  Utility function used to decide if the last component 
2579  of a path matches a (possibly wildcarded) entry in a namelist.
2580 ********************************************************************/
2581
2582 BOOL is_in_path(char *name, name_compare_entry *namelist)
2583 {
2584   pstring last_component;
2585   char *p;
2586
2587   DEBUG(8, ("is_in_path: %s\n", name));
2588
2589   /* if we have no list it's obviously not in the path */
2590   if((namelist == NULL ) || ((namelist != NULL) && (namelist[0].name == NULL))) 
2591   {
2592     DEBUG(8,("is_in_path: no name list.\n"));
2593     return False;
2594   }
2595
2596   /* Get the last component of the unix name. */
2597   p = strrchr(name, '/');
2598   strncpy(last_component, p ? ++p : name, sizeof(last_component)-1);
2599   last_component[sizeof(last_component)-1] = '\0'; 
2600
2601   for(; namelist->name != NULL; namelist++)
2602   {
2603     if(namelist->is_wild)
2604     {
2605       /* 
2606        * Look for a wildcard match. Use the old
2607        * 'unix style' mask match, rather than the
2608        * new NT one.
2609        */
2610       if (unix_mask_match(last_component, namelist->name, case_sensitive, False))
2611       {
2612          DEBUG(8,("is_in_path: mask match succeeded\n"));
2613          return True;
2614       }
2615     }
2616     else
2617     {
2618       if((case_sensitive && (strcmp(last_component, namelist->name) == 0))||
2619        (!case_sensitive && (StrCaseCmp(last_component, namelist->name) == 0)))
2620         {
2621          DEBUG(8,("is_in_path: match succeeded\n"));
2622          return True;
2623         }
2624     }
2625   }
2626   DEBUG(8,("is_in_path: match not found\n"));
2627  
2628   return False;
2629 }
2630
2631 /*******************************************************************
2632  Strip a '/' separated list into an array of 
2633  name_compare_enties structures suitable for 
2634  passing to is_in_path(). We do this for
2635  speed so we can pre-parse all the names in the list 
2636  and don't do it for each call to is_in_path().
2637  namelist is modified here and is assumed to be 
2638  a copy owned by the caller.
2639  We also check if the entry contains a wildcard to
2640  remove a potentially expensive call to mask_match
2641  if possible.
2642 ********************************************************************/
2643  
2644 void set_namearray(name_compare_entry **ppname_array, char *namelist)
2645 {
2646   char *name_end;
2647   char *nameptr = namelist;
2648   int num_entries = 0;
2649   int i;
2650
2651   (*ppname_array) = NULL;
2652
2653   if((nameptr == NULL ) || ((nameptr != NULL) && (*nameptr == '\0'))) 
2654     return;
2655
2656   /* We need to make two passes over the string. The
2657      first to count the number of elements, the second
2658      to split it.
2659    */
2660   while(*nameptr) 
2661     {
2662       if ( *nameptr == '/' ) 
2663         {
2664           /* cope with multiple (useless) /s) */
2665           nameptr++;
2666           continue;
2667         }
2668       /* find the next / */
2669       name_end = strchr(nameptr, '/');
2670
2671       /* oops - the last check for a / didn't find one. */
2672       if (name_end == NULL)
2673         break;
2674
2675       /* next segment please */
2676       nameptr = name_end + 1;
2677       num_entries++;
2678     }
2679
2680   if(num_entries == 0)
2681     return;
2682
2683   if(( (*ppname_array) = (name_compare_entry *)malloc( 
2684            (num_entries + 1) * sizeof(name_compare_entry))) == NULL)
2685         {
2686     DEBUG(0,("set_namearray: malloc fail\n"));
2687     return;
2688         }
2689
2690   /* Now copy out the names */
2691   nameptr = namelist;
2692   i = 0;
2693   while(*nameptr)
2694              {
2695       if ( *nameptr == '/' ) 
2696       {
2697           /* cope with multiple (useless) /s) */
2698           nameptr++;
2699           continue;
2700       }
2701       /* find the next / */
2702       if ((name_end = strchr(nameptr, '/')) != NULL) 
2703       {
2704           *name_end = 0;
2705          }
2706
2707       /* oops - the last check for a / didn't find one. */
2708       if(name_end == NULL) 
2709         break;
2710
2711       (*ppname_array)[i].is_wild = ((strchr( nameptr, '?')!=NULL) ||
2712                                 (strchr( nameptr, '*')!=NULL));
2713       if(((*ppname_array)[i].name = strdup(nameptr)) == NULL)
2714       {
2715         DEBUG(0,("set_namearray: malloc fail (1)\n"));
2716         return;
2717       }
2718
2719       /* next segment please */
2720       nameptr = name_end + 1;
2721       i++;
2722     }
2723   
2724   (*ppname_array)[i].name = NULL;
2725
2726   return;
2727 }
2728
2729 /****************************************************************************
2730 routine to free a namearray.
2731 ****************************************************************************/
2732
2733 void free_namearray(name_compare_entry *name_array)
2734 {
2735   if(name_array == 0)
2736     return;
2737
2738   if(name_array->name != NULL)
2739     free(name_array->name);
2740
2741   free((char *)name_array);
2742 }
2743
2744 /****************************************************************************
2745 routine to do file locking
2746 ****************************************************************************/
2747 BOOL fcntl_lock(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
2748 {
2749 #if HAVE_FCNTL_LOCK
2750   SMB_STRUCT_FLOCK lock;
2751   int ret;
2752
2753   if(lp_ole_locking_compat()) {
2754     SMB_OFF_T mask2= ((SMB_OFF_T)0x3) << (SMB_OFF_T_BITS-4);
2755     SMB_OFF_T mask = (mask2<<2);
2756
2757     /* make sure the count is reasonable, we might kill the lockd otherwise */
2758     count &= ~mask;
2759
2760     /* the offset is often strange - remove 2 of its bits if either of
2761        the top two bits are set. Shift the top ones by two bits. This
2762        still allows OLE2 apps to operate, but should stop lockd from
2763        dieing */
2764     if ((offset & mask) != 0)
2765       offset = (offset & ~mask) | (((offset & mask) >> 2) & mask2);
2766   } else {
2767     SMB_OFF_T mask2 = ((SMB_OFF_T)0x4) << (SMB_OFF_T_BITS-4);
2768     SMB_OFF_T mask = (mask2<<1);
2769     SMB_OFF_T neg_mask = ~mask;
2770
2771     /* interpret negative counts as large numbers */
2772     if (count < 0)
2773       count &= ~mask;
2774
2775     /* no negative offsets */
2776     if(offset < 0)
2777       offset &= ~mask;
2778
2779     /* count + offset must be in range */
2780     while ((offset < 0 || (offset + count < 0)) && mask)
2781     {
2782       offset &= ~mask;
2783       mask = ((mask >> 1) & neg_mask);
2784     }
2785   }
2786
2787   DEBUG(8,("fcntl_lock %d %d %.0f %.0f %d\n",fd,op,(double)offset,(double)count,type));
2788
2789   lock.l_type = type;
2790   lock.l_whence = SEEK_SET;
2791   lock.l_start = offset;
2792   lock.l_len = count;
2793   lock.l_pid = 0;
2794
2795   errno = 0;
2796
2797   ret = fcntl(fd,op,&lock);
2798   if (errno == EFBIG)
2799   {
2800     if( DEBUGLVL( 0 ))
2801     {
2802       dbgtext("fcntl_lock: WARNING: lock request at offset %.0f, length %.0f returned\n", (double)offset,(double)count);
2803       dbgtext("a 'file too large' error. This can happen when using 64 bit lock offsets\n");
2804       dbgtext("on 32 bit NFS mounted file systems. Retrying with 32 bit truncated length.\n");
2805     }
2806     /* 32 bit NFS file system, retry with smaller offset */
2807     errno = 0;
2808     lock.l_len = count & 0xffffffff;
2809     ret = fcntl(fd,op,&lock);
2810   }
2811
2812   if (errno != 0)
2813     DEBUG(3,("fcntl lock gave errno %d (%s)\n",errno,strerror(errno)));
2814
2815   /* a lock query */
2816   if (op == SMB_F_GETLK)
2817   {
2818     if ((ret != -1) &&
2819         (lock.l_type != F_UNLCK) && 
2820         (lock.l_pid != 0) && 
2821         (lock.l_pid != getpid()))
2822     {
2823       DEBUG(3,("fd %d is locked by pid %d\n",fd,(int)lock.l_pid));
2824       return(True);
2825     }
2826
2827     /* it must be not locked or locked by me */
2828     return(False);
2829   }
2830
2831   /* a lock set or unset */
2832   if (ret == -1)
2833   {
2834     DEBUG(3,("lock failed at offset %.0f count %.0f op %d type %d (%s)\n",
2835           (double)offset,(double)count,op,type,strerror(errno)));
2836
2837     /* perhaps it doesn't support this sort of locking?? */
2838     if (errno == EINVAL)
2839     {
2840       DEBUG(3,("locking not supported? returning True\n"));
2841       return(True);
2842     }
2843
2844     return(False);
2845   }
2846
2847   /* everything went OK */
2848   DEBUG(8,("Lock call successful\n"));
2849
2850   return(True);
2851 #else
2852   return(False);
2853 #endif
2854 }
2855
2856 /*******************************************************************
2857 is the name specified one of my netbios names
2858 returns true is it is equal, false otherwise
2859 ********************************************************************/
2860 BOOL is_myname(char *s)
2861 {
2862   int n;
2863   BOOL ret = False;
2864
2865   for (n=0; my_netbios_names[n]; n++) {
2866     if (strequal(my_netbios_names[n], s))
2867       ret=True;
2868   }
2869   DEBUG(8, ("is_myname(\"%s\") returns %d\n", s, ret));
2870   return(ret);
2871 }
2872
2873 /*******************************************************************
2874 set the horrid remote_arch string based on an enum.
2875 ********************************************************************/
2876 void set_remote_arch(enum remote_arch_types type)
2877 {
2878   ra_type = type;
2879   switch( type )
2880   {
2881   case RA_WFWG:
2882     fstrcpy(remote_arch, "WfWg");
2883     return;
2884   case RA_OS2:
2885     fstrcpy(remote_arch, "OS2");
2886     return;
2887   case RA_WIN95:
2888     fstrcpy(remote_arch, "Win95");
2889     return;
2890   case RA_WINNT:
2891     fstrcpy(remote_arch, "WinNT");
2892     return;
2893   case RA_SAMBA:
2894     fstrcpy(remote_arch,"Samba");
2895     return;
2896   default:
2897     ra_type = RA_UNKNOWN;
2898     fstrcpy(remote_arch, "UNKNOWN");
2899     break;
2900   }
2901 }
2902
2903 /*******************************************************************
2904  Get the remote_arch type.
2905 ********************************************************************/
2906 enum remote_arch_types get_remote_arch(void)
2907 {
2908   return ra_type;
2909 }
2910
2911
2912 /*******************************************************************
2913 align a pointer to a multiple of 2 bytes
2914 ********************************************************************/
2915 char *align2(char *q, char *base)
2916 {
2917         if ((q - base) & 1)
2918         {
2919                 q++;
2920         }
2921         return q;
2922 }
2923
2924 void out_ascii(FILE *f, unsigned char *buf,int len)
2925 {
2926         int i;
2927         for (i=0;i<len;i++)
2928         {
2929                 fprintf(f, "%c", isprint(buf[i])?buf[i]:'.');
2930         }
2931 }
2932
2933 void out_data(FILE *f,char *buf1,int len, int per_line)
2934 {
2935         unsigned char *buf = (unsigned char *)buf1;
2936         int i=0;
2937         if (len<=0)
2938         {
2939                 return;
2940         }
2941
2942         fprintf(f, "[%03X] ",i);
2943         for (i=0;i<len;)
2944         {
2945                 fprintf(f, "%02X ",(int)buf[i]);
2946                 i++;
2947                 if (i%(per_line/2) == 0) fprintf(f, " ");
2948                 if (i%per_line == 0)
2949                 {      
2950                         out_ascii(f,&buf[i-per_line  ],per_line/2); fprintf(f, " ");
2951                         out_ascii(f,&buf[i-per_line/2],per_line/2); fprintf(f, "\n");
2952                         if (i<len) fprintf(f, "[%03X] ",i);
2953                 }
2954         }
2955         if ((i%per_line) != 0)
2956         {
2957                 int n;
2958
2959                 n = per_line - (i%per_line);
2960                 fprintf(f, " ");
2961                 if (n>(per_line/2)) fprintf(f, " ");
2962                 while (n--)
2963                 {
2964                         fprintf(f, "   ");
2965                 }
2966                 n = MIN(per_line/2,i%per_line);
2967                 out_ascii(f,&buf[i-(i%per_line)],n); fprintf(f, " ");
2968                 n = (i%per_line) - n;
2969                 if (n>0) out_ascii(f,&buf[i-n],n); 
2970                 fprintf(f, "\n");    
2971         }
2972 }
2973
2974 void print_asc(int level, unsigned char *buf,int len)
2975 {
2976         int i;
2977         for (i=0;i<len;i++)
2978         {
2979                 DEBUGADD(level,("%c", isprint(buf[i])?buf[i]:'.'));
2980         }
2981 }
2982
2983 void dump_data(int level,char *buf1, int len)
2984 {
2985         unsigned char *buf = (unsigned char *)buf1;
2986         int i=0;
2987         if (len<=0) return;
2988
2989         DEBUG(level,("[%03X] ",i));
2990         for (i=0;i<len;)
2991         {
2992                 DEBUGADD(level,("%02X ",(int)buf[i]));
2993                 i++;
2994                 if (i%8 == 0) DEBUGADD(level,(" "));
2995                 if (i%16 == 0)
2996                 {      
2997                         print_asc(level,&buf[i-16],8); DEBUGADD(level,(" "));
2998                         print_asc(level,&buf[i-8],8); DEBUGADD(level,("\n"));
2999                         if (i<len) DEBUGADD(level,("[%03X] ",i));
3000                 }
3001         }
3002
3003         if (i%16 != 0) /* finish off a non-16-char-length row */
3004         {
3005                 int n;
3006
3007                 n = 16 - (i%16);
3008                 DEBUGADD(level,(" "));
3009                 if (n>8) DEBUGADD(level,(" "));
3010                 while (n--) DEBUGADD(level,("   "));
3011
3012                 n = MIN(8,i%16);
3013                 print_asc(level,&buf[i-(i%16)],n); DEBUGADD(level,(" "));
3014                 n = (i%16) - n;
3015                 if (n>0) print_asc(level,&buf[i-n],n); 
3016                 DEBUGADD(level,("\n"));    
3017         }
3018 }
3019
3020 char *tab_depth(int depth)
3021 {
3022         static pstring spaces;
3023         memset(spaces, ' ', depth * 4);
3024         spaces[depth * 4] = 0;
3025         return spaces;
3026 }
3027
3028 /*****************************************************************************
3029  * Provide a checksum on a string
3030  *
3031  *  Input:  s - the null-terminated character string for which the checksum
3032  *              will be calculated.
3033  *
3034  *  Output: The checksum value calculated for s.
3035  *
3036  * ****************************************************************************
3037  */
3038 int str_checksum(const char *s)
3039 {
3040         int res = 0;
3041         int c;
3042         int i=0;
3043         
3044         while(*s) {
3045                 c = *s;
3046                 res ^= (c << (i % 15)) ^ (c >> (15-(i%15)));
3047                 s++;
3048                 i++;
3049         }
3050         return(res);
3051 } /* str_checksum */
3052
3053
3054
3055 /*****************************************************************
3056 zero a memory area then free it. Used to catch bugs faster
3057 *****************************************************************/  
3058 void zero_free(void *p, size_t size)
3059 {
3060         memset(p, 0, size);
3061         free(p);
3062 }
3063
3064
3065 /*****************************************************************
3066 set our open file limit to a requested max and return the limit
3067 *****************************************************************/  
3068 int set_maxfiles(int requested_max)
3069 {
3070 #if (defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE))
3071         struct rlimit rlp;
3072         getrlimit(RLIMIT_NOFILE, &rlp);
3073         /* Set the fd limit to be real_max_open_files + MAX_OPEN_FUDGEFACTOR to
3074          * account for the extra fd we need 
3075          * as well as the log files and standard
3076          * handles etc.  */
3077         rlp.rlim_cur = MIN(requested_max,rlp.rlim_max);
3078         setrlimit(RLIMIT_NOFILE, &rlp);
3079         getrlimit(RLIMIT_NOFILE, &rlp);
3080         return rlp.rlim_cur;
3081 #else
3082         /*
3083          * No way to know - just guess...
3084          */
3085         return requested_max;
3086 #endif
3087 }
3088
3089
3090 /*****************************************************************
3091  splits out the last subkey of a key
3092  *****************************************************************/  
3093 void reg_get_subkey(char *full_keyname, char *key_name, char *subkey_name)
3094 {
3095         split_at_last_component(full_keyname, key_name, '\\', subkey_name);
3096 }
3097
3098 /*****************************************************************
3099  splits out the start of the key (HKLM or HKU) and the rest of the key
3100  *****************************************************************/  
3101 BOOL reg_split_key(char *full_keyname, uint32 *reg_type, char *key_name)
3102 {
3103         pstring tmp;
3104
3105         if (!next_token(&full_keyname, tmp, "\\", sizeof(tmp)))
3106         {
3107                 return False;
3108         }
3109
3110         (*reg_type) = 0;
3111
3112         DEBUG(10, ("reg_split_key: hive %s\n", tmp));
3113
3114         if (strequal(tmp, "HKLM") || strequal(tmp, "HKEY_LOCAL_MACHINE"))
3115         {
3116                 (*reg_type) = HKEY_LOCAL_MACHINE;
3117         }
3118         else if (strequal(tmp, "HKU") || strequal(tmp, "HKEY_USERS"))
3119         {
3120                 (*reg_type) = HKEY_USERS;
3121         }
3122         else
3123         {
3124                 DEBUG(10,("reg_split_key: unrecognised hive key %s\n", tmp));
3125                 return False;
3126         }
3127         
3128         if (next_token(NULL, tmp, "\n\r", sizeof(tmp)))
3129         {
3130                 fstrcpy(key_name, tmp);
3131         }
3132         else
3133         {
3134                 key_name[0] = 0;
3135         }
3136
3137         DEBUG(10, ("reg_split_key: name %s\n", key_name));
3138
3139         return True;
3140 }
3141
3142 /****************************************************************************
3143   become the specified uid - permanently !
3144 ****************************************************************************/
3145 BOOL become_user_permanently(uid_t uid, gid_t gid)
3146 {
3147         /* now completely lose our privilages. This is a fairly paranoid
3148            way of doing it, but it does work on all systems that I know of */
3149
3150 #ifdef HAVE_SETRESUID
3151         /*
3152          * Firstly ensure all our uids are set to root.
3153          */
3154         setresgid(0,0,0);
3155         setresuid(0,0,0);
3156
3157         /*
3158          * Now ensure we change all our gids.
3159          */
3160         setresgid(gid,gid,gid);
3161         
3162         /*
3163          * Now ensure all the uids are the user.
3164          */
3165         setresuid(uid,uid,uid);
3166 #else
3167         /*
3168          * Firstly ensure all our uids are set to root.
3169          */
3170         setuid(0);
3171         seteuid(0);
3172         
3173         /*
3174          * Now ensure we change all our gids.
3175          */
3176         setgid(gid);
3177         setegid(gid);
3178         
3179         /*
3180          * Now ensure all the uids are the user.
3181          */
3182         setuid(uid);
3183         seteuid(uid);
3184 #endif
3185         
3186         if (getuid() != uid || geteuid() != uid ||
3187             getgid() != gid || getegid() != gid) {
3188                 /* We failed to lose our privilages. */
3189                 return False;
3190         }
3191         
3192         return(True);
3193 }