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