1d024770739de61acefea44cd750cbd62bba7207
[kai/samba.git] / source3 / smbd / server.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Main SMB server routines
5    Copyright (C) Andrew Tridgell 1992-1995
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 #include "loadparm.h"
24 #include "pcap.h"
25 #include "trans2.h"
26 #include "reply.h"
27
28 pstring servicesf = CONFIGFILE;
29 pstring OriginalDir ="/";
30 extern pstring debugf;
31 extern pstring sesssetup_user;
32
33 char *InBuffer = NULL;
34 char *OutBuffer = NULL;
35 char *last_inbuf = NULL;
36
37 int initial_uid = 0;
38 int initial_gid = 0;
39
40 BOOL share_mode_pending = False;
41
42 /* have I done a become_user? */
43 static struct {
44   int cnum, uid;
45 } last_user;
46
47 /* the last message the was processed */
48 int last_message = -1;
49
50 /* a useful macro to debug the last message processed */
51 #define LAST_MESSAGE() smb_fn_name(last_message)
52
53 extern pstring scope;
54 extern int DEBUGLEVEL;
55 extern int case_default;
56 extern BOOL case_sensitive;
57 extern BOOL case_preserve;
58 extern BOOL use_mangled_map;
59 extern BOOL short_case_preserve;
60 extern BOOL case_mangle;
61 extern time_t smb_last_time;
62
63 extern pstring user_socket_options;
64
65 connection_struct Connections[MAX_CONNECTIONS];
66 files_struct Files[MAX_OPEN_FILES];
67
68 extern int Protocol;
69
70 int maxxmit = BUFFER_SIZE;
71
72 int chain_size = 0;
73
74 /* a fnum to use when chaining */
75 int chain_fnum = -1;
76
77 /* number of open connections */
78 static int num_connections_open = 0;
79
80 extern fstring remote_machine;
81
82
83 /* these can be set by some functions to override the error codes */
84 int unix_ERR_class=SUCCESS;
85 int unix_ERR_code=0;
86
87
88 extern int extra_time_offset;
89
90 extern pstring myhostname;
91 extern struct in_addr myip;
92
93
94 static int find_free_connection(int hash);
95
96 #ifdef SMB_PASSWD
97 extern void generate_next_challenge(char *challenge);
98 extern void set_challenge(char *challenge);
99 #endif
100
101 /* for readability... */
102 #define IS_DOS_READONLY(test_mode) (((test_mode) & aRONLY) != 0)
103 #define IS_DOS_DIR(test_mode) (((test_mode) & aDIR) != 0)
104 #define IS_DOS_ARCHIVE(test_mode) (((test_mode) & aARCH) != 0)
105 #define IS_DOS_SYSTEM(test_mode) (((test_mode) & aSYSTEM) != 0)
106 #define IS_DOS_HIDDEN(test_mode) (((test_mode) & aHIDDEN) != 0)
107
108
109
110 /****************************************************************************
111   change a dos mode to a unix mode
112     base permission for files:
113          everybody gets read bit set
114          dos readonly is represented in unix by removing everyone's write bit
115          dos archive is represented in unix by the user's execute bit
116          dos system is represented in unix by the group's execute bit
117          dos hidden is represented in unix by the other's execute bit
118     base permission for directories:
119          dos directory is represented in unix by unix's dir bit and the exec bit
120 ****************************************************************************/
121 mode_t unix_mode(int cnum,int dosmode)
122 {
123   mode_t result = (S_IRUSR | S_IRGRP | S_IROTH);
124
125   if ( !IS_DOS_READONLY(dosmode) )
126     result |= (S_IWUSR | S_IWGRP | S_IWOTH);
127  
128   if (IS_DOS_DIR(dosmode))
129     result |= (S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH | S_IWUSR);
130  
131   if (MAP_ARCHIVE(cnum) && IS_DOS_ARCHIVE(dosmode))
132     result |= S_IXUSR;
133
134   if (MAP_SYSTEM(cnum) && IS_DOS_SYSTEM(dosmode))
135     result |= S_IXGRP;
136  
137   if (MAP_HIDDEN(cnum) && IS_DOS_HIDDEN(dosmode))
138     result |= S_IXOTH;  
139  
140   result &= CREATE_MODE(cnum);
141   return(result);
142 }
143
144
145 /****************************************************************************
146   change a unix mode to a dos mode
147 ****************************************************************************/
148 int dos_mode(int cnum,char *path,struct stat *sbuf)
149 {
150   int result = 0;
151
152 #if OLD_DOS_MODE
153   if (!CAN_WRITE(cnum) || !((sbuf->st_mode & S_IWOTH) ||
154                             Connections[cnum].admin_user ||
155                             ((sbuf->st_mode & S_IWUSR) && 
156                              Connections[cnum].uid==sbuf->st_uid) ||
157                             ((sbuf->st_mode & S_IWGRP) && 
158                              in_group(sbuf->st_gid,Connections[cnum].gid,
159                                       Connections[cnum].ngroups,
160                                       Connections[cnum].igroups))))
161     result |= aRONLY;
162 #else
163   if (CAN_WRITE(cnum) && !lp_alternate_permissions(SNUM(cnum))) {
164     if (!((sbuf->st_mode & S_IWOTH) ||
165           Connections[cnum].admin_user ||
166           ((sbuf->st_mode & S_IWUSR) && Connections[cnum].uid==sbuf->st_uid) ||
167           ((sbuf->st_mode & S_IWGRP) && 
168            in_group(sbuf->st_gid,Connections[cnum].gid,
169                     Connections[cnum].ngroups,Connections[cnum].igroups))))
170       result |= aRONLY;
171   } else {
172     if ((sbuf->st_mode & S_IWUSR) == 0)
173       result |= aRONLY;
174   }
175 #endif
176
177   if ((sbuf->st_mode & S_IXUSR) != 0)
178     result |= aARCH;
179
180   if (MAP_SYSTEM(cnum) && ((sbuf->st_mode & S_IXGRP) != 0))
181     result |= aSYSTEM;
182
183   if (MAP_HIDDEN(cnum) && ((sbuf->st_mode & S_IXOTH) != 0))
184     result |= aHIDDEN;   
185   
186   if (S_ISDIR(sbuf->st_mode))
187     result = aDIR | (result & aRONLY);
188
189 #if LINKS_READ_ONLY
190   if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
191     result |= aRONLY;
192 #endif
193
194   /* hide files with a name starting with a . */
195   if (lp_hide_dot_files(SNUM(cnum)))
196     {
197       char *p = strrchr(path,'/');
198       if (p)
199         p++;
200       else
201         p = path;
202       
203       if (p[0] == '.' && p[1] != '.' && p[1] != 0)
204         result |= aHIDDEN;
205     }
206
207   return(result);
208 }
209
210
211 /*******************************************************************
212 chmod a file - but preserve some bits
213 ********************************************************************/
214 int dos_chmod(int cnum,char *fname,int dosmode,struct stat *st)
215 {
216   struct stat st1;
217   int mask=0;
218   int tmp;
219   int unixmode;
220
221   if (!st) {
222     st = &st1;
223     if (sys_stat(fname,st)) return(-1);
224   }
225
226   if (S_ISDIR(st->st_mode)) dosmode |= aDIR;
227
228   if (dos_mode(cnum,fname,st) == dosmode) return(0);
229
230   unixmode = unix_mode(cnum,dosmode);
231
232   /* preserve the s bits */
233   mask |= (S_ISUID | S_ISGID);
234
235   /* preserve the t bit */
236 #ifdef S_ISVTX
237   mask |= S_ISVTX;
238 #endif
239
240   /* possibly preserve the x bits */
241   if (!MAP_ARCHIVE(cnum)) mask |= S_IXUSR;
242   if (!MAP_SYSTEM(cnum)) mask |= S_IXGRP;
243   if (!MAP_HIDDEN(cnum)) mask |= S_IXOTH;
244
245   unixmode |= (st->st_mode & mask);
246
247   /* if we previously had any r bits set then leave them alone */
248   if ((tmp = st->st_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
249     unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
250     unixmode |= tmp;
251   }
252
253   /* if we previously had any w bits set then leave them alone 
254    if the new mode is not rdonly */
255   if (!IS_DOS_READONLY(dosmode) &&
256       (tmp = st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH))) {
257     unixmode &= ~(S_IWUSR|S_IWGRP|S_IWOTH);
258     unixmode |= tmp;
259   }
260
261   return(chmod(fname,unixmode));
262 }
263
264
265 /****************************************************************************
266 check if two filenames are equal
267
268 this needs to be careful about whether we are case sensitive
269 ****************************************************************************/
270 static BOOL fname_equal(char *name1, char *name2)
271 {
272   int l1 = strlen(name1);
273   int l2 = strlen(name2);
274
275   /* handle filenames ending in a single dot */
276   if (l1-l2 == 1 && name1[l1-1] == '.' && lp_strip_dot())
277     {
278       BOOL ret;
279       name1[l1-1] = 0;
280       ret = fname_equal(name1,name2);
281       name1[l1-1] = '.';
282       return(ret);
283     }
284
285   if (l2-l1 == 1 && name2[l2-1] == '.' && lp_strip_dot())
286     {
287       BOOL ret;
288       name2[l2-1] = 0;
289       ret = fname_equal(name1,name2);
290       name2[l2-1] = '.';
291       return(ret);
292     }
293
294   /* now normal filename handling */
295   if (case_sensitive)
296     return(strcmp(name1,name2) == 0);
297
298   return(strequal(name1,name2));
299 }
300
301
302 /****************************************************************************
303 mangle the 2nd name and check if it is then equal to the first name
304 ****************************************************************************/
305 static BOOL mangled_equal(char *name1, char *name2)
306 {
307   pstring tmpname;
308
309   if (is_8_3(name2))
310     return(False);
311
312   strcpy(tmpname,name2);
313   mangle_name_83(tmpname);
314
315   return(strequal(name1,tmpname));
316 }
317
318
319 /****************************************************************************
320 scan a directory to find a filename, matching without case sensitivity
321
322 If the name looks like a mangled name then try via the mangling functions
323 ****************************************************************************/
324 static BOOL scan_directory(char *path, char *name,int snum,BOOL docache)
325 {
326   void *cur_dir;
327   char *dname;
328   BOOL mangled;
329   pstring name2;
330
331   mangled = is_mangled(name);
332
333   /* handle null paths */
334   if (*path == 0)
335     path = ".";
336
337   if (docache && (dname = DirCacheCheck(path,name,snum))) {
338     strcpy(name, dname);        
339     return(True);
340   }      
341
342   if (mangled)
343     check_mangled_stack(name);
344
345   /* open the directory */
346   if (!(cur_dir = OpenDir(path))) 
347     {
348       DEBUG(3,("scan dir didn't open dir [%s]\n",path));
349       return(False);
350     }
351
352   /* now scan for matching names */
353   while ((dname = ReadDirName(cur_dir))) 
354     {
355       if (*dname == '.' &&
356           (strequal(dname,".") || strequal(dname,"..")))
357         continue;
358
359       strcpy(name2,dname);
360       if (!name_map_mangle(name2,False,snum)) continue;
361
362       if ((mangled && mangled_equal(name,name2))
363           || fname_equal(name, name2))
364         {
365           /* we've found the file, change it's name and return */
366           if (docache) DirCacheAdd(path,name,dname,snum);
367           strcpy(name, dname);
368           CloseDir(cur_dir);
369           return(True);
370         }
371     }
372
373   CloseDir(cur_dir);
374   return(False);
375 }
376
377 /****************************************************************************
378 This routine is called to convert names from the dos namespace to unix
379 namespace. It needs to handle any case conversions, mangling, format
380 changes etc.
381
382 We assume that we have already done a chdir() to the right "root" directory
383 for this service.
384
385 The function will return False if some part of the name except for the last
386 part cannot be resolved
387 ****************************************************************************/
388 BOOL unix_convert(char *name,int cnum)
389 {
390   struct stat st;
391   char *start, *end;
392   pstring dirpath;
393
394   *dirpath = 0;
395
396   /* convert to basic unix format - removing \ chars and cleaning it up */
397   unix_format(name);
398   unix_clean_name(name);
399
400   if (!case_sensitive && 
401       (!case_preserve || (is_8_3(name) && !short_case_preserve)))
402     strnorm(name);
403
404   /* names must be relative to the root of the service - trim any leading /.
405    also trim trailing /'s */
406   trim_string(name,"/","/");
407
408   /* check if it's a printer file */
409   if (Connections[cnum].printer)
410     {
411       if ((! *name) || strchr(name,'/') || !is_8_3(name))
412         {
413           char *s;
414           fstring name2;
415           sprintf(name2,"%.6s.XXXXXX",remote_machine);
416           /* sanitise the name */
417           for (s=name2 ; *s ; s++)
418             if (!issafe(*s)) *s = '_';
419           strcpy(name,(char *)mktemp(name2));     
420         }      
421       return(True);
422     }
423
424   /* stat the name - if it exists then we are all done! */
425   if (sys_stat(name,&st) == 0)
426     return(True);
427
428   DEBUG(5,("unix_convert(%s,%d)\n",name,cnum));
429
430   /* a special case - if we don't have any mangling chars and are case
431      sensitive then searching won't help */
432   if (case_sensitive && !is_mangled(name) && 
433       !lp_strip_dot() && !use_mangled_map)
434     return(False);
435
436   /* now we need to recursively match the name against the real 
437      directory structure */
438
439   start = name;
440   while (strncmp(start,"./",2) == 0)
441     start += 2;
442
443   /* now match each part of the path name separately, trying the names
444      as is first, then trying to scan the directory for matching names */
445   for (;start;start = (end?end+1:(char *)NULL)) 
446     {
447       /* pinpoint the end of this section of the filename */
448       end = strchr(start, '/');
449
450       /* chop the name at this point */
451       if (end) *end = 0;
452
453       /* check if the name exists up to this point */
454       if (sys_stat(name, &st) == 0) 
455         {
456           /* it exists. it must either be a directory or this must be
457              the last part of the path for it to be OK */
458           if (end && !(st.st_mode & S_IFDIR)) 
459             {
460               /* an intermediate part of the name isn't a directory */
461               DEBUG(5,("Not a dir %s\n",start));
462               *end = '/';
463               return(False);
464             }
465         }
466       else 
467         {
468           pstring rest;
469
470           *rest = 0;
471
472           /* remember the rest of the pathname so it can be restored
473              later */
474           if (end) strcpy(rest,end+1);
475
476
477           /* try to find this part of the path in the directory */
478           if (strchr(start,'?') || strchr(start,'*') ||
479               !scan_directory(dirpath, start, SNUM(cnum), end?True:False))
480             {
481               if (end) 
482                 {
483                   /* an intermediate part of the name can't be found */
484                   DEBUG(5,("Intermediate not found %s\n",start));
485                   *end = '/';
486                   return(False);
487                 }
488               
489               /* just the last part of the name doesn't exist */
490               /* we may need to strupper() or strlower() it in case
491                  this conversion is being used for file creation 
492                  purposes */
493               /* if the filename is of mixed case then don't normalise it */
494               if (!case_preserve && 
495                   (!strhasupper(start) || !strhaslower(start)))         
496                 strnorm(start);
497
498               /* check on the mangled stack to see if we can recover the 
499                  base of the filename */
500               if (is_mangled(start))
501                 check_mangled_stack(start);
502
503               DEBUG(5,("New file %s\n",start));
504               return(True); 
505             }
506
507           /* restore the rest of the string */
508           if (end) 
509             {
510               strcpy(start+strlen(start)+1,rest);
511               end = start + strlen(start);
512             }
513         }
514
515       /* add to the dirpath that we have resolved so far */
516       if (*dirpath) strcat(dirpath,"/");
517       strcat(dirpath,start);
518
519       /* restore the / that we wiped out earlier */
520       if (end) *end = '/';
521     }
522   
523   /* the name has been resolved */
524   DEBUG(5,("conversion finished %s\n",name));
525   return(True);
526 }
527
528
529 /****************************************************************************
530 normalise for DOS usage 
531 ****************************************************************************/
532 static void disk_norm(int *bsize,int *dfree,int *dsize)
533 {
534   /* check if the disk is beyond the max disk size */
535   int maxdisksize = lp_maxdisksize();
536   if (maxdisksize) {
537     /* convert to blocks - and don't overflow */
538     maxdisksize = ((maxdisksize*1024)/(*bsize))*1024;
539     if (*dsize > maxdisksize) *dsize = maxdisksize;
540     if (*dfree > maxdisksize) *dfree = maxdisksize-1; /* the -1 should stop 
541                                                          applications getting 
542                                                          div by 0 errors */
543   }  
544
545   while (*dfree > WORDMAX || *dsize > WORDMAX || *bsize < 512) 
546     {
547       *dfree /= 2;
548       *dsize /= 2;
549       *bsize *= 2;
550       if (*bsize > WORDMAX )
551         {
552           *bsize = WORDMAX;
553           if (*dsize > WORDMAX)
554             *dsize = WORDMAX;
555           if (*dfree >  WORDMAX)
556             *dfree = WORDMAX;
557           break;
558         }
559     }
560 }
561
562 /****************************************************************************
563   return number of 1K blocks available on a path and total number 
564 ****************************************************************************/
565 int disk_free(char *path,int *bsize,int *dfree,int *dsize)
566 {
567   char *df_command = lp_dfree_command();
568 #ifndef NO_STATFS
569 #ifdef USE_STATVFS
570   struct statvfs fs;
571 #else
572 #ifdef ULTRIX
573   struct fs_data fs;
574 #else
575   struct statfs fs;
576 #endif
577 #endif
578 #endif
579
580 #ifdef QUOTAS
581   if (disk_quotas(path, bsize, dfree, dsize))
582     {
583       disk_norm(bsize,dfree,dsize);
584       return(((*bsize)/1024)*(*dfree));
585     }
586 #endif
587
588
589   /* possibly use system() to get the result */
590   if (df_command && *df_command)
591     {
592       int ret;
593       pstring syscmd;
594       pstring outfile;
595           
596       sprintf(outfile,"/tmp/dfree.smb.%d",(int)getpid());
597       sprintf(syscmd,"%s %s",df_command,path);
598       standard_sub_basic(syscmd);
599
600       ret = smbrun(syscmd,outfile);
601       DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
602           
603       {
604         FILE *f = fopen(outfile,"r");   
605         *dsize = 0;
606         *dfree = 0;
607         *bsize = 1024;
608         if (f)
609           {
610             fscanf(f,"%d %d %d",dsize,dfree,bsize);
611             fclose(f);
612           }
613         else
614           DEBUG(0,("Can't open %s\n",outfile));
615       }
616           
617       unlink(outfile);
618       disk_norm(bsize,dfree,dsize);
619       return(((*bsize)/1024)*(*dfree));
620     }
621
622 #ifdef NO_STATFS
623   DEBUG(1,("Warning - no statfs function\n"));
624   return(1);
625 #else
626 #ifdef STATFS4
627   if (statfs(path,&fs,sizeof(fs),0) != 0)
628 #else
629 #ifdef USE_STATVFS
630     if (statvfs(path, &fs))
631 #else
632 #ifdef STATFS3
633       if (statfs(path,&fs,sizeof(fs)) == -1)     
634 #else
635         if (statfs(path,&fs) == -1)
636 #endif /* STATFS3 */
637 #endif /* USE_STATVFS */
638 #endif /* STATFS4 */
639           {
640             DEBUG(3,("dfree call failed code errno=%d\n",errno));
641             *bsize = 1024;
642             *dfree = 1;
643             *dsize = 1;
644             return(((*bsize)/1024)*(*dfree));
645           }
646
647 #ifdef ULTRIX
648   *bsize = 1024;
649   *dfree = fs.fd_req.bfree;
650   *dsize = fs.fd_req.btot;
651 #else
652 #ifdef USE_STATVFS
653   *bsize = fs.f_frsize;
654 #else
655 #ifdef USE_F_FSIZE
656   /* eg: osf1 has f_fsize = fundamental filesystem block size, 
657      f_bsize = optimal transfer block size (MX: 94-04-19) */
658   *bsize = fs.f_fsize;
659 #else
660   *bsize = fs.f_bsize;
661 #endif /* STATFS3 */
662 #endif /* USE_STATVFS */
663
664 #ifdef STATFS4
665   *dfree = fs.f_bfree;
666 #else
667   *dfree = fs.f_bavail;
668 #endif /* STATFS4 */
669   *dsize = fs.f_blocks;
670 #endif /* ULTRIX */
671
672 #if defined(SCO) || defined(ISC) || defined(MIPS)
673   *bsize = 512;
674 #endif
675
676 /* handle rediculous bsize values - some OSes are broken */
677 if ((*bsize) < 512 || (*bsize)>0xFFFF) *bsize = 1024;
678
679   disk_norm(bsize,dfree,dsize);
680
681   if (*bsize < 256)
682     *bsize = 512;
683   if ((*dsize)<1)
684     {
685       DEBUG(0,("dfree seems to be broken on your system\n"));
686       *dsize = 20*1024*1024/(*bsize);
687       *dfree = MAX(1,*dfree);
688     }
689   return(((*bsize)/1024)*(*dfree));
690 #endif
691 }
692
693
694 /****************************************************************************
695 wrap it to get filenames right
696 ****************************************************************************/
697 int sys_disk_free(char *path,int *bsize,int *dfree,int *dsize)
698 {
699   return(disk_free(dos_to_unix(path,False),bsize,dfree,dsize));
700 }
701
702
703
704 /****************************************************************************
705 check a filename - possibly caling reducename
706
707 This is called by every routine before it allows an operation on a filename.
708 It does any final confirmation necessary to ensure that the filename is
709 a valid one for the user to access.
710 ****************************************************************************/
711 BOOL check_name(char *name,int cnum)
712 {
713   BOOL ret;
714
715   errno = 0;
716
717   ret = reduce_name(name,Connections[cnum].connectpath,lp_widelinks(SNUM(cnum)));
718   if (!ret)
719     DEBUG(5,("check_name on %s failed\n",name));
720
721   return(ret);
722 }
723
724 /****************************************************************************
725 check a filename - possibly caling reducename
726 ****************************************************************************/
727 static void check_for_pipe(char *fname)
728 {
729   /* special case of pipe opens */
730   char s[10];
731   StrnCpy(s,fname,9);
732   strlower(s);
733   if (strstr(s,"pipe/"))
734     {
735       DEBUG(3,("Rejecting named pipe open for %s\n",fname));
736       unix_ERR_class = ERRSRV;
737       unix_ERR_code = ERRaccess;
738     }
739 }
740
741
742 /****************************************************************************
743 open a file
744 ****************************************************************************/
745 void open_file(int fnum,int cnum,char *fname1,int flags,int mode)
746 {
747   pstring fname;
748
749   Files[fnum].open = False;
750   Files[fnum].fd = -1;
751   errno = EPERM;
752
753   strcpy(fname,fname1);
754
755   /* check permissions */
756   if ((flags != O_RDONLY) && !CAN_WRITE(cnum) && !Connections[cnum].printer)
757     {
758       DEBUG(3,("Permission denied opening %s\n",fname));
759       check_for_pipe(fname);
760       return;
761     }
762
763   /* this handles a bug in Win95 - it doesn't say to create the file when it 
764      should */
765   if (Connections[cnum].printer)
766     flags |= O_CREAT;
767
768 /*
769   if (flags == O_WRONLY)
770     DEBUG(3,("Bug in client? Set O_WRONLY without O_CREAT\n"));
771 */
772
773 #if UTIME_WORKAROUND
774   /* XXXX - is this OK?? */
775   /* this works around a utime bug but can cause other problems */
776   if ((flags & (O_WRONLY|O_RDWR)) && (flags & O_CREAT) && !(flags & O_APPEND))
777     sys_unlink(fname);
778 #endif
779
780
781   Files[fnum].fd = sys_open(fname,flags,mode);
782
783   if ((Files[fnum].fd>=0) && 
784       Connections[cnum].printer && lp_minprintspace(SNUM(cnum))) {
785     pstring dname;
786     int dum1,dum2,dum3;
787     char *p;
788     strcpy(dname,fname);
789     p = strrchr(dname,'/');
790     if (p) *p = 0;
791     if (sys_disk_free(dname,&dum1,&dum2,&dum3) < 
792         lp_minprintspace(SNUM(cnum))) {
793       close(Files[fnum].fd);
794       Files[fnum].fd = -1;
795       sys_unlink(fname);
796       errno = ENOSPC;
797       return;
798     }
799   }
800     
801
802   /* Fix for files ending in '.' */
803   if((Files[fnum].fd == -1) && (errno == ENOENT) && 
804      (strchr(fname,'.')==NULL))
805     {
806       strcat(fname,".");
807       Files[fnum].fd = sys_open(fname,flags,mode);
808     }
809
810 #if (defined(ENAMETOOLONG) && defined(HAVE_PATHCONF))
811   if ((Files[fnum].fd == -1) && (errno == ENAMETOOLONG))
812     {
813       int max_len;
814       char *p = strrchr(fname, '/');
815
816       if (p == fname)   /* name is "/xxx" */
817         {
818           max_len = pathconf("/", _PC_NAME_MAX);
819           p++;
820         }
821       else if ((p == NULL) || (p == fname))
822         {
823           p = fname;
824           max_len = pathconf(".", _PC_NAME_MAX);
825         }
826       else
827         {
828           *p = '\0';
829           max_len = pathconf(fname, _PC_NAME_MAX);
830           *p = '/';
831           p++;
832         }
833       if (strlen(p) > max_len)
834         {
835           char tmp = p[max_len];
836
837           p[max_len] = '\0';
838           if ((Files[fnum].fd = sys_open(fname,flags,mode)) == -1)
839             p[max_len] = tmp;
840         }
841     }
842 #endif
843
844   if (Files[fnum].fd < 0)
845     {
846       DEBUG(3,("Error opening file %s (%s) (flags=%d)\n",
847                fname,strerror(errno),flags));
848       check_for_pipe(fname);
849       return;
850     }
851
852   if (Files[fnum].fd >= 0)
853     {
854       struct stat st;
855       Connections[cnum].num_files_open++;
856       fstat(Files[fnum].fd,&st);
857       Files[fnum].mode = st.st_mode;
858       Files[fnum].open_time = time(NULL);
859       Files[fnum].size = 0;
860       Files[fnum].pos = -1;
861       Files[fnum].open = True;
862       Files[fnum].mmap_ptr = NULL;
863       Files[fnum].mmap_size = 0;
864       Files[fnum].can_lock = True;
865       Files[fnum].can_read = ((flags & O_WRONLY)==0);
866       Files[fnum].can_write = ((flags & (O_WRONLY|O_RDWR))!=0);
867       Files[fnum].share_mode = 0;
868       Files[fnum].share_pending = False;
869       Files[fnum].print_file = Connections[cnum].printer;
870       Files[fnum].modified = False;
871       Files[fnum].cnum = cnum;
872       string_set(&Files[fnum].name,fname);
873       Files[fnum].wbmpx_ptr = NULL;      
874
875       /*
876        * If the printer is marked as postscript output a leading
877        * file identifier to ensure the file is treated as a raw
878        * postscript file.
879        * This has a similar effect as CtrlD=0 in WIN.INI file.
880        * tim@fsg.com 09/06/94
881        */
882       if (Files[fnum].print_file && POSTSCRIPT(cnum) && 
883           Files[fnum].can_write) 
884         {
885           DEBUG(3,("Writing postscript line\n"));
886           write_file(fnum,"%!\n",3);
887         }
888       
889       DEBUG(2,("%s %s opened file %s read=%s write=%s (numopen=%d fnum=%d)\n",
890                timestring(),Connections[cnum].user,fname,
891                BOOLSTR(Files[fnum].can_read),BOOLSTR(Files[fnum].can_write),
892                Connections[cnum].num_files_open,fnum));
893
894     }
895
896 #if USE_MMAP
897   /* mmap it if read-only */
898   if (!Files[fnum].can_write)
899     {
900       Files[fnum].mmap_size = file_size(fname);
901       Files[fnum].mmap_ptr = (char *)mmap(NULL,Files[fnum].mmap_size,
902                                           PROT_READ,MAP_SHARED,Files[fnum].fd,0);
903
904       if (Files[fnum].mmap_ptr == (char *)-1 || !Files[fnum].mmap_ptr)
905         {
906           DEBUG(3,("Failed to mmap() %s - %s\n",fname,strerror(errno)));
907           Files[fnum].mmap_ptr = NULL;
908         }
909     }
910 #endif
911 }
912
913 /*******************************************************************
914 sync a file
915 ********************************************************************/
916 void sync_file(int fnum)
917 {
918 #ifndef NO_FSYNC
919   fsync(Files[fnum].fd);
920 #endif
921 }
922
923 /****************************************************************************
924 run a file if it is a magic script
925 ****************************************************************************/
926 static void check_magic(int fnum,int cnum)
927 {
928   if (!*lp_magicscript(SNUM(cnum)))
929     return;
930
931   DEBUG(5,("checking magic for %s\n",Files[fnum].name));
932
933   {
934     char *p;
935     if (!(p = strrchr(Files[fnum].name,'/')))
936       p = Files[fnum].name;
937     else
938       p++;
939
940     if (!strequal(lp_magicscript(SNUM(cnum)),p))
941       return;
942   }
943
944   {
945     int ret;
946     pstring magic_output;
947     pstring fname;
948     strcpy(fname,Files[fnum].name);
949
950     if (*lp_magicoutput(SNUM(cnum)))
951       strcpy(magic_output,lp_magicoutput(SNUM(cnum)));
952     else
953       sprintf(magic_output,"%s.out",fname);
954
955     chmod(fname,0755);
956     ret = smbrun(fname,magic_output);
957     DEBUG(3,("Invoking magic command %s gave %d\n",fname,ret));
958     unlink(fname);
959   }
960 }
961
962
963 /****************************************************************************
964 close a file - possibly invalidating the read prediction
965 ****************************************************************************/
966 void close_file(int fnum)
967 {
968   int cnum = Files[fnum].cnum;
969   invalidate_read_prediction(Files[fnum].fd);
970   Files[fnum].open = False;
971   Connections[cnum].num_files_open--;
972   if(Files[fnum].wbmpx_ptr) 
973     {
974       free((char *)Files[fnum].wbmpx_ptr);
975       Files[fnum].wbmpx_ptr = NULL;
976     }
977
978 #if USE_MMAP
979   if(Files[fnum].mmap_ptr) 
980     {
981       munmap(Files[fnum].mmap_ptr,Files[fnum].mmap_size);
982       Files[fnum].mmap_ptr = NULL;
983     }
984 #endif
985
986   if (lp_share_modes(SNUM(cnum)))
987     del_share_mode(fnum);
988
989   close(Files[fnum].fd);
990
991   /* NT uses smbclose to start a print - weird */
992   if (Files[fnum].print_file)
993     print_file(fnum);
994
995   /* check for magic scripts */
996   check_magic(fnum,cnum);
997
998   DEBUG(2,("%s %s closed file %s (numopen=%d)\n",
999            timestring(),Connections[cnum].user,Files[fnum].name,
1000            Connections[cnum].num_files_open));
1001 }
1002
1003 enum {AFAIL,AREAD,AWRITE,AALL};
1004
1005 /*******************************************************************
1006 reproduce the share mode access table
1007 ********************************************************************/
1008 static int access_table(int new_deny,int old_deny,int old_mode,
1009                         int share_pid,char *fname)
1010 {
1011   if (new_deny == DENY_ALL || old_deny == DENY_ALL) return(AFAIL);
1012
1013   if (new_deny == DENY_DOS || old_deny == DENY_DOS) {
1014     if (old_deny == new_deny && share_pid == getpid()) 
1015         return(AALL);    
1016
1017     if (old_mode == 0) return(AREAD);
1018
1019     /* the new smbpub.zip spec says that if the file extension is
1020        .com, .dll, .exe or .sym then allow the open. I will force
1021        it to read-only as this seems sensible although the spec is
1022        a little unclear on this. */
1023     if ((fname = strrchr(fname,'.'))) {
1024       if (strequal(fname,".com") ||
1025           strequal(fname,".dll") ||
1026           strequal(fname,".exe") ||
1027           strequal(fname,".sym"))
1028         return(AREAD);
1029     }
1030
1031     return(AFAIL);
1032   }
1033
1034   switch (new_deny) 
1035     {
1036     case DENY_WRITE:
1037       if (old_deny==DENY_WRITE && old_mode==0) return(AREAD);
1038       if (old_deny==DENY_READ && old_mode==0) return(AWRITE);
1039       if (old_deny==DENY_NONE && old_mode==0) return(AALL);
1040       return(AFAIL);
1041     case DENY_READ:
1042       if (old_deny==DENY_WRITE && old_mode==1) return(AREAD);
1043       if (old_deny==DENY_READ && old_mode==1) return(AWRITE);
1044       if (old_deny==DENY_NONE && old_mode==1) return(AALL);
1045       return(AFAIL);
1046     case DENY_NONE:
1047       if (old_deny==DENY_WRITE) return(AREAD);
1048       if (old_deny==DENY_READ) return(AWRITE);
1049       if (old_deny==DENY_NONE) return(AALL);
1050       return(AFAIL);      
1051     }
1052   return(AFAIL);      
1053 }
1054
1055 /*******************************************************************
1056 check if the share mode on a file allows it to be deleted or unlinked
1057 return True if sharing doesn't prevent the operation
1058 ********************************************************************/
1059 BOOL check_file_sharing(int cnum,char *fname)
1060 {
1061   int pid=0;
1062   int share_mode = get_share_mode_byname(cnum,fname,&pid);
1063
1064   if (!pid || !share_mode) return(True);
1065  
1066   if (share_mode == DENY_DOS)
1067     return(pid == getpid());
1068
1069   /* XXXX exactly what share mode combinations should be allowed for
1070      deleting/renaming? */
1071   return(False);
1072 }
1073
1074 /****************************************************************************
1075   C. Hoch 11/22/95
1076   Helper for open_file_shared. 
1077   Truncate a file after checking locking; close file if locked.
1078   **************************************************************************/
1079 static void truncate_unless_locked(int fnum, int cnum)
1080 {
1081   if (Files[fnum].can_write){
1082     if (is_locked(fnum,cnum,0x3FFFFFFF,0)){
1083       close_file(fnum);   
1084       errno = EACCES;
1085       unix_ERR_class = ERRDOS;
1086       unix_ERR_code = ERRlock;
1087     }
1088     else
1089       ftruncate(Files[fnum].fd,0); 
1090   }
1091 }
1092
1093
1094 /****************************************************************************
1095 open a file with a share mode
1096 ****************************************************************************/
1097 void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
1098                       int mode,int *Access,int *action)
1099 {
1100   int flags=0;
1101   int flags2=0;
1102   int deny_mode = (share_mode>>4)&7;
1103   struct stat sbuf;
1104   BOOL file_existed = file_exist(fname,&sbuf);
1105   BOOL fcbopen = False;
1106   int share_pid=0;
1107
1108   Files[fnum].open = False;
1109   Files[fnum].fd = -1;
1110
1111   /* this is for OS/2 EAs - try and say we don't support them */
1112   if (strstr(fname,".+,;=[].")) {
1113     unix_ERR_class = ERRDOS;
1114     unix_ERR_code = ERROR_EAS_NOT_SUPPORTED;
1115     return;
1116   }
1117
1118   if ((ofun & 0x3) == 0 && file_existed) {
1119     errno = EEXIST;
1120     return;
1121   }
1122       
1123   if (ofun & 0x10)
1124     flags2 |= O_CREAT;
1125   if ((ofun & 0x3) == 2)
1126     flags2 |= O_TRUNC;
1127
1128   /* note that we ignore the append flag as 
1129      append does not mean the same thing under dos and unix */
1130
1131   switch (share_mode&0xF)
1132     {
1133     case 1: 
1134       flags = O_WRONLY; 
1135       break;
1136     case 0xF: 
1137       fcbopen = True;
1138       flags = O_RDWR; 
1139       break;
1140     case 2: 
1141       flags = O_RDWR; 
1142       break;
1143     default:
1144       flags = O_RDONLY;
1145       break;
1146     }
1147   
1148   if (flags != O_RDONLY && file_existed && 
1149       (!CAN_WRITE(cnum) || IS_DOS_READONLY(dos_mode(cnum,fname,&sbuf)))) {
1150     if (!fcbopen) {
1151       errno = EACCES;
1152       return;
1153     }
1154     flags = O_RDONLY;
1155   }
1156
1157   if (deny_mode > DENY_NONE && deny_mode!=DENY_FCB) {
1158     DEBUG(2,("Invalid deny mode %d on file %s\n",deny_mode,fname));
1159     errno = EINVAL;
1160     return;
1161   }
1162
1163   if (deny_mode == DENY_FCB) deny_mode = DENY_DOS;
1164
1165   if (lp_share_modes(SNUM(cnum))) {
1166     int old_share=0;
1167
1168     if (file_existed)
1169       old_share = get_share_mode(cnum,&sbuf,&share_pid);
1170
1171     if (share_pid) {
1172       /* someone else has a share lock on it, check to see 
1173          if we can too */
1174       int old_open_mode = old_share&0xF;
1175       int old_deny_mode = (old_share>>4)&7;
1176
1177       if (deny_mode > 4 || old_deny_mode > 4 || old_open_mode > 2) {
1178         DEBUG(2,("Invalid share mode (%d,%d,%d) on file %s\n",
1179                  deny_mode,old_deny_mode,old_open_mode,fname));
1180         errno = EACCES;
1181         unix_ERR_class = ERRDOS;
1182         unix_ERR_code = ERRbadshare;
1183         return;
1184       }
1185
1186       {
1187         int access_allowed = access_table(deny_mode,old_deny_mode,old_open_mode,
1188                                           share_pid,fname);
1189
1190         if ((access_allowed == AFAIL) ||
1191             (access_allowed == AREAD && flags == O_WRONLY) ||
1192             (access_allowed == AWRITE && flags == O_RDONLY)) {
1193           DEBUG(2,("Share violation on file (%d,%d,%d,%d,%s) = %d\n",
1194                    deny_mode,old_deny_mode,old_open_mode,
1195                    share_pid,fname,
1196                    access_allowed));
1197           errno = EACCES;
1198           unix_ERR_class = ERRDOS;
1199           unix_ERR_code = ERRbadshare;
1200           return;
1201         }
1202         
1203         if (access_allowed == AREAD)
1204           flags = O_RDONLY;
1205         
1206         if (access_allowed == AWRITE)
1207           flags = O_WRONLY;
1208       }
1209     }
1210   }
1211
1212   DEBUG(4,("calling open_file with flags=0x%X flags2=0x%X mode=0%o\n",
1213            flags,flags2,mode));
1214
1215   open_file(fnum,cnum,fname,flags|(flags2&~(O_TRUNC)),mode);
1216   if (!Files[fnum].open && flags==O_RDWR && errno!=ENOENT && fcbopen) {
1217     flags = O_RDONLY;
1218     open_file(fnum,cnum,fname,flags,mode);
1219   }
1220
1221   if (Files[fnum].open) {
1222     int open_mode=0;
1223     switch (flags) {
1224     case O_RDONLY:
1225       open_mode = 0;
1226       break;
1227     case O_RDWR:
1228       open_mode = 2;
1229       break;
1230     case O_WRONLY:
1231       open_mode = 1;
1232       break;
1233     }
1234
1235     Files[fnum].share_mode = (deny_mode<<4) | open_mode;
1236     Files[fnum].share_pending = True;
1237
1238     if (Access) {
1239       (*Access) = open_mode;
1240     }
1241     
1242     if (action) {
1243       if (file_existed && !(flags2 & O_TRUNC)) *action = 1;
1244       if (!file_existed) *action = 2;
1245       if (file_existed && (flags2 & O_TRUNC)) *action = 3;
1246     }
1247
1248     if (!share_pid)
1249       share_mode_pending = True;
1250
1251     if ((flags2&O_TRUNC) && file_existed)
1252       truncate_unless_locked(fnum,cnum);
1253   }
1254 }
1255
1256
1257
1258 /*******************************************************************
1259 check for files that we should now set our share modes on
1260 ********************************************************************/
1261 static void check_share_modes(void)
1262 {
1263   int i;
1264   for (i=0;i<MAX_OPEN_FILES;i++)
1265     if(Files[i].open && Files[i].share_pending) {
1266       if (lp_share_modes(SNUM(Files[i].cnum))) {
1267         int pid=0;
1268         get_share_mode_by_fnum(Files[i].cnum,i,&pid);
1269         if (!pid) {
1270           set_share_mode(i,Files[i].share_mode);
1271           Files[i].share_pending = False;
1272         }
1273       } else {
1274         Files[i].share_pending = False; 
1275       }
1276     }
1277 }
1278
1279
1280 /****************************************************************************
1281 seek a file. Try to avoid the seek if possible
1282 ****************************************************************************/
1283 int seek_file(int fnum,int pos)
1284 {
1285   int offset = 0;
1286   if (Files[fnum].print_file && POSTSCRIPT(Files[fnum].cnum))
1287     offset = 3;
1288
1289   Files[fnum].pos = lseek(Files[fnum].fd,pos+offset,SEEK_SET) - offset;
1290   return(Files[fnum].pos);
1291 }
1292
1293 /****************************************************************************
1294 read from a file
1295 ****************************************************************************/
1296 int read_file(int fnum,char *data,int pos,int mincnt,int maxcnt,int timeout,BOOL exact)
1297 {
1298   int ret=0;
1299
1300   if (!Files[fnum].can_write)
1301     {
1302       ret = read_predict(Files[fnum].fd,
1303                          pos,
1304                          data,
1305                          NULL,
1306                          maxcnt);
1307
1308       data += ret;
1309       maxcnt -= ret;
1310       mincnt = MAX(mincnt-ret,0);
1311       pos += ret;
1312     }
1313
1314 #if USE_MMAP
1315   if (Files[fnum].mmap_ptr)
1316     {
1317       int num = MIN(maxcnt,Files[fnum].mmap_size-pos);
1318       if (num > 0)
1319         {
1320           memcpy(data,Files[fnum].mmap_ptr+pos,num);
1321           data += num;
1322           pos += num;
1323           maxcnt -= num;
1324           mincnt = MAX(mincnt-num,0);
1325           ret += num;
1326         }
1327     }
1328 #endif
1329
1330   if (maxcnt <= 0)
1331     return(ret);
1332
1333   if (seek_file(fnum,pos) != pos)
1334     {
1335       DEBUG(3,("Failed to seek to %d\n",pos));
1336       return(ret);
1337     }
1338   
1339   if (maxcnt > 0)
1340     ret += read_with_timeout(Files[fnum].fd,
1341                              data,
1342                              mincnt,
1343                              maxcnt,
1344                              timeout,
1345                              exact);
1346
1347   return(ret);
1348 }
1349
1350
1351 /****************************************************************************
1352 write to a file
1353 ****************************************************************************/
1354 int write_file(int fnum,char *data,int n)
1355 {
1356   if (!Files[fnum].can_write) {
1357     errno = EPERM;
1358     return(0);
1359   }
1360
1361   if (!Files[fnum].modified) {
1362     struct stat st;
1363     Files[fnum].modified = True;
1364     if (fstat(Files[fnum].fd,&st) == 0) {
1365       int dosmode = dos_mode(Files[fnum].cnum,Files[fnum].name,&st);
1366       if (MAP_ARCHIVE(Files[fnum].cnum) && !IS_DOS_ARCHIVE(dosmode)) {  
1367         dos_chmod(Files[fnum].cnum,Files[fnum].name,dosmode | aARCH,&st);
1368       }
1369     }  
1370   }
1371
1372   return(write_data(Files[fnum].fd,data,n));
1373 }
1374
1375
1376 static int old_umask = 022;
1377
1378 /****************************************************************************
1379 load parameters specific to a connection/service
1380 ****************************************************************************/
1381 BOOL become_service(int cnum,BOOL do_chdir)
1382 {
1383   extern char magic_char;
1384   static int last_cnum = -1;
1385   int snum;
1386
1387   if (!OPEN_CNUM(cnum))
1388     {
1389       last_cnum = -1;
1390       return(False);
1391     }
1392
1393   Connections[cnum].lastused = smb_last_time;
1394
1395   snum = SNUM(cnum);
1396   
1397   if (do_chdir &&
1398       ChDir(Connections[cnum].connectpath) != 0 &&
1399       ChDir(Connections[cnum].origpath) != 0)
1400     {
1401       DEBUG(0,("%s chdir (%s) failed cnum=%d\n",timestring(),
1402             Connections[cnum].connectpath,cnum));     
1403       return(False);
1404     }
1405
1406   if (cnum == last_cnum)
1407     return(True);
1408
1409   last_cnum = cnum;
1410
1411   case_default = lp_defaultcase(snum);
1412   case_preserve = lp_preservecase(snum);
1413   short_case_preserve = lp_shortpreservecase(snum);
1414   case_mangle = lp_casemangle(snum);
1415   case_sensitive = lp_casesensitive(snum);
1416   magic_char = lp_magicchar(snum);
1417   use_mangled_map = (*lp_mangled_map(snum) ? True:False);
1418   return(True);
1419 }
1420
1421
1422 /****************************************************************************
1423   become the specified uid 
1424 ****************************************************************************/
1425 static BOOL become_uid(int uid)
1426 {
1427   if (initial_uid != 0)
1428     return(True);
1429
1430 #ifdef AIX
1431   {
1432     /* AIX 3 stuff - inspired by a code fragment in wu-ftpd */
1433     priv_t priv;
1434
1435     priv.pv_priv[0] = 0;
1436     priv.pv_priv[1] = 0;
1437     if (setpriv(PRIV_SET|PRIV_INHERITED|PRIV_EFFECTIVE|PRIV_BEQUEATH,
1438                 &priv, sizeof(priv_t)) < 0 ||
1439         setuidx(ID_REAL|ID_EFFECTIVE, (uid_t)uid) < 0 ||
1440         seteuid((uid_t)uid) < 0) 
1441       DEBUG(1,("Can't set uid (AIX3)"));
1442   }
1443 #endif
1444
1445 #ifdef USE_SETRES
1446   if (setresuid(-1,uid,-1) != 0)
1447 #else
1448     if ((seteuid(uid) != 0) && 
1449         (setuid(uid) != 0))
1450 #endif
1451       {
1452         DEBUG(0,("Couldn't set uid %d currently set to (%d,%d)\n",
1453                  uid,getuid(), geteuid()));
1454         if (uid > 32000)
1455           DEBUG(0,("Looks like your OS doesn't like high uid values - try using a different account\n"));
1456         return(False);
1457       }
1458
1459   if (((uid == -1) || (uid == 65535)) && geteuid() != uid)
1460     {
1461       DEBUG(0,("Invalid uid -1. perhaps you have a account with uid 65535?\n"));
1462       return(False);
1463     }
1464
1465   return(True);
1466 }
1467
1468
1469 /****************************************************************************
1470   become the specified gid
1471 ****************************************************************************/
1472 static BOOL become_gid(int gid)
1473 {
1474   if (initial_uid != 0)
1475     return(True);
1476   
1477 #ifdef USE_SETRES 
1478   if (setresgid(-1,gid,-1) != 0)
1479 #else
1480     if (setgid(gid) != 0)
1481 #endif
1482       {
1483         DEBUG(0,("Couldn't set gid %d currently set to (%d,%d)\n",
1484                  gid,getgid(),getegid()));
1485         if (gid > 32000)
1486           DEBUG(0,("Looks like your OS doesn't like high gid values - try using a different account\n"));
1487         return(False);
1488       }
1489
1490   return(True);
1491 }
1492
1493
1494 /****************************************************************************
1495   become the specified uid and gid
1496 ****************************************************************************/
1497 static BOOL become_id(int uid,int gid)
1498 {
1499   return(become_gid(gid) && become_uid(uid));
1500 }
1501
1502 /****************************************************************************
1503 become the guest user
1504 ****************************************************************************/
1505 static BOOL become_guest(void)
1506 {
1507   BOOL ret;
1508   static struct passwd *pass=NULL;
1509
1510   if (initial_uid != 0) 
1511     return(True);
1512
1513   if (!pass)
1514     pass = Get_Pwnam(lp_guestaccount(-1),True);
1515   if (!pass) return(False);
1516
1517   ret = become_id(pass->pw_uid,pass->pw_gid);
1518
1519   if (!ret)
1520     DEBUG(1,("Failed to become guest. Invalid guest account?\n"));
1521
1522   last_user.cnum = -2;
1523
1524   return(ret);
1525 }
1526
1527 /*******************************************************************
1528 check if a username is OK
1529 ********************************************************************/
1530 static BOOL check_user_ok(int cnum,user_struct *vuser,int snum)
1531 {
1532   int i;
1533   for (i=0;i<Connections[cnum].uid_cache.entries;i++)
1534     if (Connections[cnum].uid_cache.list[i] == vuser->uid) return(True);
1535
1536   if (!user_ok(vuser->name,snum)) return(False);
1537
1538   i = Connections[cnum].uid_cache.entries % UID_CACHE_SIZE;
1539   Connections[cnum].uid_cache.list[i] = vuser->uid;
1540
1541   if (Connections[cnum].uid_cache.entries < UID_CACHE_SIZE)
1542     Connections[cnum].uid_cache.entries++;
1543
1544   return(True);
1545 }
1546
1547
1548 /****************************************************************************
1549   become the user of a connection number
1550 ****************************************************************************/
1551 BOOL become_user(int cnum, int uid)
1552 {
1553   int new_umask;
1554   user_struct *vuser;
1555   int snum,gid;
1556   int ngroups;
1557   gid_t *groups;
1558
1559   if (last_user.cnum == cnum && last_user.uid == uid) {
1560     DEBUG(4,("Skipping become_user - already user\n"));
1561     return(True);
1562   }
1563
1564   unbecome_user();
1565
1566   if (!OPEN_CNUM(cnum)) {
1567     DEBUG(2,("Connection %d not open\n",cnum));
1568     return(False);
1569   }
1570
1571   snum = Connections[cnum].service;
1572
1573   if (Connections[cnum].force_user || 
1574       lp_security() == SEC_SHARE ||
1575       !(vuser = get_valid_user_struct(uid)) ||
1576       !check_user_ok(cnum,vuser,snum)) {
1577     uid = Connections[cnum].uid;
1578     gid = Connections[cnum].gid;
1579     groups = Connections[cnum].groups;
1580     ngroups = Connections[cnum].ngroups;
1581   } else {
1582     if (!vuser) {
1583       DEBUG(2,("Invalid vuid used %d\n",uid));
1584       return(False);
1585     }
1586     uid = vuser->uid;
1587     if(!*lp_force_group(snum))
1588       gid = vuser->gid;
1589     else
1590       gid = Connections[cnum].gid;
1591     groups = vuser->user_groups;
1592     ngroups = vuser->user_ngroups;
1593   }
1594
1595   if (initial_uid == 0)
1596     {
1597       if (!become_gid(gid)) return(False);
1598
1599 #ifndef NO_SETGROUPS      
1600       if (!IS_IPC(cnum)) {
1601         /* groups stuff added by ih/wreu */
1602         if (ngroups > 0)
1603           if (setgroups(ngroups,groups)<0)
1604             DEBUG(0,("setgroups call failed!\n"));
1605       }
1606 #endif
1607
1608       if (!Connections[cnum].admin_user && !become_uid(uid))
1609         return(False);
1610     }
1611
1612   new_umask = 0777 & ~CREATE_MODE(cnum);
1613   old_umask = umask(new_umask);
1614
1615   last_user.cnum = cnum;
1616   last_user.uid = uid;
1617   
1618   DEBUG(5,("become_user uid=(%d,%d) gid=(%d,%d) new_umask=0%o\n",
1619            getuid(),geteuid(),getgid(),getegid(),new_umask));
1620   
1621   return(True);
1622 }
1623
1624 /****************************************************************************
1625   unbecome the user of a connection number
1626 ****************************************************************************/
1627 BOOL unbecome_user(void )
1628 {
1629   if (last_user.cnum == -1)
1630     return(False);
1631
1632   ChDir(OriginalDir);
1633
1634   umask(old_umask);
1635
1636   if (initial_uid == 0)
1637     {
1638 #ifdef USE_SETRES
1639       setresuid(-1,getuid(),-1);
1640       setresgid(-1,getgid(),-1);
1641 #else
1642       if (seteuid(initial_uid) != 0) 
1643         setuid(initial_uid);
1644       setgid(initial_gid);
1645 #endif
1646     }
1647 #ifdef NO_EID
1648   if (initial_uid == 0)
1649     DEBUG(2,("Running with no EID\n"));
1650   initial_uid = getuid();
1651   initial_gid = getgid();
1652 #else
1653   if (geteuid() != initial_uid)
1654     {
1655       DEBUG(0,("Warning: You appear to have a trapdoor uid system\n"));
1656       initial_uid = geteuid();
1657     }
1658   if (getegid() != initial_gid)
1659     {
1660       DEBUG(0,("Warning: You appear to have a trapdoor gid system\n"));
1661       initial_gid = getegid();
1662     }
1663 #endif
1664   
1665   if (ChDir(OriginalDir) != 0)
1666     DEBUG(0,("%s chdir(%s) failed in unbecome_user\n",
1667              timestring(),OriginalDir));  
1668
1669   DEBUG(5,("unbecome_user now uid=(%d,%d) gid=(%d,%d)\n",
1670         getuid(),geteuid(),getgid(),getegid()));
1671
1672   last_user.cnum = -1;
1673
1674   return(True);
1675 }
1676
1677 /****************************************************************************
1678   find a service entry
1679 ****************************************************************************/
1680 int find_service(char *service)
1681 {
1682    int iService;
1683
1684    string_sub(service,"\\","/");
1685
1686    iService = lp_servicenumber(service);
1687
1688    /* now handle the special case of a home directory */
1689    if (iService < 0)
1690    {
1691       char *phome_dir = get_home_dir(service);
1692       DEBUG(3,("checking for home directory %s gave %s\n",service,
1693             phome_dir?phome_dir:"(NULL)"));
1694       if (phome_dir)
1695       {   
1696          int iHomeService;
1697          if ((iHomeService = lp_servicenumber(HOMES_NAME)) >= 0)
1698          {
1699             lp_add_home(service,iHomeService,phome_dir);
1700             iService = lp_servicenumber(service);
1701          }
1702       }
1703    }
1704
1705    /* If we still don't have a service, attempt to add it as a printer. */
1706    if (iService < 0)
1707    {
1708       int iPrinterService;
1709
1710       if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) >= 0)
1711       {
1712          char *pszTemp;
1713
1714          DEBUG(3,("checking whether %s is a valid printer name...\n", service));
1715          pszTemp = PRINTCAP;
1716          if ((pszTemp != NULL) && pcap_printername_ok(service, pszTemp))
1717          {
1718             DEBUG(3,("%s is a valid printer name\n", service));
1719             DEBUG(3,("adding %s as a printer service\n", service));
1720             lp_add_printer(service,iPrinterService);
1721             iService = lp_servicenumber(service);
1722             if (iService < 0)
1723                DEBUG(0,("failed to add %s as a printer service!\n", service));
1724          }
1725          else
1726             DEBUG(3,("%s is not a valid printer name\n", service));
1727       }
1728    }
1729
1730    /* just possibly it's a default service? */
1731    if (iService < 0) 
1732      {
1733        char *defservice = lp_defaultservice();
1734        if (defservice && *defservice && !strequal(defservice,service)) {
1735          iService = find_service(defservice);
1736          if (iService >= 0) {
1737            string_sub(service,"_","/");
1738            iService = lp_add_service(service,iService);
1739          }
1740        }
1741      }
1742
1743    if (iService >= 0)
1744       if (!VALID_SNUM(iService))
1745       {
1746          DEBUG(0,("Invalid snum %d for %s\n",iService,service));
1747          iService = -1;
1748       }
1749
1750    if (iService < 0)
1751       DEBUG(3,("find_service() failed to find service %s\n", service));
1752
1753    return (iService);
1754 }
1755
1756
1757 /****************************************************************************
1758   create an error packet from a cached error.
1759 ****************************************************************************/
1760 int cached_error_packet(char *inbuf,char *outbuf,int fnum,int line)
1761 {
1762   write_bmpx_struct *wbmpx = Files[fnum].wbmpx_ptr;
1763
1764   int32 eclass = wbmpx->wr_errclass;
1765   int32 err = wbmpx->wr_error;
1766
1767   /* We can now delete the auxiliary struct */
1768   free((char *)wbmpx);
1769   Files[fnum].wbmpx_ptr = NULL;
1770   return error_packet(inbuf,outbuf,eclass,err,line);
1771 }
1772
1773
1774 struct
1775 {
1776   int unixerror;
1777   int smbclass;
1778   int smbcode;
1779 } unix_smb_errmap[] =
1780 {
1781   {EPERM,ERRDOS,ERRnoaccess},
1782   {EACCES,ERRDOS,ERRnoaccess},
1783   {ENOENT,ERRDOS,ERRbadfile},
1784   {EIO,ERRHRD,ERRgeneral},
1785   {EBADF,ERRSRV,ERRsrverror},
1786   {EINVAL,ERRSRV,ERRsrverror},
1787   {EEXIST,ERRDOS,ERRfilexists},
1788   {ENFILE,ERRDOS,ERRnofids},
1789   {EMFILE,ERRDOS,ERRnofids},
1790   {ENOSPC,ERRHRD,ERRdiskfull},
1791 #ifdef EDQUOT
1792   {EDQUOT,ERRHRD,ERRdiskfull},
1793 #endif
1794 #ifdef ENOTEMPTY
1795   {ENOTEMPTY,ERRDOS,ERRnoaccess},
1796 #endif
1797 #ifdef EXDEV
1798   {EXDEV,ERRDOS,ERRdiffdevice},
1799 #endif
1800   {EROFS,ERRHRD,ERRnowrite},
1801   {0,0,0}
1802 };
1803
1804
1805 /****************************************************************************
1806   create an error packet from errno
1807 ****************************************************************************/
1808 int unix_error_packet(char *inbuf,char *outbuf,int def_class,uint32 def_code,int line)
1809 {
1810   int eclass=def_class;
1811   int ecode=def_code;
1812   int i=0;
1813
1814   if (unix_ERR_class != SUCCESS)
1815     {
1816       eclass = unix_ERR_class;
1817       ecode = unix_ERR_code;
1818       unix_ERR_class = SUCCESS;
1819       unix_ERR_code = 0;
1820     }
1821   else
1822     {
1823       while (unix_smb_errmap[i].smbclass != 0)
1824         {
1825           if (unix_smb_errmap[i].unixerror == errno)
1826             {
1827               eclass = unix_smb_errmap[i].smbclass;
1828               ecode = unix_smb_errmap[i].smbcode;
1829               break;
1830             }
1831           i++;
1832         }
1833     }
1834
1835   return(error_packet(inbuf,outbuf,eclass,ecode,line));
1836 }
1837
1838
1839 /****************************************************************************
1840   create an error packet. Normally called using the ERROR() macro
1841 ****************************************************************************/
1842 int error_packet(char *inbuf,char *outbuf,int error_class,uint32 error_code,int line)
1843 {
1844   int outsize = set_message(outbuf,0,0,True);
1845   int cmd;
1846   cmd = CVAL(inbuf,smb_com);
1847   
1848   CVAL(outbuf,smb_rcls) = error_class;
1849   SSVAL(outbuf,smb_err,error_code);  
1850   
1851   DEBUG(3,("%s error packet at line %d cmd=%d (%s) eclass=%d ecode=%d\n",
1852            timestring(),
1853            line,
1854            (int)CVAL(inbuf,smb_com),
1855            smb_fn_name(CVAL(inbuf,smb_com)),
1856            error_class,
1857            error_code));
1858
1859   if (errno != 0)
1860     DEBUG(3,("error string = %s\n",strerror(errno)));
1861   
1862   return(outsize);
1863 }
1864
1865
1866 #ifndef SIGCLD_IGNORE
1867 /****************************************************************************
1868 this prevents zombie child processes
1869 ****************************************************************************/
1870 static int sig_cld()
1871 {
1872   static int depth = 0;
1873   if (depth != 0)
1874     {
1875       DEBUG(0,("ERROR: Recursion in sig_cld? Perhaps you need `#define USE_WAITPID'?\n"));
1876       depth=0;
1877       return(0);
1878     }
1879   depth++;
1880
1881   BlockSignals(True);
1882   DEBUG(5,("got SIGCLD\n"));
1883
1884 #ifdef USE_WAITPID
1885   while (waitpid((pid_t)-1,(int *)NULL, WNOHANG) > 0);
1886 #endif
1887
1888   /* Stop zombies */
1889   /* Stevens, Adv. Unix Prog. says that on system V you must call
1890      wait before reinstalling the signal handler, because the kernel
1891      calls the handler from within the signal-call when there is a
1892      child that has exited. This would lead to an infinite recursion
1893      if done vice versa. */
1894         
1895 #ifndef DONT_REINSTALL_SIG
1896 #ifdef SIGCLD_IGNORE
1897   signal(SIGCLD, SIG_IGN);  
1898 #else
1899   signal(SIGCLD, SIGNAL_CAST sig_cld);
1900 #endif
1901 #endif
1902
1903 #ifndef USE_WAITPID
1904   while (wait3(WAIT3_CAST1 NULL, WNOHANG, WAIT3_CAST2 NULL) > 0);
1905 #endif
1906   depth--;
1907   BlockSignals(False);
1908   return 0;
1909 }
1910 #endif
1911
1912 /****************************************************************************
1913   this is called when the client exits abruptly
1914   **************************************************************************/
1915 static int sig_pipe()
1916 {
1917   exit_server("Got sigpipe\n");
1918   return(0);
1919 }
1920
1921 /****************************************************************************
1922   open the socket communication
1923 ****************************************************************************/
1924 static BOOL open_sockets(BOOL is_daemon,int port)
1925 {
1926   extern int Client;
1927
1928   if (is_daemon)
1929     {
1930       int s;
1931       struct sockaddr addr;
1932       int in_addrlen = sizeof(addr);
1933        
1934       /* Stop zombies */
1935 #ifdef SIGCLD_IGNORE
1936       signal(SIGCLD, SIG_IGN);
1937 #else
1938       signal(SIGCLD, SIGNAL_CAST sig_cld);
1939 #endif
1940
1941       /* open an incoming socket */
1942       s = open_socket_in(SOCK_STREAM, port, 0);
1943       if (s == -1)
1944         return(False);
1945
1946       /* ready to listen */
1947       if (listen(s, 5) == -1) 
1948         {
1949           DEBUG(0,("listen: %s",strerror(errno)));
1950           close(s);
1951           return False;
1952         }
1953       
1954       /* now accept incoming connections - forking a new process
1955          for each incoming connection */
1956       DEBUG(2,("waiting for a connection\n"));
1957       while (1)
1958         {
1959           Client = accept(s,&addr,&in_addrlen);
1960
1961           if (Client == -1 && errno == EINTR)
1962             continue;
1963
1964           if (Client == -1)
1965             {
1966               DEBUG(0,("accept: %s",strerror(errno)));
1967               return False;
1968             }
1969
1970 #ifdef NO_FORK_DEBUG
1971 #ifndef NO_SIGNAL_TEST
1972           signal(SIGPIPE, SIGNAL_CAST sig_pipe);
1973           signal(SIGCLD, SIGNAL_CAST SIG_DFL);
1974 #endif
1975           return True;
1976 #else
1977           if (Client != -1 && fork()==0)
1978             {
1979 #ifndef NO_SIGNAL_TEST
1980               signal(SIGPIPE, SIGNAL_CAST sig_pipe);
1981               signal(SIGCLD, SIGNAL_CAST SIG_DFL);
1982 #endif
1983               /* close the listening socket */
1984               close(s);
1985
1986               /* close our standard file descriptors */
1987               close_low_fds();
1988   
1989               set_socket_options(Client,"SO_KEEPALIVE");
1990               set_socket_options(Client,user_socket_options);
1991
1992               return True; 
1993             }
1994           close(Client); /* The parent doesn't need this socket */
1995 #endif
1996         }
1997     }
1998   else
1999     {
2000       /* We will abort gracefully when the client or remote system 
2001          goes away */
2002 #ifndef NO_SIGNAL_TEST
2003       signal(SIGPIPE, SIGNAL_CAST sig_pipe);
2004 #endif
2005       Client = dup(0);
2006
2007       /* close our standard file descriptors */
2008       close_low_fds();
2009
2010       set_socket_options(Client,"SO_KEEPALIVE");
2011       set_socket_options(Client,user_socket_options);
2012     }
2013
2014   return True;
2015 }
2016
2017
2018 /****************************************************************************
2019 check if a snum is in use
2020 ****************************************************************************/
2021 BOOL snum_used(int snum)
2022 {
2023   int i;
2024   for (i=0;i<MAX_CONNECTIONS;i++)
2025     if (OPEN_CNUM(i) && (SNUM(i) == snum))
2026       return(True);
2027   return(False);
2028 }
2029
2030 /****************************************************************************
2031   reload the services file
2032   **************************************************************************/
2033 BOOL reload_services(BOOL test)
2034 {
2035   BOOL ret;
2036
2037   if (lp_loaded())
2038     {
2039       pstring fname;
2040       strcpy(fname,lp_configfile());
2041       if (file_exist(fname,NULL) && !strcsequal(fname,servicesf))
2042         {
2043           strcpy(servicesf,fname);
2044           test = False;
2045         }
2046     }
2047
2048   reopen_logs();
2049
2050   if (test && !lp_file_list_changed())
2051     return(True);
2052
2053   lp_killunused(snum_used);
2054
2055   ret = lp_load(servicesf,False);
2056
2057   /* perhaps the config filename is now set */
2058   if (!test)
2059     reload_services(True);
2060
2061   reopen_logs();
2062
2063   {
2064     extern int Client;
2065     if (Client != -1) {      
2066       set_socket_options(Client,"SO_KEEPALIVE");
2067       set_socket_options(Client,user_socket_options);
2068     }
2069   }
2070
2071   create_mangled_stack(lp_mangledstack());
2072
2073   /* this forces service parameters to be flushed */
2074   become_service(-1,True);
2075
2076   return(ret);
2077 }
2078
2079
2080
2081 /****************************************************************************
2082 this prevents zombie child processes
2083 ****************************************************************************/
2084 static int sig_hup()
2085 {
2086   BlockSignals(True);
2087   DEBUG(0,("Got SIGHUP\n"));
2088   reload_services(False);
2089 #ifndef DONT_REINSTALL_SIG
2090   signal(SIGHUP,SIGNAL_CAST sig_hup);
2091 #endif
2092   BlockSignals(False);
2093   return(0);
2094 }
2095
2096 /****************************************************************************
2097 Setup the groups a user belongs to.
2098 ****************************************************************************/
2099 int setup_groups(char *user, int uid, int gid, int *p_ngroups, 
2100                  int **p_igroups, gid_t **p_groups)
2101 {
2102   if (-1 == initgroups(user,gid))
2103     {
2104       if (getuid() == 0)
2105         {
2106           DEBUG(0,("Unable to initgroups!\n"));
2107           if (gid < 0 || gid > 16000 || uid < 0 || uid > 16000)
2108             DEBUG(0,("This is probably a problem with the account %s\n",user));
2109         }
2110     }
2111   else
2112     {
2113       int i,ngroups;
2114       int *igroups;
2115       gid_t grp = 0;
2116       ngroups = getgroups(0,&grp);
2117       if (ngroups <= 0)
2118         ngroups = 32;
2119       igroups = (int *)malloc(sizeof(int)*ngroups);
2120       for (i=0;i<ngroups;i++)
2121         igroups[i] = 0x42424242;
2122       ngroups = getgroups(ngroups,(gid_t *)igroups);
2123
2124       if (igroups[0] == 0x42424242)
2125         ngroups = 0;
2126
2127       *p_ngroups = ngroups;
2128
2129       /* The following bit of code is very strange. It is due to the
2130          fact that some OSes use int* and some use gid_t* for
2131          getgroups, and some (like SunOS) use both, one in prototypes,
2132          and one in man pages and the actual code. Thus we detect it
2133          dynamically using some very ugly code */
2134       if (ngroups > 0)
2135         {
2136           /* does getgroups return ints or gid_t ?? */
2137           static BOOL groups_use_ints = True;
2138
2139           if (groups_use_ints && 
2140               ngroups == 1 && 
2141               SVAL(igroups,2) == 0x4242)
2142             groups_use_ints = False;
2143           
2144           for (i=0;groups_use_ints && i<ngroups;i++)
2145             if (igroups[i] == 0x42424242)
2146               groups_use_ints = False;
2147               
2148           if (groups_use_ints)
2149             {
2150               *p_igroups = igroups;
2151               *p_groups = (gid_t *)igroups;       
2152             }
2153           else
2154             {
2155               gid_t *groups = (gid_t *)igroups;
2156               igroups = (int *)malloc(sizeof(int)*ngroups);
2157               for (i=0;i<ngroups;i++)
2158                 igroups[i] = groups[i];
2159               *p_igroups = igroups;
2160               *p_groups = (gid_t *)groups;
2161             }
2162         }
2163       DEBUG(3,("%s is in %d groups\n",user,ngroups));
2164       for (i=0;i<ngroups;i++)
2165         DEBUG(3,("%d ",igroups[i]));
2166       DEBUG(3,("\n"));
2167     }
2168   return 0;
2169 }
2170
2171 /****************************************************************************
2172   make a connection to a service
2173 ****************************************************************************/
2174 int make_connection(char *service,char *user,char *password, int pwlen, char *dev,int vuid)
2175 {
2176   int cnum;
2177   int snum;
2178   struct passwd *pass = NULL;
2179   connection_struct *pcon;
2180   BOOL guest = False;
2181   BOOL force = False;
2182   static BOOL first_connection = True;
2183
2184   strlower(service);
2185
2186   snum = find_service(service);
2187   if (snum < 0)
2188     {
2189       if (strequal(service,"IPC$"))
2190         {         
2191           DEBUG(3,("%s refusing IPC connection\n",timestring()));
2192           return(-3);
2193         }
2194
2195       DEBUG(0,("%s couldn't find service %s\n",timestring(),service));      
2196       return(-2);
2197     }
2198
2199   if (strequal(service,HOMES_NAME))
2200     {
2201       if (*user && Get_Pwnam(user,True))
2202         return(make_connection(user,user,password,pwlen,dev,vuid));
2203
2204       if (validated_username(vuid))
2205         {
2206           strcpy(user,validated_username(vuid));
2207           return(make_connection(user,user,password,pwlen,dev,vuid));
2208         }
2209     }
2210
2211   if (!lp_snum_ok(snum) || !check_access(snum)) {    
2212     return(-4);
2213   }
2214
2215   /* you can only connect to the IPC$ service as an ipc device */
2216   if (strequal(service,"IPC$"))
2217     strcpy(dev,"IPC");
2218
2219   if (*dev == '?' || !*dev)
2220     {
2221       if (lp_print_ok(snum))
2222         strcpy(dev,"LPT1:");
2223       else
2224         strcpy(dev,"A:");
2225     }
2226
2227   /* if the request is as a printer and you can't print then refuse */
2228   strupper(dev);
2229   if (!lp_print_ok(snum) && (strncmp(dev,"LPT",3) == 0)) {
2230     DEBUG(1,("Attempt to connect to non-printer as a printer\n"));
2231     return(-6);
2232   }
2233
2234   /* lowercase the user name */
2235   strlower(user);
2236
2237   /* add it as a possible user name */
2238   add_session_user(service);
2239
2240   /* shall we let them in? */
2241   if (!authorise_login(snum,user,password,pwlen,&guest,&force,vuid))
2242     {
2243       DEBUG(2,("%s invalid username/password for %s\n",timestring(),service));
2244       return(-1);
2245     }
2246   
2247   cnum = find_free_connection(str_checksum(service) + str_checksum(user));
2248   if (cnum < 0)
2249     {
2250       DEBUG(0,("%s couldn't find free connection\n",timestring()));      
2251       return(-1);
2252     }
2253
2254   pcon = &Connections[cnum];
2255   bzero((char *)pcon,sizeof(*pcon));
2256
2257   /* find out some info about the user */
2258   pass = Get_Pwnam(user,True);
2259
2260   if (pass == NULL)
2261     {
2262       DEBUG(0,("%s couldn't find account %s\n",timestring(),user)); 
2263       return(-7);
2264     }
2265
2266   pcon->read_only = lp_readonly(snum);
2267
2268   {
2269     pstring list;
2270     StrnCpy(list,lp_readlist(snum),sizeof(pstring)-1);
2271     string_sub(list,"%S",service);
2272
2273     if (user_in_list(user,list))
2274       pcon->read_only = True;
2275
2276     StrnCpy(list,lp_writelist(snum),sizeof(pstring)-1);
2277     string_sub(list,"%S",service);
2278
2279     if (user_in_list(user,list))
2280       pcon->read_only = False;    
2281   }
2282
2283   /* admin user check */
2284   if (user_in_list(user,lp_admin_users(snum)) &&
2285       !pcon->read_only)
2286     {
2287       pcon->admin_user = True;
2288       DEBUG(0,("%s logged in as admin user (root privileges)\n",user));
2289     }
2290   else
2291     pcon->admin_user = False;
2292     
2293   pcon->force_user = force;
2294   pcon->uid = pass->pw_uid;
2295   pcon->gid = pass->pw_gid;
2296   pcon->num_files_open = 0;
2297   pcon->lastused = time(NULL);
2298   pcon->service = snum;
2299   pcon->used = True;
2300   pcon->printer = (strncmp(dev,"LPT",3) == 0);
2301   pcon->ipc = (strncmp(dev,"IPC",3) == 0);
2302   pcon->dirptr = NULL;
2303   string_set(&pcon->dirpath,"");
2304   string_set(&pcon->user,user);
2305
2306 #if HAVE_GETGRNAM 
2307   if (*lp_force_group(snum))
2308     {
2309       struct group *gptr = (struct group *)getgrnam(lp_force_group(snum));
2310       if (gptr)
2311         {
2312           pcon->gid = gptr->gr_gid;
2313           DEBUG(3,("Forced group %s\n",lp_force_group(snum)));
2314         }
2315       else
2316         DEBUG(1,("Couldn't find group %s\n",lp_force_group(snum)));
2317     }
2318 #endif
2319
2320   if (*lp_force_user(snum))
2321     {
2322       struct passwd *pass2;
2323       fstring fuser;
2324       strcpy(fuser,lp_force_user(snum));
2325       pass2 = (struct passwd *)Get_Pwnam(fuser,True);
2326       if (pass2)
2327         {
2328           pcon->uid = pass2->pw_uid;
2329           string_set(&pcon->user,fuser);
2330           strcpy(user,fuser);
2331           pcon->force_user = True;
2332           DEBUG(3,("Forced user %s\n",fuser));    
2333         }
2334       else
2335         DEBUG(1,("Couldn't find user %s\n",fuser));
2336     }
2337
2338   {
2339     pstring s;
2340     strcpy(s,lp_pathname(snum));
2341     standard_sub(cnum,s);
2342     string_set(&pcon->connectpath,s);
2343     DEBUG(3,("Connect path is %s\n",s));
2344   }
2345
2346   /* groups stuff added by ih */
2347   pcon->ngroups = 0;
2348   pcon->groups = NULL;
2349
2350   if (!IS_IPC(cnum))
2351     {
2352       /* Find all the groups this uid is in and store them. Used by become_user() */
2353       setup_groups(pcon->user,pcon->uid,pcon->gid,&pcon->ngroups,&pcon->igroups,&pcon->groups);
2354       
2355       /* check number of connections */
2356       if (!claim_connection(cnum,
2357                             lp_servicename(SNUM(cnum)),
2358                             lp_max_connections(SNUM(cnum)),False))
2359         {
2360           DEBUG(1,("too many connections - rejected\n"));
2361           return(-8);
2362         }  
2363
2364       if (lp_status(SNUM(cnum)))
2365         claim_connection(cnum,"STATUS.",MAXSTATUS,first_connection);
2366
2367       first_connection = False;
2368     } /* IS_IPC */
2369
2370   pcon->open = True;
2371
2372   /* execute any "root preexec = " line */
2373   if (*lp_rootpreexec(SNUM(cnum)))
2374     {
2375       pstring cmd;
2376       strcpy(cmd,lp_rootpreexec(SNUM(cnum)));
2377       standard_sub(cnum,cmd);
2378       DEBUG(5,("cmd=%s\n",cmd));
2379       smbrun(cmd,NULL);
2380     }
2381
2382   if (!become_user(cnum,pcon->uid))
2383     {
2384       DEBUG(0,("Can't become connected user!\n"));
2385       pcon->open = False;
2386       if (!IS_IPC(cnum)) {
2387         yield_connection(cnum,
2388                          lp_servicename(SNUM(cnum)),
2389                          lp_max_connections(SNUM(cnum)));
2390         if (lp_status(SNUM(cnum))) yield_connection(cnum,"STATUS.",MAXSTATUS);
2391       }
2392       return(-1);
2393     }
2394
2395   if (ChDir(pcon->connectpath) != 0)
2396     {
2397       DEBUG(0,("Can't change directory to %s\n",pcon->connectpath));
2398       pcon->open = False;
2399       unbecome_user();
2400       if (!IS_IPC(cnum)) {
2401         yield_connection(cnum,
2402                          lp_servicename(SNUM(cnum)),
2403                          lp_max_connections(SNUM(cnum)));
2404         if (lp_status(SNUM(cnum))) yield_connection(cnum,"STATUS.",MAXSTATUS);
2405       }
2406       return(-5);      
2407     }
2408
2409   string_set(&pcon->origpath,pcon->connectpath);
2410
2411 #if SOFTLINK_OPTIMISATION
2412   /* resolve any soft links early */
2413   {
2414     pstring s;
2415     strcpy(s,pcon->connectpath);
2416     GetWd(s);
2417     string_set(&pcon->connectpath,s);
2418     ChDir(pcon->connectpath);
2419   }
2420 #endif
2421
2422   num_connections_open++;
2423   add_session_user(user);
2424   
2425   /* execute any "preexec = " line */
2426   if (*lp_preexec(SNUM(cnum)))
2427     {
2428       pstring cmd;
2429       strcpy(cmd,lp_preexec(SNUM(cnum)));
2430       standard_sub(cnum,cmd);
2431       smbrun(cmd,NULL);
2432     }
2433   
2434   /* we've finished with the sensitive stuff */
2435   unbecome_user();
2436
2437   {
2438     extern struct from_host Client_info;
2439     DEBUG(IS_IPC(cnum)?3:1,("%s %s (%s) connect to service %s as user %s (uid=%d,gid=%d) (pid %d)\n",
2440                             timestring(),
2441                             Client_info.name,Client_info.addr,
2442                             lp_servicename(SNUM(cnum)),user,
2443                             pcon->uid,
2444                             pcon->gid,
2445                             (int)getpid()));
2446   }
2447
2448   return(cnum);
2449 }
2450
2451
2452 /****************************************************************************
2453   find first available file slot
2454 ****************************************************************************/
2455 int find_free_file(void )
2456 {
2457   int i;
2458   for (i=1;i<MAX_OPEN_FILES;i++)
2459     if (!Files[i].open)
2460       return(i);
2461   DEBUG(1,("ERROR! Out of file structures - perhaps increase MAX_OPEN_FILES?\n"));
2462   return(-1);
2463 }
2464
2465 /****************************************************************************
2466   find first available connection slot, starting from a random position.
2467 The randomisation stops problems with the server dieing and clients
2468 thinking the server is still available.
2469 ****************************************************************************/
2470 static int find_free_connection(int hash )
2471 {
2472   int i;
2473   BOOL used=False;
2474   hash = (hash % (MAX_CONNECTIONS-2))+1;
2475
2476  again:
2477
2478   for (i=hash+1;i!=hash;)
2479     {
2480       if (!Connections[i].open && Connections[i].used == used) 
2481         {
2482           DEBUG(3,("found free connection number %d\n",i));
2483           return(i);
2484         }
2485       i++;
2486       if (i == MAX_CONNECTIONS)
2487         i = 1;
2488     }
2489
2490   if (!used)
2491     {
2492       used = !used;
2493       goto again;
2494     }
2495
2496   DEBUG(1,("ERROR! Out of connection structures\n"));
2497   return(-1);
2498 }
2499
2500
2501 /****************************************************************************
2502 reply for the core protocol
2503 ****************************************************************************/
2504 int reply_corep(char *outbuf)
2505 {
2506   int outsize = set_message(outbuf,1,0,True);
2507
2508   Protocol = PROTOCOL_CORE;
2509
2510   return outsize;
2511 }
2512
2513
2514 /****************************************************************************
2515 reply for the coreplus protocol
2516 ****************************************************************************/
2517 int reply_coreplus(char *outbuf)
2518 {
2519   int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
2520   int outsize = set_message(outbuf,13,0,True);
2521   SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support
2522                                  readbraw and writebraw (possibly) */
2523   CVAL(outbuf,smb_flg) = 0x81; /* Reply, SMBlockread, SMBwritelock supported */
2524   SSVAL(outbuf,smb_vwv1,0x1); /* user level security, don't encrypt */  
2525
2526   Protocol = PROTOCOL_COREPLUS;
2527
2528   return outsize;
2529 }
2530
2531
2532 /****************************************************************************
2533 reply for the lanman 1.0 protocol
2534 ****************************************************************************/
2535 int reply_lanman1(char *outbuf)
2536 {
2537   int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
2538   int secword=0;
2539   BOOL doencrypt = SMBENCRYPT();
2540   time_t t = time(NULL);
2541
2542   if (lp_security()>=SEC_USER) secword |= 1;
2543   if (doencrypt) secword |= 2;
2544
2545   set_message(outbuf,13,doencrypt?8:0,True);
2546   SSVAL(outbuf,smb_vwv1,secword); 
2547 #ifdef SMB_PASSWD
2548   /* Create a token value and add it to the outgoing packet. */
2549   if (doencrypt) 
2550     generate_next_challenge(smb_buf(outbuf));
2551 #endif
2552
2553   Protocol = PROTOCOL_LANMAN1;
2554
2555   if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) {
2556     DEBUG(3,("using password server validation\n"));
2557 #ifdef SMB_PASSWD
2558   if (doencrypt) set_challenge(smb_buf(outbuf));    
2559 #endif
2560   }
2561
2562   CVAL(outbuf,smb_flg) = 0x81; /* Reply, SMBlockread, SMBwritelock supported */
2563   SSVAL(outbuf,smb_vwv2,maxxmit);
2564   SSVAL(outbuf,smb_vwv3,lp_maxmux()); /* maxmux */
2565   SSVAL(outbuf,smb_vwv4,1);
2566   SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support
2567                                  readbraw writebraw (possibly) */
2568   SIVAL(outbuf,smb_vwv6,getpid());
2569   SSVAL(outbuf,smb_vwv10, TimeDiff(t)/60);
2570
2571   put_dos_date(outbuf,smb_vwv8,t);
2572
2573   return (smb_len(outbuf)+4);
2574 }
2575
2576
2577 /****************************************************************************
2578 reply for the lanman 2.0 protocol
2579 ****************************************************************************/
2580 int reply_lanman2(char *outbuf)
2581 {
2582   int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
2583   int secword=0;
2584   BOOL doencrypt = SMBENCRYPT();
2585   time_t t = time(NULL);
2586
2587   if (lp_security()>=SEC_USER) secword |= 1;
2588   if (doencrypt) secword |= 2;
2589
2590   set_message(outbuf,13,doencrypt?8:0,True);
2591   SSVAL(outbuf,smb_vwv1,secword); 
2592 #ifdef SMB_PASSWD
2593   /* Create a token value and add it to the outgoing packet. */
2594   if (doencrypt) 
2595     generate_next_challenge(smb_buf(outbuf));
2596 #endif
2597
2598   SIVAL(outbuf,smb_vwv6,getpid());
2599
2600   Protocol = PROTOCOL_LANMAN2;
2601
2602   if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) {
2603     DEBUG(3,("using password server validation\n"));
2604 #ifdef SMB_PASSWD
2605     if (doencrypt) set_challenge(smb_buf(outbuf));    
2606 #endif
2607   }
2608
2609   CVAL(outbuf,smb_flg) = 0x81; /* Reply, SMBlockread, SMBwritelock supported */
2610   SSVAL(outbuf,smb_vwv2,maxxmit);
2611   SSVAL(outbuf,smb_vwv3,lp_maxmux()); 
2612   SSVAL(outbuf,smb_vwv4,1);
2613   SSVAL(outbuf,smb_vwv5,raw); /* readbraw and/or writebraw */
2614   SSVAL(outbuf,smb_vwv10, TimeDiff(t)/60);
2615   put_dos_date(outbuf,smb_vwv8,t);
2616
2617   return (smb_len(outbuf)+4);
2618 }
2619
2620 /****************************************************************************
2621 reply for the nt protocol
2622 ****************************************************************************/
2623 int reply_nt1(char *outbuf)
2624 {
2625   int capabilities=0x300; /* has dual names + lock_and_read */
2626   int secword=0;
2627   BOOL doencrypt = SMBENCRYPT();
2628
2629   if (lp_security()>=SEC_USER) secword |= 1;
2630   if (doencrypt) secword |= 2;
2631
2632   set_message(outbuf,17,doencrypt?8:0,True);
2633   CVAL(outbuf,smb_vwv1) = secword;
2634 #ifdef SMB_PASSWD
2635   /* Create a token value and add it to the outgoing packet. */
2636   if (doencrypt) {
2637     generate_next_challenge(smb_buf(outbuf));
2638     /* Tell the nt machine how long the challenge is. */
2639     SSVALS(outbuf,smb_vwv16+1,8);
2640   }
2641 #endif
2642
2643   SIVAL(outbuf,smb_vwv7+1,getpid()); /* session key */
2644
2645   Protocol = PROTOCOL_NT1;
2646
2647   if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) {
2648     DEBUG(3,("using password server validation\n"));
2649 #ifdef SMB_PASSWD
2650     if (doencrypt) set_challenge(smb_buf(outbuf));    
2651 #endif
2652   }
2653
2654   if (lp_readraw() && lp_writeraw())
2655     capabilities |= 1;
2656
2657   SSVAL(outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */
2658   SSVAL(outbuf,smb_vwv2+1,1); /* num vcs */
2659   SIVAL(outbuf,smb_vwv3+1,0xFFFF); /* max buffer */
2660   SIVAL(outbuf,smb_vwv5+1,0xFFFF); /* raw size */
2661   SIVAL(outbuf,smb_vwv9+1,capabilities); /* capabilities */
2662   put_long_date(outbuf+smb_vwv11+1,time(NULL));
2663   SSVALS(outbuf,smb_vwv15+1,TimeDiff(time(NULL))/60);
2664
2665   return (smb_len(outbuf)+4);
2666 }
2667
2668
2669 /* these are the protocol lists used for auto architecture detection:
2670
2671 WinNT 3.51:
2672 protocol [PC NETWORK PROGRAM 1.0]
2673 protocol [XENIX CORE]
2674 protocol [MICROSOFT NETWORKS 1.03]
2675 protocol [LANMAN1.0]
2676 protocol [Windows for Workgroups 3.1a]
2677 protocol [LM1.2X002]
2678 protocol [LANMAN2.1]
2679 protocol [NT LM 0.12]
2680
2681 Win95:
2682 protocol [PC NETWORK PROGRAM 1.0]
2683 protocol [XENIX CORE]
2684 protocol [MICROSOFT NETWORKS 1.03]
2685 protocol [LANMAN1.0]
2686 protocol [Windows for Workgroups 3.1a]
2687 protocol [LM1.2X002]
2688 protocol [LANMAN2.1]
2689 protocol [NT LM 0.12]
2690
2691 OS/2:
2692 protocol [PC NETWORK PROGRAM 1.0]
2693 protocol [XENIX CORE]
2694 protocol [LANMAN1.0]
2695 protocol [LM1.2X002]
2696 protocol [LANMAN2.1]
2697 */
2698
2699 /*
2700   * Modified to recognize the architecture of the remote machine better.
2701   *
2702   * This appears to be the matrix of which protocol is used by which
2703   * MS product.
2704        Protocol                       WfWg    Win95   WinNT  OS/2
2705        PC NETWORK PROGRAM 1.0          1       1       1      1
2706        XENIX CORE                                      2      2
2707        MICROSOFT NETWORKS 3.0          2       2       
2708        DOS LM1.2X002                   3       3       
2709        MICROSOFT NETWORKS 1.03                         3
2710        DOS LANMAN2.1                   4       4       
2711        LANMAN1.0                                       4      3
2712        Windows for Workgroups 3.1a     5       5       5
2713        LM1.2X002                                       6      4
2714        LANMAN2.1                                       7      5
2715        NT LM 0.12                              6       8
2716   *
2717   *  tim@fsg.com 09/29/95
2718   */
2719   
2720 #define ARCH_WFWG     0x3      /* This is a fudge because WfWg is like Win95 */
2721 #define ARCH_WIN95    0x2
2722 #define ARCH_OS2      0xC      /* Again OS/2 is like NT */
2723 #define ARCH_WINNT    0x8
2724 #define ARCH_SAMBA    0x10
2725  
2726 #define ARCH_ALL      0x1F
2727  
2728 /* List of supported protocols, most desired first */
2729 struct {
2730   char *proto_name;
2731   char *short_name;
2732   int (*proto_reply_fn)(char *);
2733   int protocol_level;
2734 } supported_protocols[] = {
2735   {"NT LANMAN 1.0",           "NT1",      reply_nt1,      PROTOCOL_NT1},
2736   {"NT LM 0.12",              "NT1",      reply_nt1,      PROTOCOL_NT1},
2737   {"LM1.2X002",               "LANMAN2",  reply_lanman2,  PROTOCOL_LANMAN2},
2738   {"Samba",                   "LANMAN2",  reply_lanman2,  PROTOCOL_LANMAN2},
2739   {"DOS LM1.2X002",           "LANMAN2",  reply_lanman2,  PROTOCOL_LANMAN2},
2740   {"LANMAN1.0",               "LANMAN1",  reply_lanman1,  PROTOCOL_LANMAN1},
2741   {"MICROSOFT NETWORKS 3.0",  "LANMAN1",  reply_lanman1,  PROTOCOL_LANMAN1},
2742   {"MICROSOFT NETWORKS 1.03", "COREPLUS", reply_coreplus, PROTOCOL_COREPLUS},
2743   {"PC NETWORK PROGRAM 1.0",  "CORE",     reply_corep,    PROTOCOL_CORE}, 
2744   {NULL,NULL},
2745 };
2746
2747
2748 /****************************************************************************
2749   reply to a negprot
2750 ****************************************************************************/
2751 static int reply_negprot(char *inbuf,char *outbuf)
2752 {
2753   extern fstring remote_arch;
2754   int outsize = set_message(outbuf,1,0,True);
2755   int Index=0;
2756   int choice= -1;
2757   int protocol;
2758   char *p;
2759   int bcc = SVAL(smb_buf(inbuf),-2);
2760   int arch = ARCH_ALL;
2761
2762   p = smb_buf(inbuf)+1;
2763   while (p < (smb_buf(inbuf) + bcc))
2764     { 
2765       Index++;
2766       DEBUG(3,("Requested protocol [%s]\n",p));
2767       if (strcsequal(p,"Windows for Workgroups 3.1a"))
2768         arch &= ( ARCH_WFWG | ARCH_WIN95 | ARCH_WINNT );
2769       else if (strcsequal(p,"DOS LM1.2X002"))
2770         arch &= ( ARCH_WFWG | ARCH_WIN95 );
2771       else if (strcsequal(p,"DOS LANMAN2.1"))
2772         arch &= ( ARCH_WFWG | ARCH_WIN95 );
2773       else if (strcsequal(p,"NT LM 0.12"))
2774         arch &= ( ARCH_WIN95 | ARCH_WINNT );
2775       else if (strcsequal(p,"LANMAN2.1"))
2776         arch &= ( ARCH_WINNT | ARCH_OS2 );
2777       else if (strcsequal(p,"LM1.2X002"))
2778         arch &= ( ARCH_WINNT | ARCH_OS2 );
2779       else if (strcsequal(p,"MICROSOFT NETWORKS 1.03"))
2780         arch &= ARCH_WINNT;
2781       else if (strcsequal(p,"XENIX CORE"))
2782         arch &= ( ARCH_WINNT | ARCH_OS2 );
2783       else if (strcsequal(p,"Samba")) {
2784         arch = ARCH_SAMBA;
2785         break;
2786       }
2787  
2788       p += strlen(p) + 2;
2789     }
2790     
2791   switch ( arch ) {
2792   case ARCH_SAMBA:
2793     strcpy(remote_arch,"Samba");
2794     break;
2795   case ARCH_WFWG:
2796     strcpy(remote_arch,"WfWg");
2797     break;
2798   case ARCH_WIN95:
2799     strcpy(remote_arch,"Win95");
2800     break;
2801   case ARCH_WINNT:
2802     strcpy(remote_arch,"WinNT");
2803     break;
2804   case ARCH_OS2:
2805     strcpy(remote_arch,"OS2");
2806     break;
2807   default:
2808     strcpy(remote_arch,"UNKNOWN");
2809     break;
2810   }
2811  
2812   /* possibly reload - change of architecture */
2813   reload_services(True);      
2814     
2815   /* a special case to stop password server loops */
2816   if (Index == 1 && strequal(remote_machine,myhostname) && 
2817       lp_security()==SEC_SERVER)
2818     exit_server("Password server loop!");
2819   
2820   /* Check for protocols, most desirable first */
2821   for (protocol = 0; supported_protocols[protocol].proto_name; protocol++)
2822     {
2823       p = smb_buf(inbuf)+1;
2824       Index = 0;
2825       if (lp_maxprotocol() >= supported_protocols[protocol].protocol_level)
2826         while (p < (smb_buf(inbuf) + bcc))
2827           { 
2828             if (strequal(p,supported_protocols[protocol].proto_name))
2829               choice = Index;
2830             Index++;
2831             p += strlen(p) + 2;
2832           }
2833       if(choice != -1)
2834         break;
2835     }
2836   
2837   SSVAL(outbuf,smb_vwv0,choice);
2838   if(choice != -1) {
2839     extern fstring remote_proto;
2840     strcpy(remote_proto,supported_protocols[protocol].short_name);
2841     reload_services(True);          
2842     outsize = supported_protocols[protocol].proto_reply_fn(outbuf);
2843     DEBUG(3,("Selected protocol %s\n",supported_protocols[protocol].proto_name));
2844   }
2845   else {
2846     DEBUG(0,("No protocol supported !\n"));
2847   }
2848   SSVAL(outbuf,smb_vwv0,choice);
2849   
2850   DEBUG(5,("%s negprot index=%d\n",timestring(),choice));
2851
2852   return(outsize);
2853 }
2854
2855
2856 /****************************************************************************
2857   parse a connect packet
2858 ****************************************************************************/
2859 void parse_connect(char *buf,char *service,char *user,char *password,int *pwlen,char *dev)
2860 {
2861   char *p = smb_buf(buf) + 1;
2862   char *p2;
2863
2864   DEBUG(4,("parsing connect string %s\n",p));
2865     
2866   p2 = strrchr(p,'\\');
2867   if (p2 == NULL)
2868     strcpy(service,p);
2869   else
2870     strcpy(service,p2+1);
2871   
2872   p += strlen(p) + 2;
2873   
2874   strcpy(password,p);
2875   *pwlen = strlen(password);
2876
2877   p += strlen(p) + 2;
2878
2879   strcpy(dev,p);
2880   
2881   *user = 0;
2882   p = strchr(service,'%');
2883   if (p != NULL)
2884     {
2885       *p = 0;
2886       strcpy(user,p+1);
2887     }
2888 }
2889
2890
2891 /****************************************************************************
2892 close all open files for a connection
2893 ****************************************************************************/
2894 static void close_open_files(int cnum)
2895 {
2896   int i;
2897   for (i=0;i<MAX_OPEN_FILES;i++)
2898     if( Files[i].cnum == cnum && Files[i].open) {
2899       close_file(i);
2900     }
2901 }
2902
2903
2904
2905 /****************************************************************************
2906 close a cnum
2907 ****************************************************************************/
2908 void close_cnum(int cnum, int uid)
2909 {
2910   extern struct from_host Client_info;
2911
2912   DirCacheFlush(SNUM(cnum));
2913
2914   unbecome_user();
2915
2916   if (!OPEN_CNUM(cnum))
2917     {
2918       DEBUG(0,("Can't close cnum %d\n",cnum));
2919       return;
2920     }
2921
2922   DEBUG(IS_IPC(cnum)?3:1,("%s %s (%s) closed connection to service %s\n",
2923                           timestring(),
2924                           Client_info.name,Client_info.addr,
2925                           lp_servicename(SNUM(cnum))));
2926
2927   yield_connection(cnum,
2928                    lp_servicename(SNUM(cnum)),
2929                    lp_max_connections(SNUM(cnum)));
2930
2931   if (lp_status(SNUM(cnum)))
2932     yield_connection(cnum,"STATUS.",MAXSTATUS);
2933
2934   close_open_files(cnum);
2935   dptr_closecnum(cnum);
2936
2937   /* execute any "postexec = " line */
2938   if (*lp_postexec(SNUM(cnum)) && become_user(cnum,uid))
2939     {
2940       pstring cmd;
2941       strcpy(cmd,lp_postexec(SNUM(cnum)));
2942       standard_sub(cnum,cmd);
2943       smbrun(cmd,NULL);
2944       unbecome_user();
2945     }
2946
2947   unbecome_user();
2948   /* execute any "root postexec = " line */
2949   if (*lp_rootpostexec(SNUM(cnum)))
2950     {
2951       pstring cmd;
2952       strcpy(cmd,lp_rootpostexec(SNUM(cnum)));
2953       standard_sub(cnum,cmd);
2954       smbrun(cmd,NULL);
2955     }
2956
2957   Connections[cnum].open = False;
2958   num_connections_open--;
2959   if (Connections[cnum].ngroups && Connections[cnum].groups)
2960     {
2961       if (Connections[cnum].igroups != (int *)Connections[cnum].groups)
2962         free(Connections[cnum].groups);
2963       free(Connections[cnum].igroups);
2964       Connections[cnum].groups = NULL;
2965       Connections[cnum].igroups = NULL;
2966       Connections[cnum].ngroups = 0;
2967     }
2968
2969   string_set(&Connections[cnum].user,"");
2970   string_set(&Connections[cnum].dirpath,"");
2971   string_set(&Connections[cnum].connectpath,"");
2972 }
2973
2974
2975 /****************************************************************************
2976 simple routines to do connection counting
2977 ****************************************************************************/
2978 BOOL yield_connection(int cnum,char *name,int max_connections)
2979 {
2980   struct connect_record crec;
2981   pstring fname;
2982   FILE *f;
2983   int mypid = getpid();
2984   int i;
2985
2986   DEBUG(3,("Yielding connection to %d %s\n",cnum,name));
2987
2988   if (max_connections <= 0)
2989     return(True);
2990
2991   bzero(&crec,sizeof(crec));
2992
2993   strcpy(fname,lp_lockdir());
2994   standard_sub(cnum,fname);
2995   trim_string(fname,"","/");
2996
2997   strcat(fname,"/");
2998   strcat(fname,name);
2999   strcat(fname,".LCK");
3000
3001   f = fopen(fname,"r+");
3002   if (!f)
3003     {
3004       DEBUG(2,("Coudn't open lock file %s (%s)\n",fname,strerror(errno)));
3005       return(False);
3006     }
3007
3008   fseek(f,0,SEEK_SET);
3009
3010   /* find a free spot */
3011   for (i=0;i<max_connections;i++)
3012     {
3013       if (fread(&crec,sizeof(crec),1,f) != 1)
3014         {
3015           DEBUG(2,("Entry not found in lock file %s\n",fname));
3016           fclose(f);
3017           return(False);
3018         }
3019       if (crec.pid == mypid && crec.cnum == cnum)
3020         break;
3021     }
3022
3023   if (crec.pid != mypid || crec.cnum != cnum)
3024     {
3025       fclose(f);
3026       DEBUG(2,("Entry not found in lock file %s\n",fname));
3027       return(False);
3028     }
3029
3030   bzero((void *)&crec,sizeof(crec));
3031   
3032   /* remove our mark */
3033   if (fseek(f,i*sizeof(crec),SEEK_SET) != 0 ||
3034       fwrite(&crec,sizeof(crec),1,f) != 1)
3035     {
3036       DEBUG(2,("Couldn't update lock file %s (%s)\n",fname,strerror(errno)));
3037       fclose(f);
3038       return(False);
3039     }
3040
3041   DEBUG(3,("Yield successful\n"));
3042
3043   fclose(f);
3044   return(True);
3045 }
3046
3047
3048 /****************************************************************************
3049 simple routines to do connection counting
3050 ****************************************************************************/
3051 BOOL claim_connection(int cnum,char *name,int max_connections,BOOL Clear)
3052 {
3053   struct connect_record crec;
3054   pstring fname;
3055   FILE *f;
3056   int snum = SNUM(cnum);
3057   int i,foundi= -1;
3058   int total_recs;
3059
3060   if (max_connections <= 0)
3061     return(True);
3062
3063   DEBUG(5,("trying claim %s %s %d\n",lp_lockdir(),name,max_connections));
3064
3065   strcpy(fname,lp_lockdir());
3066   standard_sub(cnum,fname);
3067   trim_string(fname,"","/");
3068
3069   if (!directory_exist(fname,NULL))
3070     mkdir(fname,0755);
3071
3072   strcat(fname,"/");
3073   strcat(fname,name);
3074   strcat(fname,".LCK");
3075
3076   if (!file_exist(fname,NULL))
3077     {
3078       f = fopen(fname,"w");
3079       if (f) fclose(f);
3080     }
3081
3082   total_recs = file_size(fname) / sizeof(crec);
3083
3084   f = fopen(fname,"r+");
3085
3086   if (!f)
3087     {
3088       DEBUG(1,("couldn't open lock file %s\n",fname));
3089       return(False);
3090     }
3091
3092   /* find a free spot */
3093   for (i=0;i<max_connections;i++)
3094     {
3095
3096       if (i>=total_recs || 
3097           fseek(f,i*sizeof(crec),SEEK_SET) != 0 ||
3098           fread(&crec,sizeof(crec),1,f) != 1)
3099         {
3100           if (foundi < 0) foundi = i;
3101           break;
3102         }
3103
3104       if (Clear && crec.pid && !process_exists(crec.pid))
3105         {
3106           fseek(f,i*sizeof(crec),SEEK_SET);
3107           bzero((void *)&crec,sizeof(crec));
3108           fwrite(&crec,sizeof(crec),1,f);
3109           if (foundi < 0) foundi = i;
3110           continue;
3111         }
3112       if (foundi < 0 && (!crec.pid || !process_exists(crec.pid)))
3113         {
3114           foundi=i;
3115           if (!Clear) break;
3116         }
3117     }  
3118
3119   if (foundi < 0)
3120     {
3121       DEBUG(3,("no free locks in %s\n",fname));
3122       fclose(f);
3123       return(False);
3124     }      
3125
3126   /* fill in the crec */
3127   bzero((void *)&crec,sizeof(crec));
3128   crec.magic = 0x280267;
3129   crec.pid = getpid();
3130   crec.cnum = cnum;
3131   crec.uid = Connections[cnum].uid;
3132   crec.gid = Connections[cnum].gid;
3133   StrnCpy(crec.name,lp_servicename(snum),sizeof(crec.name)-1);
3134   crec.start = time(NULL);
3135
3136   {
3137     extern struct from_host Client_info;
3138     StrnCpy(crec.machine,Client_info.name,sizeof(crec.machine)-1);
3139     StrnCpy(crec.addr,Client_info.addr,sizeof(crec.addr)-1);
3140   }
3141   
3142   /* make our mark */
3143   if (fseek(f,foundi*sizeof(crec),SEEK_SET) != 0 ||
3144       fwrite(&crec,sizeof(crec),1,f) != 1)
3145     {
3146       fclose(f);
3147       return(False);
3148     }
3149
3150   fclose(f);
3151   return(True);
3152 }
3153
3154 #if DUMP_CORE
3155 /*******************************************************************
3156 prepare to dump a core file - carefully!
3157 ********************************************************************/
3158 static BOOL dump_core(void)
3159 {
3160   char *p;
3161   pstring dname;
3162   strcpy(dname,debugf);
3163   if ((p=strrchr(dname,'/'))) *p=0;
3164   strcat(dname,"/corefiles");
3165   mkdir(dname,0700);
3166   sys_chown(dname,getuid(),getgid());
3167   chmod(dname,0700);
3168   if (chdir(dname)) return(False);
3169   umask(~(0700));
3170
3171 #ifndef NO_GETRLIMIT
3172 #ifdef RLIMIT_CORE
3173   {
3174     struct rlimit rlp;
3175     getrlimit(RLIMIT_CORE, &rlp);
3176     rlp.rlim_cur = MAX(4*1024*1024,rlp.rlim_cur);
3177     setrlimit(RLIMIT_CORE, &rlp);
3178     getrlimit(RLIMIT_CORE, &rlp);
3179     DEBUG(3,("Core limits now %d %d\n",rlp.rlim_cur,rlp.rlim_max));
3180   }
3181 #endif
3182 #endif
3183
3184
3185   DEBUG(0,("Dumping core in %s\n",dname));
3186   return(True);
3187 }
3188 #endif
3189
3190 /****************************************************************************
3191 exit the server
3192 ****************************************************************************/
3193 void exit_server(char *reason)
3194 {
3195   static int firsttime=1;
3196   int i;
3197
3198   if (!firsttime) exit(0);
3199   firsttime = 0;
3200
3201   unbecome_user();
3202   DEBUG(2,("Closing connections\n"));
3203   for (i=0;i<MAX_CONNECTIONS;i++)
3204     if (Connections[i].open)
3205       close_cnum(i,-1);
3206 #ifdef DFS_AUTH
3207   if (dcelogin_atmost_once)
3208     dfs_unlogin();
3209 #endif
3210   if (!reason) {   
3211     int oldlevel = DEBUGLEVEL;
3212     DEBUGLEVEL = 10;
3213     DEBUG(0,("Last message was %s\n",smb_fn_name(last_message)));
3214     if (last_inbuf)
3215       show_msg(last_inbuf);
3216     DEBUGLEVEL = oldlevel;
3217     DEBUG(0,("===============================================================\n"));
3218 #if DUMP_CORE
3219     if (dump_core()) return;
3220 #endif
3221   }    
3222   DEBUG(3,("%s Server exit  (%s)\n",timestring(),reason?reason:""));
3223   exit(0);
3224 }
3225
3226 /****************************************************************************
3227 do some standard substitutions in a string
3228 ****************************************************************************/
3229 void standard_sub(int cnum,char *s)
3230 {
3231   if (!strchr(s,'%')) return;
3232
3233   if (VALID_CNUM(cnum))
3234     {
3235       string_sub(s,"%S",lp_servicename(Connections[cnum].service));
3236       string_sub(s,"%P",Connections[cnum].connectpath);
3237       string_sub(s,"%u",Connections[cnum].user);
3238       if (strstr(s,"%H")) {
3239         char *home = get_home_dir(Connections[cnum].user);
3240         if (home) string_sub(s,"%H",home);
3241       }
3242       string_sub(s,"%g",gidtoname(Connections[cnum].gid));
3243     }
3244   standard_sub_basic(s);
3245 }
3246
3247 /*
3248 These flags determine some of the permissions required to do an operation 
3249
3250 Note that I don't set NEED_WRITE on some write operations because they
3251 are used by some brain-dead clients when printing, and I don't want to
3252 force write permissions on print services.
3253 */
3254 #define AS_USER (1<<0)
3255 #define NEED_WRITE (1<<1)
3256 #define TIME_INIT (1<<2)
3257 #define CAN_IPC (1<<3)
3258 #define AS_GUEST (1<<5)
3259
3260
3261 /* 
3262    define a list of possible SMB messages and their corresponding
3263    functions. Any message that has a NULL function is unimplemented -
3264    please feel free to contribute implementations!
3265 */
3266 struct smb_message_struct
3267 {
3268   int code;
3269   char *name;
3270   int (*fn)();
3271   int flags;
3272 #if PROFILING
3273   unsigned long time;
3274 #endif
3275 }
3276  smb_messages[] = {
3277
3278     /* CORE PROTOCOL */
3279
3280    {SMBnegprot,"SMBnegprot",reply_negprot,0},
3281    {SMBtcon,"SMBtcon",reply_tcon,0},
3282    {SMBtdis,"SMBtdis",reply_tdis,0},
3283    {SMBexit,"SMBexit",reply_exit,0},
3284    {SMBioctl,"SMBioctl",reply_ioctl,0},
3285    {SMBecho,"SMBecho",reply_echo,0},
3286    {SMBsesssetupX,"SMBsesssetupX",reply_sesssetup_and_X,0},
3287    {SMBtconX,"SMBtconX",reply_tcon_and_X,0},
3288    {SMBulogoffX, "SMBulogoffX", reply_ulogoffX, 0}, 
3289    {SMBgetatr,"SMBgetatr",reply_getatr,AS_USER},
3290    {SMBsetatr,"SMBsetatr",reply_setatr,AS_USER | NEED_WRITE},
3291    {SMBchkpth,"SMBchkpth",reply_chkpth,AS_USER},
3292    {SMBsearch,"SMBsearch",reply_search,AS_USER},
3293    {SMBopen,"SMBopen",reply_open,AS_USER},
3294
3295    /* note that SMBmknew and SMBcreate are deliberately overloaded */   
3296    {SMBcreate,"SMBcreate",reply_mknew,AS_USER},
3297    {SMBmknew,"SMBmknew",reply_mknew,AS_USER}, 
3298
3299    {SMBunlink,"SMBunlink",reply_unlink,AS_USER | NEED_WRITE},
3300    {SMBread,"SMBread",reply_read,AS_USER},
3301    {SMBwrite,"SMBwrite",reply_write,AS_USER},
3302    {SMBclose,"SMBclose",reply_close,AS_USER},
3303    {SMBmkdir,"SMBmkdir",reply_mkdir,AS_USER | NEED_WRITE},
3304    {SMBrmdir,"SMBrmdir",reply_rmdir,AS_USER | NEED_WRITE},
3305    {SMBdskattr,"SMBdskattr",reply_dskattr,AS_USER},
3306    {SMBmv,"SMBmv",reply_mv,AS_USER | NEED_WRITE},
3307
3308    /* this is a Pathworks specific call, allowing the 
3309       changing of the root path */
3310    {pSETDIR,"pSETDIR",reply_setdir,AS_USER}, 
3311
3312    {SMBlseek,"SMBlseek",reply_lseek,AS_USER},
3313    {SMBflush,"SMBflush",reply_flush,AS_USER},
3314    {SMBctemp,"SMBctemp",reply_ctemp,AS_USER},
3315    {SMBsplopen,"SMBsplopen",reply_printopen,AS_USER},
3316    {SMBsplclose,"SMBsplclose",reply_printclose,AS_USER},
3317    {SMBsplretq,"SMBsplretq",reply_printqueue,AS_USER},
3318    {SMBsplwr,"SMBsplwr",reply_printwrite,AS_USER},
3319    {SMBlock,"SMBlock",reply_lock,AS_USER},
3320    {SMBunlock,"SMBunlock",reply_unlock,AS_USER},
3321    
3322    /* CORE+ PROTOCOL FOLLOWS */
3323    
3324    {SMBreadbraw,"SMBreadbraw",reply_readbraw,AS_USER},
3325    {SMBwritebraw,"SMBwritebraw",reply_writebraw,AS_USER},
3326    {SMBwriteclose,"SMBwriteclose",reply_writeclose,AS_USER},
3327    {SMBlockread,"SMBlockread",reply_lockread,AS_USER},
3328    {SMBwriteunlock,"SMBwriteunlock",reply_writeunlock,AS_USER},
3329    
3330    /* LANMAN1.0 PROTOCOL FOLLOWS */
3331    
3332    {SMBreadBmpx,"SMBreadBmpx",reply_readbmpx,AS_USER},
3333    {SMBreadBs,"SMBreadBs",NULL,AS_USER},
3334    {SMBwriteBmpx,"SMBwriteBmpx",reply_writebmpx,AS_USER},
3335    {SMBwriteBs,"SMBwriteBs",reply_writebs,AS_USER},
3336    {SMBwritec,"SMBwritec",NULL,AS_USER},
3337    {SMBsetattrE,"SMBsetattrE",reply_setattrE,AS_USER | NEED_WRITE},
3338    {SMBgetattrE,"SMBgetattrE",reply_getattrE,AS_USER},
3339    {SMBtrans,"SMBtrans",reply_trans,AS_USER | CAN_IPC},
3340    {SMBtranss,"SMBtranss",NULL,AS_USER | CAN_IPC},
3341    {SMBioctls,"SMBioctls",NULL,AS_USER},
3342    {SMBcopy,"SMBcopy",reply_copy,AS_USER | NEED_WRITE},
3343    {SMBmove,"SMBmove",NULL,AS_USER | NEED_WRITE},
3344    
3345    {SMBopenX,"SMBopenX",reply_open_and_X,AS_USER},
3346    {SMBreadX,"SMBreadX",reply_read_and_X,AS_USER},
3347    {SMBwriteX,"SMBwriteX",reply_write_and_X,AS_USER},
3348    {SMBlockingX,"SMBlockingX",reply_lockingX,AS_USER},
3349    
3350    {SMBffirst,"SMBffirst",reply_search,AS_USER},
3351    {SMBfunique,"SMBfunique",reply_search,AS_USER},
3352    {SMBfclose,"SMBfclose",reply_fclose,AS_USER},
3353
3354    /* LANMAN2.0 PROTOCOL FOLLOWS */
3355    {SMBfindnclose, "SMBfindnclose", reply_findnclose, AS_USER},
3356    {SMBfindclose, "SMBfindclose", reply_findclose,AS_USER},
3357    {SMBtrans2, "SMBtrans2", reply_trans2, AS_USER},
3358    {SMBtranss2, "SMBtranss2", reply_transs2, AS_USER},
3359
3360    /* messaging routines */
3361    {SMBsends,"SMBsends",reply_sends,AS_GUEST},
3362    {SMBsendstrt,"SMBsendstrt",reply_sendstrt,AS_GUEST},
3363    {SMBsendend,"SMBsendend",reply_sendend,AS_GUEST},
3364    {SMBsendtxt,"SMBsendtxt",reply_sendtxt,AS_GUEST},
3365
3366    /* NON-IMPLEMENTED PARTS OF THE CORE PROTOCOL */
3367    
3368    {SMBsendb,"SMBsendb",NULL,AS_GUEST},
3369    {SMBfwdname,"SMBfwdname",NULL,AS_GUEST},
3370    {SMBcancelf,"SMBcancelf",NULL,AS_GUEST},
3371    {SMBgetmac,"SMBgetmac",NULL,AS_GUEST}
3372  };
3373
3374 /****************************************************************************
3375 return a string containing the function name of a SMB command
3376 ****************************************************************************/
3377 char *smb_fn_name(int type)
3378 {
3379   static char *unknown_name = "SMBunknown";
3380   static int num_smb_messages = 
3381     sizeof(smb_messages) / sizeof(struct smb_message_struct);
3382   int match;
3383
3384   for (match=0;match<num_smb_messages;match++)
3385     if (smb_messages[match].code == type)
3386       break;
3387
3388   if (match == num_smb_messages)
3389     return(unknown_name);
3390
3391   return(smb_messages[match].name);
3392 }
3393
3394
3395 /****************************************************************************
3396 do a switch on the message type, and return the response size
3397 ****************************************************************************/
3398 static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize)
3399 {
3400   static int pid= -1;
3401   int outsize = 0;
3402   static int num_smb_messages = 
3403     sizeof(smb_messages) / sizeof(struct smb_message_struct);
3404   int match;
3405
3406 #if PROFILING
3407   struct timeval msg_start_time;
3408   struct timeval msg_end_time;
3409   static unsigned long total_time = 0;
3410
3411   GetTimeOfDay(&msg_start_time);
3412 #endif
3413
3414   if (pid == -1)
3415     pid = getpid();
3416
3417   errno = 0;
3418   last_message = type;
3419
3420   /* make sure this is an SMB packet */
3421   if (strncmp(smb_base(inbuf),"\377SMB",4) != 0)
3422     {
3423       DEBUG(2,("Non-SMB packet of length %d\n",smb_len(inbuf)));
3424       return(-1);
3425     }
3426
3427   for (match=0;match<num_smb_messages;match++)
3428     if (smb_messages[match].code == type)
3429       break;
3430
3431   if (match == num_smb_messages)
3432     {
3433       DEBUG(0,("Unknown message type %d!\n",type));
3434       outsize = reply_unknown(inbuf,outbuf);
3435     }
3436   else
3437     {
3438       DEBUG(3,("switch message %s (pid %d)\n",smb_messages[match].name,pid));
3439       if (smb_messages[match].fn)
3440         {
3441           int cnum = SVAL(inbuf,smb_tid);
3442           int flags = smb_messages[match].flags;
3443           int uid = SVAL(inbuf,smb_uid);
3444
3445           /* does this protocol need to be run as root? */
3446           if (!(flags & AS_USER))
3447             unbecome_user();
3448
3449           /* does this protocol need to be run as the connected user? */
3450           if ((flags & AS_USER) && !become_user(cnum,uid))
3451             return(ERROR(ERRSRV,ERRinvnid));
3452
3453           /* does it need write permission? */
3454           if ((flags & NEED_WRITE) && !CAN_WRITE(cnum))
3455             return(ERROR(ERRSRV,ERRaccess));
3456
3457           /* ipc services are limited */
3458           if (IS_IPC(cnum) && (flags & AS_USER) && !(flags & CAN_IPC))
3459             return(ERROR(ERRSRV,ERRaccess));        
3460
3461           /* load service specific parameters */
3462           if (OPEN_CNUM(cnum) && !become_service(cnum,(flags & AS_USER)?True:False))
3463             return(ERROR(ERRSRV,ERRaccess));
3464
3465           /* does this protocol need to be run as guest? */
3466           if ((flags & AS_GUEST) && (!become_guest() || !check_access(-1)))
3467             return(ERROR(ERRSRV,ERRaccess));
3468
3469           last_inbuf = inbuf;
3470
3471           outsize = smb_messages[match].fn(inbuf,outbuf,size,bufsize);
3472         }
3473       else
3474         {
3475           outsize = reply_unknown(inbuf,outbuf);
3476         }
3477     }
3478
3479 #if PROFILING
3480   GetTimeOfDay(&msg_end_time);
3481   if (!(smb_messages[match].flags & TIME_INIT))
3482     {
3483       smb_messages[match].time = 0;
3484       smb_messages[match].flags |= TIME_INIT;
3485     }
3486   {
3487     unsigned long this_time =     
3488       (msg_end_time.tv_sec - msg_start_time.tv_sec)*1e6 +
3489         (msg_end_time.tv_usec - msg_start_time.tv_usec);
3490     smb_messages[match].time += this_time;
3491     total_time += this_time;
3492   }
3493   DEBUG(2,("TIME %s  %d usecs   %g pct\n",
3494            smb_fn_name(type),smb_messages[match].time,
3495         (100.0*smb_messages[match].time) / total_time));
3496 #endif
3497
3498   return(outsize);
3499 }
3500
3501
3502 /****************************************************************************
3503 construct a chained reply and add it to the already made reply
3504
3505 inbuf points to the original message start.
3506 inbuf2 points to the smb_wct part of the secondary message
3507 type is the type of the secondary message
3508 outbuf points to the original outbuffer
3509 outbuf2 points to the smb_wct field of the new outbuffer
3510 size is the total length of the incoming message (from inbuf1)
3511 bufsize is the total buffer size
3512
3513 return how many bytes were added to the response
3514 ****************************************************************************/
3515 int chain_reply(int type,char *inbuf,char *inbuf2,char *outbuf,char *outbuf2,int size,int bufsize)
3516 {
3517   int outsize = 0;
3518   char *ibuf,*obuf;
3519   static BOOL in_chain = False;
3520   static char *last_outbuf=NULL;
3521   BOOL was_inchain = in_chain;
3522   int insize_remaining;
3523   static int insize_deleted;
3524  
3525
3526   chain_size += PTR_DIFF(outbuf2,outbuf) - smb_wct;
3527   if (was_inchain)
3528     outbuf = last_outbuf;
3529   else
3530     insize_deleted = 0;
3531
3532
3533   insize_deleted = 0;
3534   inbuf2 -= insize_deleted;
3535   insize_remaining = size - PTR_DIFF(inbuf2,inbuf);
3536   insize_deleted += size - (insize_remaining + smb_wct);
3537
3538   in_chain = True;
3539   last_outbuf = outbuf;
3540
3541
3542   /* allocate some space for the in and out buffers of the chained message */
3543   ibuf = (char *)malloc(size + SAFETY_MARGIN);
3544   obuf = (char *)malloc(bufsize + SAFETY_MARGIN);
3545
3546   if (!ibuf || !obuf)
3547     {
3548       DEBUG(0,("Out of memory in chain reply\n"));
3549       return(ERROR(ERRSRV,ERRnoresource));
3550     }
3551
3552   ibuf += SMB_ALIGNMENT;
3553   obuf += SMB_ALIGNMENT;
3554
3555   /* create the in buffer */
3556   memcpy(ibuf,inbuf,smb_wct);
3557   memcpy(ibuf+smb_wct,inbuf2,insize_remaining);
3558   CVAL(ibuf,smb_com) = type;
3559
3560   /* create the out buffer */
3561   bzero(obuf,smb_size);
3562
3563   set_message(obuf,0,0,True);
3564   CVAL(obuf,smb_com) = CVAL(ibuf,smb_com);
3565   
3566   memcpy(obuf+4,ibuf+4,4);
3567   CVAL(obuf,smb_rcls) = SUCCESS;
3568   CVAL(obuf,smb_reh) = 0;
3569   CVAL(obuf,smb_flg) = 0x80 | (CVAL(ibuf,smb_flg) & 0x8); /* bit 7 set 
3570                                                              means a reply */
3571   SSVAL(obuf,smb_flg2,1); /* say we support long filenames */
3572   SSVAL(obuf,smb_err,SUCCESS);
3573   SSVAL(obuf,smb_tid,SVAL(inbuf,smb_tid));
3574   SSVAL(obuf,smb_pid,SVAL(inbuf,smb_pid));
3575   SSVAL(obuf,smb_uid,SVAL(inbuf,smb_uid));
3576   SSVAL(obuf,smb_mid,SVAL(inbuf,smb_mid));
3577
3578   DEBUG(3,("Chained message\n"));
3579   show_msg(ibuf);
3580
3581   /* process the request */
3582   outsize = switch_message(type,ibuf,obuf,smb_wct+insize_remaining,
3583                            bufsize-chain_size);
3584
3585   /* copy the new reply header over the old one, but preserve 
3586      the smb_com field */
3587   memcpy(outbuf+smb_com+1,obuf+smb_com+1,smb_wct-(smb_com+1));
3588
3589   /* and copy the data from the reply to the right spot */
3590   memcpy(outbuf2,obuf+smb_wct,outsize - smb_wct);
3591
3592   /* free the allocated buffers */
3593   if (ibuf) free(ibuf-SMB_ALIGNMENT);
3594   if (obuf) free(obuf-SMB_ALIGNMENT);
3595
3596   in_chain = was_inchain;
3597
3598   /* return how much extra has been added to the packet */
3599   return(outsize - smb_wct);
3600 }
3601
3602
3603
3604 /****************************************************************************
3605   construct a reply to the incoming packet
3606 ****************************************************************************/
3607 int construct_reply(char *inbuf,char *outbuf,int size,int bufsize)
3608 {
3609   int type = CVAL(inbuf,smb_com);
3610   int outsize = 0;
3611   int msg_type = CVAL(inbuf,0);
3612
3613   smb_last_time = time(NULL);
3614
3615   chain_size = 0;
3616
3617   bzero(outbuf,smb_size);
3618
3619   if (msg_type != 0)
3620     return(reply_special(inbuf,outbuf));  
3621
3622   CVAL(outbuf,smb_com) = CVAL(inbuf,smb_com);
3623   set_message(outbuf,0,0,True);
3624   
3625   memcpy(outbuf+4,inbuf+4,4);
3626   CVAL(outbuf,smb_rcls) = SUCCESS;
3627   CVAL(outbuf,smb_reh) = 0;
3628   CVAL(outbuf,smb_flg) = 0x80 | (CVAL(inbuf,smb_flg) & 0x8); /* bit 7 set 
3629                                                              means a reply */
3630   SSVAL(outbuf,smb_flg2,1); /* say we support long filenames */
3631   SSVAL(outbuf,smb_err,SUCCESS);
3632   SSVAL(outbuf,smb_tid,SVAL(inbuf,smb_tid));
3633   SSVAL(outbuf,smb_pid,SVAL(inbuf,smb_pid));
3634   SSVAL(outbuf,smb_uid,SVAL(inbuf,smb_uid));
3635   SSVAL(outbuf,smb_mid,SVAL(inbuf,smb_mid));
3636
3637   outsize = switch_message(type,inbuf,outbuf,size,bufsize);
3638
3639   if(outsize > 4)
3640     smb_setlen(outbuf,outsize - 4);
3641   return(outsize);
3642 }
3643
3644
3645 /****************************************************************************
3646   process commands from the client
3647 ****************************************************************************/
3648 void process(void )
3649 {
3650   static int trans_num = 0;
3651   int nread;
3652   extern struct from_host Client_info;
3653   extern int Client;
3654
3655   fromhost(Client,&Client_info);
3656   
3657   InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3658   OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3659   if ((InBuffer == NULL) || (OutBuffer == NULL)) 
3660     return;
3661
3662   InBuffer += SMB_ALIGNMENT;
3663   OutBuffer += SMB_ALIGNMENT;
3664
3665 #if PRIME_NMBD
3666   DEBUG(3,("priming nmbd\n"));
3667   {
3668     struct in_addr ip;
3669     ip = *interpret_addr2("localhost");
3670     if (zero_ip(ip)) ip = *interpret_addr2("127.0.0.1");
3671     *OutBuffer = 0;
3672     send_one_packet(OutBuffer,1,ip,137,SOCK_DGRAM);
3673   }
3674 #endif    
3675
3676   last_user.cnum = -1;
3677   
3678   while (True)
3679     {
3680       int32 len;      
3681       int msg_type;
3682       int msg_flags;
3683       int type;
3684       int deadtime = lp_deadtime()*60;
3685       int counter;
3686       int last_keepalive=0;
3687
3688       if (deadtime <= 0)
3689         deadtime = DEFAULT_SMBD_TIMEOUT;
3690
3691       if (lp_readprediction())
3692         do_read_prediction();
3693
3694       {
3695         extern pstring share_del_pending;
3696         if (*share_del_pending) {
3697           unbecome_user();
3698           if (!unlink(share_del_pending))
3699             DEBUG(3,("Share file deleted %s\n",share_del_pending));
3700           else
3701             DEBUG(2,("Share del failed of %s\n",share_del_pending));
3702           share_del_pending[0] = 0;
3703         }
3704       }
3705
3706       if (share_mode_pending) {
3707         unbecome_user();
3708         check_share_modes();
3709         share_mode_pending=False;
3710       }
3711
3712       errno = 0;      
3713
3714       for (counter=SMBD_SELECT_LOOP; 
3715            !receive_smb(Client,InBuffer,SMBD_SELECT_LOOP*1000); 
3716            counter += SMBD_SELECT_LOOP)
3717         {
3718           int i;
3719           time_t t;
3720           BOOL allidle = True;
3721           extern int keepalive;
3722
3723           /* check for socket failure */
3724           if (errno == EBADF) {
3725             DEBUG(3,("%s Bad file descriptor - exiting\n",timestring()));
3726             return;
3727           }
3728
3729           t = time(NULL);
3730
3731           /* become root again if waiting */
3732           unbecome_user();
3733
3734           /* check for smb.conf reload */
3735           if (!(counter%SMBD_RELOAD_CHECK))
3736             reload_services(True);
3737
3738           /* check the share modes every 10 secs */
3739           if (!(counter%SHARE_MODES_CHECK))
3740             check_share_modes();
3741
3742           /* clean the share modes every 5 minutes */
3743           if (!(counter%SHARE_MODES_CLEAN))
3744             clean_share_files();
3745
3746           /* automatic timeout if all connections are closed */      
3747           if (num_connections_open==0 && counter >= IDLE_CLOSED_TIMEOUT) {
3748             DEBUG(2,("%s Closing idle connection\n",timestring()));
3749             return;
3750           }
3751
3752           if (keepalive && (counter-last_keepalive)>keepalive) {
3753             extern int password_client;
3754             if (!send_keepalive(Client)) {
3755               DEBUG(2,("%s Keepalive failed - exiting\n",timestring()));
3756               return;
3757             }       
3758             /* also send a keepalive to the password server if its still
3759                connected */
3760             if (password_client != -1)
3761               send_keepalive(password_client);
3762             last_keepalive = counter;
3763           }
3764
3765           /* check for connection timeouts */
3766           for (i=0;i<MAX_CONNECTIONS;i++)
3767             if (Connections[i].open)
3768               {
3769                 /* close dirptrs on connections that are idle */
3770                 if ((t-Connections[i].lastused)>DPTR_IDLE_TIMEOUT)
3771                   dptr_idlecnum(i);
3772
3773                 if (Connections[i].num_files_open > 0 ||
3774                     (t-Connections[i].lastused)<deadtime)
3775                   allidle = False;
3776               }
3777
3778           if (allidle && num_connections_open>0) {
3779             DEBUG(2,("%s Closing idle connection 2\n",timestring()));
3780             return;
3781           }
3782         }
3783
3784       msg_type = CVAL(InBuffer,0);
3785       msg_flags = CVAL(InBuffer,1);
3786       type = CVAL(InBuffer,smb_com);
3787
3788       len = smb_len(InBuffer);
3789
3790       DEBUG(6,("got message type 0x%x of len 0x%x\n",msg_type,len));
3791
3792       nread = len + 4;
3793       
3794       DEBUG(3,("%s Transaction %d of length %d\n",timestring(),trans_num,nread));
3795
3796 #ifdef WITH_VTP
3797       if(trans_num == 1 && VT_Check(InBuffer)) {
3798         VT_Process();
3799         return;
3800       }
3801 #endif
3802
3803
3804       if (msg_type == 0)
3805         show_msg(InBuffer);
3806
3807       nread = construct_reply(InBuffer,OutBuffer,nread,maxxmit);
3808       
3809       if(nread > 0) {
3810         if (CVAL(OutBuffer,0) == 0)
3811           show_msg(OutBuffer);
3812         
3813         if (nread != smb_len(OutBuffer) + 4) 
3814           {
3815             DEBUG(0,("ERROR: Invalid message response size! %d %d\n",
3816                      nread,
3817                      smb_len(OutBuffer)));
3818           }
3819         else
3820           send_smb(Client,OutBuffer);
3821       }
3822       trans_num++;
3823     }
3824 }
3825
3826
3827 /****************************************************************************
3828   initialise connect, service and file structs
3829 ****************************************************************************/
3830 static void init_structs(void )
3831 {
3832   int i;
3833   get_myname(myhostname,&myip);
3834
3835   for (i=0;i<MAX_CONNECTIONS;i++)
3836     {
3837       Connections[i].open = False;
3838       Connections[i].num_files_open=0;
3839       Connections[i].lastused=0;
3840       Connections[i].used=False;
3841       string_init(&Connections[i].user,"");
3842       string_init(&Connections[i].dirpath,"");
3843       string_init(&Connections[i].connectpath,"");
3844       string_init(&Connections[i].origpath,"");
3845     }
3846
3847   for (i=0;i<MAX_OPEN_FILES;i++)
3848     {
3849       Files[i].open = False;
3850       string_init(&Files[i].name,"");
3851     }
3852
3853   init_dptrs();
3854 }
3855
3856 /****************************************************************************
3857 usage on the program
3858 ****************************************************************************/
3859 void usage(char *pname)
3860 {
3861   DEBUG(0,("Incorrect program usage - are you sure the command line is correct?\n"));
3862
3863   printf("Usage: %s [-D] [-p port] [-d debuglevel] [-l log basename] [-s services file]\n",pname);
3864   printf("Version %s\n",VERSION);
3865   printf("\t-D                    become a daemon\n");
3866   printf("\t-p port               listen on the specified port\n");
3867   printf("\t-d debuglevel         set the debuglevel\n");
3868   printf("\t-l log basename.      Basename for log/debug files\n");
3869   printf("\t-s services file.     Filename of services file\n");
3870   printf("\t-P                    passive only\n");
3871   printf("\t-a                    overwrite log file, don't append\n");
3872   printf("\n");
3873 }
3874
3875
3876 /****************************************************************************
3877   main program
3878 ****************************************************************************/
3879 int main(int argc,char *argv[])
3880 {
3881   extern BOOL append_log;
3882   /* shall I run as a daemon */
3883   BOOL is_daemon = False;
3884   int port = 139;
3885   int opt;
3886   extern char *optarg;
3887
3888 #ifdef NEED_AUTH_PARAMETERS
3889   set_auth_parameters(argc,argv);
3890 #endif
3891
3892 #ifdef SecureWare
3893   setluid(0);
3894 #endif
3895
3896   append_log = True;
3897
3898   TimeInit();
3899
3900   strcpy(debugf,SMBLOGFILE);  
3901
3902   setup_logging(argv[0],False);
3903
3904   charset_initialise();
3905
3906   /* make absolutely sure we run as root - to handle cases whre people
3907      are crazy enough to have it setuid */
3908 #ifdef USE_SETRES
3909   setresuid(0,0,0);
3910 #else
3911   setuid(0);
3912   seteuid(0);
3913   setuid(0);
3914   seteuid(0);
3915 #endif
3916
3917   fault_setup(exit_server);
3918
3919   umask(0777 & ~DEF_CREATE_MASK);
3920
3921   initial_uid = geteuid();
3922   initial_gid = getegid();
3923
3924   if (initial_gid != 0 && initial_uid == 0)
3925     {
3926 #ifdef HPUX
3927       setresgid(0,0,0);
3928 #else
3929       setgid(0);
3930       setegid(0);
3931 #endif
3932     }
3933
3934   initial_uid = geteuid();
3935   initial_gid = getegid();
3936
3937
3938   /* this is for people who can't start the program correctly */
3939   while (argc > 1 && (*argv[1] != '-'))
3940     {
3941       argv++;
3942       argc--;
3943     }
3944
3945   while ((opt = getopt(argc, argv, "O:i:l:s:d:Dp:hPa")) != EOF)
3946     switch (opt)
3947       {
3948       case 'O':
3949         strcpy(user_socket_options,optarg);
3950         break;
3951       case 'i':
3952         strcpy(scope,optarg);
3953         break;
3954       case 'P':
3955         {
3956           extern BOOL passive;
3957           passive = True;
3958         }
3959         break;  
3960       case 's':
3961         strcpy(servicesf,optarg);
3962         break;
3963       case 'l':
3964         strcpy(debugf,optarg);
3965         break;
3966       case 'a':
3967         {
3968           extern BOOL append_log;
3969           append_log = !append_log;
3970         }
3971         break;
3972       case 'D':
3973         is_daemon = True;
3974         break;
3975       case 'd':
3976         if (*optarg == 'A')
3977           DEBUGLEVEL = 10000;
3978         else
3979           DEBUGLEVEL = atoi(optarg);
3980         break;
3981       case 'p':
3982         port = atoi(optarg);
3983         break;
3984       case 'h':
3985         usage(argv[0]);
3986         exit(0);
3987         break;
3988       default:
3989         usage(argv[0]);
3990         exit(1);
3991       }
3992
3993   reopen_logs();
3994
3995   DEBUG(2,("%s smbd version %s started\n",timestring(),VERSION));
3996   DEBUG(2,("Copyright Andrew Tridgell 1992-1995\n"));
3997
3998   GetWd(OriginalDir);
3999
4000 #ifndef NO_GETRLIMIT
4001 #ifdef RLIMIT_NOFILE
4002   {
4003     struct rlimit rlp;
4004     getrlimit(RLIMIT_NOFILE, &rlp);
4005     rlp.rlim_cur = (MAX_OPEN_FILES>rlp.rlim_max)? rlp.rlim_max:MAX_OPEN_FILES;
4006     setrlimit(RLIMIT_NOFILE, &rlp);
4007     getrlimit(RLIMIT_NOFILE, &rlp);
4008     DEBUG(3,("Maximum number of open files per session is %d\n",rlp.rlim_cur));
4009   }
4010 #endif
4011 #endif
4012
4013   
4014   DEBUG(2,("uid=%d gid=%d euid=%d egid=%d\n",
4015         getuid(),getgid(),geteuid(),getegid()));
4016
4017   if (sizeof(uint16) < 2 || sizeof(uint32) < 4)
4018     {
4019       DEBUG(0,("ERROR: Samba is not configured correctly for the word size on your machine\n"));
4020       exit(1);
4021     }
4022
4023   init_structs();
4024
4025   if (!reload_services(False))
4026     return(-1); 
4027
4028 #ifndef NO_SIGNAL_TEST
4029   signal(SIGHUP,SIGNAL_CAST sig_hup);
4030 #endif
4031   
4032   DEBUG(3,("%s loaded services\n",timestring()));
4033
4034   if (!is_daemon && !is_a_socket(0))
4035     {
4036       DEBUG(0,("standard input is not a socket, assuming -D option\n"));
4037       is_daemon = True;
4038     }
4039
4040   if (is_daemon)
4041     {
4042       DEBUG(3,("%s becoming a daemon\n",timestring()));
4043       become_daemon();
4044     }
4045
4046   if (!open_sockets(is_daemon,port))
4047     exit(1);
4048
4049   /* possibly reload the services file. */
4050   reload_services(True);
4051
4052   maxxmit = MIN(lp_maxxmit(),BUFFER_SIZE);
4053
4054   if (*lp_rootdir())
4055     {
4056       if (sys_chroot(lp_rootdir()) == 0)
4057         DEBUG(2,("%s changed root to %s\n",timestring(),lp_rootdir()));
4058     }
4059
4060   process();
4061   close_sockets();
4062
4063   exit_server("normal exit");
4064   return(0);
4065 }
4066
4067