- added an entry on WinDD to samba.faq
[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 (%s)\n",
2398                pcon->connectpath,strerror(errno)));
2399       pcon->open = False;
2400       unbecome_user();
2401       if (!IS_IPC(cnum)) {
2402         yield_connection(cnum,
2403                          lp_servicename(SNUM(cnum)),
2404                          lp_max_connections(SNUM(cnum)));
2405         if (lp_status(SNUM(cnum))) yield_connection(cnum,"STATUS.",MAXSTATUS);
2406       }
2407       return(-5);      
2408     }
2409
2410   string_set(&pcon->origpath,pcon->connectpath);
2411
2412 #if SOFTLINK_OPTIMISATION
2413   /* resolve any soft links early */
2414   {
2415     pstring s;
2416     strcpy(s,pcon->connectpath);
2417     GetWd(s);
2418     string_set(&pcon->connectpath,s);
2419     ChDir(pcon->connectpath);
2420   }
2421 #endif
2422
2423   num_connections_open++;
2424   add_session_user(user);
2425   
2426   /* execute any "preexec = " line */
2427   if (*lp_preexec(SNUM(cnum)))
2428     {
2429       pstring cmd;
2430       strcpy(cmd,lp_preexec(SNUM(cnum)));
2431       standard_sub(cnum,cmd);
2432       smbrun(cmd,NULL);
2433     }
2434   
2435   /* we've finished with the sensitive stuff */
2436   unbecome_user();
2437
2438   {
2439     extern struct from_host Client_info;
2440     DEBUG(IS_IPC(cnum)?3:1,("%s %s (%s) connect to service %s as user %s (uid=%d,gid=%d) (pid %d)\n",
2441                             timestring(),
2442                             Client_info.name,Client_info.addr,
2443                             lp_servicename(SNUM(cnum)),user,
2444                             pcon->uid,
2445                             pcon->gid,
2446                             (int)getpid()));
2447   }
2448
2449   return(cnum);
2450 }
2451
2452
2453 /****************************************************************************
2454   find first available file slot
2455 ****************************************************************************/
2456 int find_free_file(void )
2457 {
2458   int i;
2459   for (i=1;i<MAX_OPEN_FILES;i++)
2460     if (!Files[i].open)
2461       return(i);
2462   DEBUG(1,("ERROR! Out of file structures - perhaps increase MAX_OPEN_FILES?\n"));
2463   return(-1);
2464 }
2465
2466 /****************************************************************************
2467   find first available connection slot, starting from a random position.
2468 The randomisation stops problems with the server dieing and clients
2469 thinking the server is still available.
2470 ****************************************************************************/
2471 static int find_free_connection(int hash )
2472 {
2473   int i;
2474   BOOL used=False;
2475   hash = (hash % (MAX_CONNECTIONS-2))+1;
2476
2477  again:
2478
2479   for (i=hash+1;i!=hash;)
2480     {
2481       if (!Connections[i].open && Connections[i].used == used) 
2482         {
2483           DEBUG(3,("found free connection number %d\n",i));
2484           return(i);
2485         }
2486       i++;
2487       if (i == MAX_CONNECTIONS)
2488         i = 1;
2489     }
2490
2491   if (!used)
2492     {
2493       used = !used;
2494       goto again;
2495     }
2496
2497   DEBUG(1,("ERROR! Out of connection structures\n"));
2498   return(-1);
2499 }
2500
2501
2502 /****************************************************************************
2503 reply for the core protocol
2504 ****************************************************************************/
2505 int reply_corep(char *outbuf)
2506 {
2507   int outsize = set_message(outbuf,1,0,True);
2508
2509   Protocol = PROTOCOL_CORE;
2510
2511   return outsize;
2512 }
2513
2514
2515 /****************************************************************************
2516 reply for the coreplus protocol
2517 ****************************************************************************/
2518 int reply_coreplus(char *outbuf)
2519 {
2520   int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
2521   int outsize = set_message(outbuf,13,0,True);
2522   SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support
2523                                  readbraw and writebraw (possibly) */
2524   CVAL(outbuf,smb_flg) = 0x81; /* Reply, SMBlockread, SMBwritelock supported */
2525   SSVAL(outbuf,smb_vwv1,0x1); /* user level security, don't encrypt */  
2526
2527   Protocol = PROTOCOL_COREPLUS;
2528
2529   return outsize;
2530 }
2531
2532
2533 /****************************************************************************
2534 reply for the lanman 1.0 protocol
2535 ****************************************************************************/
2536 int reply_lanman1(char *outbuf)
2537 {
2538   int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
2539   int secword=0;
2540   BOOL doencrypt = SMBENCRYPT();
2541   time_t t = time(NULL);
2542
2543   if (lp_security()>=SEC_USER) secword |= 1;
2544   if (doencrypt) secword |= 2;
2545
2546   set_message(outbuf,13,doencrypt?8:0,True);
2547   SSVAL(outbuf,smb_vwv1,secword); 
2548 #ifdef SMB_PASSWD
2549   /* Create a token value and add it to the outgoing packet. */
2550   if (doencrypt) 
2551     generate_next_challenge(smb_buf(outbuf));
2552 #endif
2553
2554   Protocol = PROTOCOL_LANMAN1;
2555
2556   if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) {
2557     DEBUG(3,("using password server validation\n"));
2558 #ifdef SMB_PASSWD
2559   if (doencrypt) set_challenge(smb_buf(outbuf));    
2560 #endif
2561   }
2562
2563   CVAL(outbuf,smb_flg) = 0x81; /* Reply, SMBlockread, SMBwritelock supported */
2564   SSVAL(outbuf,smb_vwv2,maxxmit);
2565   SSVAL(outbuf,smb_vwv3,lp_maxmux()); /* maxmux */
2566   SSVAL(outbuf,smb_vwv4,1);
2567   SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support
2568                                  readbraw writebraw (possibly) */
2569   SIVAL(outbuf,smb_vwv6,getpid());
2570   SSVAL(outbuf,smb_vwv10, TimeDiff(t)/60);
2571
2572   put_dos_date(outbuf,smb_vwv8,t);
2573
2574   return (smb_len(outbuf)+4);
2575 }
2576
2577
2578 /****************************************************************************
2579 reply for the lanman 2.0 protocol
2580 ****************************************************************************/
2581 int reply_lanman2(char *outbuf)
2582 {
2583   int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
2584   int secword=0;
2585   BOOL doencrypt = SMBENCRYPT();
2586   time_t t = time(NULL);
2587
2588   if (lp_security()>=SEC_USER) secword |= 1;
2589   if (doencrypt) secword |= 2;
2590
2591   set_message(outbuf,13,doencrypt?8:0,True);
2592   SSVAL(outbuf,smb_vwv1,secword); 
2593 #ifdef SMB_PASSWD
2594   /* Create a token value and add it to the outgoing packet. */
2595   if (doencrypt) 
2596     generate_next_challenge(smb_buf(outbuf));
2597 #endif
2598
2599   SIVAL(outbuf,smb_vwv6,getpid());
2600
2601   Protocol = PROTOCOL_LANMAN2;
2602
2603   if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) {
2604     DEBUG(3,("using password server validation\n"));
2605 #ifdef SMB_PASSWD
2606     if (doencrypt) set_challenge(smb_buf(outbuf));    
2607 #endif
2608   }
2609
2610   CVAL(outbuf,smb_flg) = 0x81; /* Reply, SMBlockread, SMBwritelock supported */
2611   SSVAL(outbuf,smb_vwv2,maxxmit);
2612   SSVAL(outbuf,smb_vwv3,lp_maxmux()); 
2613   SSVAL(outbuf,smb_vwv4,1);
2614   SSVAL(outbuf,smb_vwv5,raw); /* readbraw and/or writebraw */
2615   SSVAL(outbuf,smb_vwv10, TimeDiff(t)/60);
2616   put_dos_date(outbuf,smb_vwv8,t);
2617
2618   return (smb_len(outbuf)+4);
2619 }
2620
2621 /****************************************************************************
2622 reply for the nt protocol
2623 ****************************************************************************/
2624 int reply_nt1(char *outbuf)
2625 {
2626   int capabilities=0x300; /* has dual names + lock_and_read */
2627   int secword=0;
2628   BOOL doencrypt = SMBENCRYPT();
2629   time_t t = time(NULL);
2630
2631   if (lp_security()>=SEC_USER) secword |= 1;
2632   if (doencrypt) secword |= 2;
2633
2634   set_message(outbuf,17,doencrypt?8:0,True);
2635   CVAL(outbuf,smb_vwv1) = secword;
2636 #ifdef SMB_PASSWD
2637   /* Create a token value and add it to the outgoing packet. */
2638   if (doencrypt) {
2639     generate_next_challenge(smb_buf(outbuf));
2640     /* Tell the nt machine how long the challenge is. */
2641     SSVALS(outbuf,smb_vwv16+1,8);
2642   }
2643 #endif
2644
2645   SIVAL(outbuf,smb_vwv7+1,getpid()); /* session key */
2646
2647   Protocol = PROTOCOL_NT1;
2648
2649   if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) {
2650     DEBUG(3,("using password server validation\n"));
2651 #ifdef SMB_PASSWD
2652     if (doencrypt) set_challenge(smb_buf(outbuf));    
2653 #endif
2654   }
2655
2656   if (lp_readraw() && lp_writeraw())
2657     capabilities |= 1;
2658
2659   SSVAL(outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */
2660   SSVAL(outbuf,smb_vwv2+1,1); /* num vcs */
2661   SIVAL(outbuf,smb_vwv3+1,0xFFFF); /* max buffer */
2662   SIVAL(outbuf,smb_vwv5+1,0xFFFF); /* raw size */
2663   SIVAL(outbuf,smb_vwv9+1,capabilities); /* capabilities */
2664   put_long_date(outbuf+smb_vwv11+1,t);
2665   SSVALS(outbuf,smb_vwv15+1,TimeDiff(t)/60);
2666
2667   return (smb_len(outbuf)+4);
2668 }
2669
2670
2671 /* these are the protocol lists used for auto architecture detection:
2672
2673 WinNT 3.51:
2674 protocol [PC NETWORK PROGRAM 1.0]
2675 protocol [XENIX CORE]
2676 protocol [MICROSOFT NETWORKS 1.03]
2677 protocol [LANMAN1.0]
2678 protocol [Windows for Workgroups 3.1a]
2679 protocol [LM1.2X002]
2680 protocol [LANMAN2.1]
2681 protocol [NT LM 0.12]
2682
2683 Win95:
2684 protocol [PC NETWORK PROGRAM 1.0]
2685 protocol [XENIX CORE]
2686 protocol [MICROSOFT NETWORKS 1.03]
2687 protocol [LANMAN1.0]
2688 protocol [Windows for Workgroups 3.1a]
2689 protocol [LM1.2X002]
2690 protocol [LANMAN2.1]
2691 protocol [NT LM 0.12]
2692
2693 OS/2:
2694 protocol [PC NETWORK PROGRAM 1.0]
2695 protocol [XENIX CORE]
2696 protocol [LANMAN1.0]
2697 protocol [LM1.2X002]
2698 protocol [LANMAN2.1]
2699 */
2700
2701 /*
2702   * Modified to recognize the architecture of the remote machine better.
2703   *
2704   * This appears to be the matrix of which protocol is used by which
2705   * MS product.
2706        Protocol                       WfWg    Win95   WinNT  OS/2
2707        PC NETWORK PROGRAM 1.0          1       1       1      1
2708        XENIX CORE                                      2      2
2709        MICROSOFT NETWORKS 3.0          2       2       
2710        DOS LM1.2X002                   3       3       
2711        MICROSOFT NETWORKS 1.03                         3
2712        DOS LANMAN2.1                   4       4       
2713        LANMAN1.0                                       4      3
2714        Windows for Workgroups 3.1a     5       5       5
2715        LM1.2X002                                       6      4
2716        LANMAN2.1                                       7      5
2717        NT LM 0.12                              6       8
2718   *
2719   *  tim@fsg.com 09/29/95
2720   */
2721   
2722 #define ARCH_WFWG     0x3      /* This is a fudge because WfWg is like Win95 */
2723 #define ARCH_WIN95    0x2
2724 #define ARCH_OS2      0xC      /* Again OS/2 is like NT */
2725 #define ARCH_WINNT    0x8
2726 #define ARCH_SAMBA    0x10
2727  
2728 #define ARCH_ALL      0x1F
2729  
2730 /* List of supported protocols, most desired first */
2731 struct {
2732   char *proto_name;
2733   char *short_name;
2734   int (*proto_reply_fn)(char *);
2735   int protocol_level;
2736 } supported_protocols[] = {
2737   {"NT LANMAN 1.0",           "NT1",      reply_nt1,      PROTOCOL_NT1},
2738   {"NT LM 0.12",              "NT1",      reply_nt1,      PROTOCOL_NT1},
2739   {"LM1.2X002",               "LANMAN2",  reply_lanman2,  PROTOCOL_LANMAN2},
2740   {"Samba",                   "LANMAN2",  reply_lanman2,  PROTOCOL_LANMAN2},
2741   {"DOS LM1.2X002",           "LANMAN2",  reply_lanman2,  PROTOCOL_LANMAN2},
2742   {"LANMAN1.0",               "LANMAN1",  reply_lanman1,  PROTOCOL_LANMAN1},
2743   {"MICROSOFT NETWORKS 3.0",  "LANMAN1",  reply_lanman1,  PROTOCOL_LANMAN1},
2744   {"MICROSOFT NETWORKS 1.03", "COREPLUS", reply_coreplus, PROTOCOL_COREPLUS},
2745   {"PC NETWORK PROGRAM 1.0",  "CORE",     reply_corep,    PROTOCOL_CORE}, 
2746   {NULL,NULL},
2747 };
2748
2749
2750 /****************************************************************************
2751   reply to a negprot
2752 ****************************************************************************/
2753 static int reply_negprot(char *inbuf,char *outbuf)
2754 {
2755   extern fstring remote_arch;
2756   int outsize = set_message(outbuf,1,0,True);
2757   int Index=0;
2758   int choice= -1;
2759   int protocol;
2760   char *p;
2761   int bcc = SVAL(smb_buf(inbuf),-2);
2762   int arch = ARCH_ALL;
2763
2764   p = smb_buf(inbuf)+1;
2765   while (p < (smb_buf(inbuf) + bcc))
2766     { 
2767       Index++;
2768       DEBUG(3,("Requested protocol [%s]\n",p));
2769       if (strcsequal(p,"Windows for Workgroups 3.1a"))
2770         arch &= ( ARCH_WFWG | ARCH_WIN95 | ARCH_WINNT );
2771       else if (strcsequal(p,"DOS LM1.2X002"))
2772         arch &= ( ARCH_WFWG | ARCH_WIN95 );
2773       else if (strcsequal(p,"DOS LANMAN2.1"))
2774         arch &= ( ARCH_WFWG | ARCH_WIN95 );
2775       else if (strcsequal(p,"NT LM 0.12"))
2776         arch &= ( ARCH_WIN95 | ARCH_WINNT );
2777       else if (strcsequal(p,"LANMAN2.1"))
2778         arch &= ( ARCH_WINNT | ARCH_OS2 );
2779       else if (strcsequal(p,"LM1.2X002"))
2780         arch &= ( ARCH_WINNT | ARCH_OS2 );
2781       else if (strcsequal(p,"MICROSOFT NETWORKS 1.03"))
2782         arch &= ARCH_WINNT;
2783       else if (strcsequal(p,"XENIX CORE"))
2784         arch &= ( ARCH_WINNT | ARCH_OS2 );
2785       else if (strcsequal(p,"Samba")) {
2786         arch = ARCH_SAMBA;
2787         break;
2788       }
2789  
2790       p += strlen(p) + 2;
2791     }
2792     
2793   switch ( arch ) {
2794   case ARCH_SAMBA:
2795     strcpy(remote_arch,"Samba");
2796     break;
2797   case ARCH_WFWG:
2798     strcpy(remote_arch,"WfWg");
2799     break;
2800   case ARCH_WIN95:
2801     strcpy(remote_arch,"Win95");
2802     break;
2803   case ARCH_WINNT:
2804     strcpy(remote_arch,"WinNT");
2805     break;
2806   case ARCH_OS2:
2807     strcpy(remote_arch,"OS2");
2808     break;
2809   default:
2810     strcpy(remote_arch,"UNKNOWN");
2811     break;
2812   }
2813  
2814   /* possibly reload - change of architecture */
2815   reload_services(True);      
2816     
2817   /* a special case to stop password server loops */
2818   if (Index == 1 && strequal(remote_machine,myhostname) && 
2819       lp_security()==SEC_SERVER)
2820     exit_server("Password server loop!");
2821   
2822   /* Check for protocols, most desirable first */
2823   for (protocol = 0; supported_protocols[protocol].proto_name; protocol++)
2824     {
2825       p = smb_buf(inbuf)+1;
2826       Index = 0;
2827       if (lp_maxprotocol() >= supported_protocols[protocol].protocol_level)
2828         while (p < (smb_buf(inbuf) + bcc))
2829           { 
2830             if (strequal(p,supported_protocols[protocol].proto_name))
2831               choice = Index;
2832             Index++;
2833             p += strlen(p) + 2;
2834           }
2835       if(choice != -1)
2836         break;
2837     }
2838   
2839   SSVAL(outbuf,smb_vwv0,choice);
2840   if(choice != -1) {
2841     extern fstring remote_proto;
2842     strcpy(remote_proto,supported_protocols[protocol].short_name);
2843     reload_services(True);          
2844     outsize = supported_protocols[protocol].proto_reply_fn(outbuf);
2845     DEBUG(3,("Selected protocol %s\n",supported_protocols[protocol].proto_name));
2846   }
2847   else {
2848     DEBUG(0,("No protocol supported !\n"));
2849   }
2850   SSVAL(outbuf,smb_vwv0,choice);
2851   
2852   DEBUG(5,("%s negprot index=%d\n",timestring(),choice));
2853
2854   return(outsize);
2855 }
2856
2857
2858 /****************************************************************************
2859   parse a connect packet
2860 ****************************************************************************/
2861 void parse_connect(char *buf,char *service,char *user,char *password,int *pwlen,char *dev)
2862 {
2863   char *p = smb_buf(buf) + 1;
2864   char *p2;
2865
2866   DEBUG(4,("parsing connect string %s\n",p));
2867     
2868   p2 = strrchr(p,'\\');
2869   if (p2 == NULL)
2870     strcpy(service,p);
2871   else
2872     strcpy(service,p2+1);
2873   
2874   p += strlen(p) + 2;
2875   
2876   strcpy(password,p);
2877   *pwlen = strlen(password);
2878
2879   p += strlen(p) + 2;
2880
2881   strcpy(dev,p);
2882   
2883   *user = 0;
2884   p = strchr(service,'%');
2885   if (p != NULL)
2886     {
2887       *p = 0;
2888       strcpy(user,p+1);
2889     }
2890 }
2891
2892
2893 /****************************************************************************
2894 close all open files for a connection
2895 ****************************************************************************/
2896 static void close_open_files(int cnum)
2897 {
2898   int i;
2899   for (i=0;i<MAX_OPEN_FILES;i++)
2900     if( Files[i].cnum == cnum && Files[i].open) {
2901       close_file(i);
2902     }
2903 }
2904
2905
2906
2907 /****************************************************************************
2908 close a cnum
2909 ****************************************************************************/
2910 void close_cnum(int cnum, int uid)
2911 {
2912   extern struct from_host Client_info;
2913
2914   DirCacheFlush(SNUM(cnum));
2915
2916   unbecome_user();
2917
2918   if (!OPEN_CNUM(cnum))
2919     {
2920       DEBUG(0,("Can't close cnum %d\n",cnum));
2921       return;
2922     }
2923
2924   DEBUG(IS_IPC(cnum)?3:1,("%s %s (%s) closed connection to service %s\n",
2925                           timestring(),
2926                           Client_info.name,Client_info.addr,
2927                           lp_servicename(SNUM(cnum))));
2928
2929   yield_connection(cnum,
2930                    lp_servicename(SNUM(cnum)),
2931                    lp_max_connections(SNUM(cnum)));
2932
2933   if (lp_status(SNUM(cnum)))
2934     yield_connection(cnum,"STATUS.",MAXSTATUS);
2935
2936   close_open_files(cnum);
2937   dptr_closecnum(cnum);
2938
2939   /* execute any "postexec = " line */
2940   if (*lp_postexec(SNUM(cnum)) && become_user(cnum,uid))
2941     {
2942       pstring cmd;
2943       strcpy(cmd,lp_postexec(SNUM(cnum)));
2944       standard_sub(cnum,cmd);
2945       smbrun(cmd,NULL);
2946       unbecome_user();
2947     }
2948
2949   unbecome_user();
2950   /* execute any "root postexec = " line */
2951   if (*lp_rootpostexec(SNUM(cnum)))
2952     {
2953       pstring cmd;
2954       strcpy(cmd,lp_rootpostexec(SNUM(cnum)));
2955       standard_sub(cnum,cmd);
2956       smbrun(cmd,NULL);
2957     }
2958
2959   Connections[cnum].open = False;
2960   num_connections_open--;
2961   if (Connections[cnum].ngroups && Connections[cnum].groups)
2962     {
2963       if (Connections[cnum].igroups != (int *)Connections[cnum].groups)
2964         free(Connections[cnum].groups);
2965       free(Connections[cnum].igroups);
2966       Connections[cnum].groups = NULL;
2967       Connections[cnum].igroups = NULL;
2968       Connections[cnum].ngroups = 0;
2969     }
2970
2971   string_set(&Connections[cnum].user,"");
2972   string_set(&Connections[cnum].dirpath,"");
2973   string_set(&Connections[cnum].connectpath,"");
2974 }
2975
2976
2977 /****************************************************************************
2978 simple routines to do connection counting
2979 ****************************************************************************/
2980 BOOL yield_connection(int cnum,char *name,int max_connections)
2981 {
2982   struct connect_record crec;
2983   pstring fname;
2984   FILE *f;
2985   int mypid = getpid();
2986   int i;
2987
2988   DEBUG(3,("Yielding connection to %d %s\n",cnum,name));
2989
2990   if (max_connections <= 0)
2991     return(True);
2992
2993   bzero(&crec,sizeof(crec));
2994
2995   strcpy(fname,lp_lockdir());
2996   standard_sub(cnum,fname);
2997   trim_string(fname,"","/");
2998
2999   strcat(fname,"/");
3000   strcat(fname,name);
3001   strcat(fname,".LCK");
3002
3003   f = fopen(fname,"r+");
3004   if (!f)
3005     {
3006       DEBUG(2,("Coudn't open lock file %s (%s)\n",fname,strerror(errno)));
3007       return(False);
3008     }
3009
3010   fseek(f,0,SEEK_SET);
3011
3012   /* find a free spot */
3013   for (i=0;i<max_connections;i++)
3014     {
3015       if (fread(&crec,sizeof(crec),1,f) != 1)
3016         {
3017           DEBUG(2,("Entry not found in lock file %s\n",fname));
3018           fclose(f);
3019           return(False);
3020         }
3021       if (crec.pid == mypid && crec.cnum == cnum)
3022         break;
3023     }
3024
3025   if (crec.pid != mypid || crec.cnum != cnum)
3026     {
3027       fclose(f);
3028       DEBUG(2,("Entry not found in lock file %s\n",fname));
3029       return(False);
3030     }
3031
3032   bzero((void *)&crec,sizeof(crec));
3033   
3034   /* remove our mark */
3035   if (fseek(f,i*sizeof(crec),SEEK_SET) != 0 ||
3036       fwrite(&crec,sizeof(crec),1,f) != 1)
3037     {
3038       DEBUG(2,("Couldn't update lock file %s (%s)\n",fname,strerror(errno)));
3039       fclose(f);
3040       return(False);
3041     }
3042
3043   DEBUG(3,("Yield successful\n"));
3044
3045   fclose(f);
3046   return(True);
3047 }
3048
3049
3050 /****************************************************************************
3051 simple routines to do connection counting
3052 ****************************************************************************/
3053 BOOL claim_connection(int cnum,char *name,int max_connections,BOOL Clear)
3054 {
3055   struct connect_record crec;
3056   pstring fname;
3057   FILE *f;
3058   int snum = SNUM(cnum);
3059   int i,foundi= -1;
3060   int total_recs;
3061
3062   if (max_connections <= 0)
3063     return(True);
3064
3065   DEBUG(5,("trying claim %s %s %d\n",lp_lockdir(),name,max_connections));
3066
3067   strcpy(fname,lp_lockdir());
3068   standard_sub(cnum,fname);
3069   trim_string(fname,"","/");
3070
3071   if (!directory_exist(fname,NULL))
3072     mkdir(fname,0755);
3073
3074   strcat(fname,"/");
3075   strcat(fname,name);
3076   strcat(fname,".LCK");
3077
3078   if (!file_exist(fname,NULL))
3079     {
3080       f = fopen(fname,"w");
3081       if (f) fclose(f);
3082     }
3083
3084   total_recs = file_size(fname) / sizeof(crec);
3085
3086   f = fopen(fname,"r+");
3087
3088   if (!f)
3089     {
3090       DEBUG(1,("couldn't open lock file %s\n",fname));
3091       return(False);
3092     }
3093
3094   /* find a free spot */
3095   for (i=0;i<max_connections;i++)
3096     {
3097
3098       if (i>=total_recs || 
3099           fseek(f,i*sizeof(crec),SEEK_SET) != 0 ||
3100           fread(&crec,sizeof(crec),1,f) != 1)
3101         {
3102           if (foundi < 0) foundi = i;
3103           break;
3104         }
3105
3106       if (Clear && crec.pid && !process_exists(crec.pid))
3107         {
3108           fseek(f,i*sizeof(crec),SEEK_SET);
3109           bzero((void *)&crec,sizeof(crec));
3110           fwrite(&crec,sizeof(crec),1,f);
3111           if (foundi < 0) foundi = i;
3112           continue;
3113         }
3114       if (foundi < 0 && (!crec.pid || !process_exists(crec.pid)))
3115         {
3116           foundi=i;
3117           if (!Clear) break;
3118         }
3119     }  
3120
3121   if (foundi < 0)
3122     {
3123       DEBUG(3,("no free locks in %s\n",fname));
3124       fclose(f);
3125       return(False);
3126     }      
3127
3128   /* fill in the crec */
3129   bzero((void *)&crec,sizeof(crec));
3130   crec.magic = 0x280267;
3131   crec.pid = getpid();
3132   crec.cnum = cnum;
3133   crec.uid = Connections[cnum].uid;
3134   crec.gid = Connections[cnum].gid;
3135   StrnCpy(crec.name,lp_servicename(snum),sizeof(crec.name)-1);
3136   crec.start = time(NULL);
3137
3138   {
3139     extern struct from_host Client_info;
3140     StrnCpy(crec.machine,Client_info.name,sizeof(crec.machine)-1);
3141     StrnCpy(crec.addr,Client_info.addr,sizeof(crec.addr)-1);
3142   }
3143   
3144   /* make our mark */
3145   if (fseek(f,foundi*sizeof(crec),SEEK_SET) != 0 ||
3146       fwrite(&crec,sizeof(crec),1,f) != 1)
3147     {
3148       fclose(f);
3149       return(False);
3150     }
3151
3152   fclose(f);
3153   return(True);
3154 }
3155
3156 #if DUMP_CORE
3157 /*******************************************************************
3158 prepare to dump a core file - carefully!
3159 ********************************************************************/
3160 static BOOL dump_core(void)
3161 {
3162   char *p;
3163   pstring dname;
3164   strcpy(dname,debugf);
3165   if ((p=strrchr(dname,'/'))) *p=0;
3166   strcat(dname,"/corefiles");
3167   mkdir(dname,0700);
3168   sys_chown(dname,getuid(),getgid());
3169   chmod(dname,0700);
3170   if (chdir(dname)) return(False);
3171   umask(~(0700));
3172
3173 #ifndef NO_GETRLIMIT
3174 #ifdef RLIMIT_CORE
3175   {
3176     struct rlimit rlp;
3177     getrlimit(RLIMIT_CORE, &rlp);
3178     rlp.rlim_cur = MAX(4*1024*1024,rlp.rlim_cur);
3179     setrlimit(RLIMIT_CORE, &rlp);
3180     getrlimit(RLIMIT_CORE, &rlp);
3181     DEBUG(3,("Core limits now %d %d\n",rlp.rlim_cur,rlp.rlim_max));
3182   }
3183 #endif
3184 #endif
3185
3186
3187   DEBUG(0,("Dumping core in %s\n",dname));
3188   return(True);
3189 }
3190 #endif
3191
3192 /****************************************************************************
3193 exit the server
3194 ****************************************************************************/
3195 void exit_server(char *reason)
3196 {
3197   static int firsttime=1;
3198   int i;
3199
3200   if (!firsttime) exit(0);
3201   firsttime = 0;
3202
3203   unbecome_user();
3204   DEBUG(2,("Closing connections\n"));
3205   for (i=0;i<MAX_CONNECTIONS;i++)
3206     if (Connections[i].open)
3207       close_cnum(i,-1);
3208 #ifdef DFS_AUTH
3209   if (dcelogin_atmost_once)
3210     dfs_unlogin();
3211 #endif
3212   if (!reason) {   
3213     int oldlevel = DEBUGLEVEL;
3214     DEBUGLEVEL = 10;
3215     DEBUG(0,("Last message was %s\n",smb_fn_name(last_message)));
3216     if (last_inbuf)
3217       show_msg(last_inbuf);
3218     DEBUGLEVEL = oldlevel;
3219     DEBUG(0,("===============================================================\n"));
3220 #if DUMP_CORE
3221     if (dump_core()) return;
3222 #endif
3223   }    
3224   DEBUG(3,("%s Server exit  (%s)\n",timestring(),reason?reason:""));
3225   exit(0);
3226 }
3227
3228 /****************************************************************************
3229 do some standard substitutions in a string
3230 ****************************************************************************/
3231 void standard_sub(int cnum,char *s)
3232 {
3233   if (!strchr(s,'%')) return;
3234
3235   if (VALID_CNUM(cnum))
3236     {
3237       string_sub(s,"%S",lp_servicename(Connections[cnum].service));
3238       string_sub(s,"%P",Connections[cnum].connectpath);
3239       string_sub(s,"%u",Connections[cnum].user);
3240       if (strstr(s,"%H")) {
3241         char *home = get_home_dir(Connections[cnum].user);
3242         if (home) string_sub(s,"%H",home);
3243       }
3244       string_sub(s,"%g",gidtoname(Connections[cnum].gid));
3245     }
3246   standard_sub_basic(s);
3247 }
3248
3249 /*
3250 These flags determine some of the permissions required to do an operation 
3251
3252 Note that I don't set NEED_WRITE on some write operations because they
3253 are used by some brain-dead clients when printing, and I don't want to
3254 force write permissions on print services.
3255 */
3256 #define AS_USER (1<<0)
3257 #define NEED_WRITE (1<<1)
3258 #define TIME_INIT (1<<2)
3259 #define CAN_IPC (1<<3)
3260 #define AS_GUEST (1<<5)
3261
3262
3263 /* 
3264    define a list of possible SMB messages and their corresponding
3265    functions. Any message that has a NULL function is unimplemented -
3266    please feel free to contribute implementations!
3267 */
3268 struct smb_message_struct
3269 {
3270   int code;
3271   char *name;
3272   int (*fn)();
3273   int flags;
3274 #if PROFILING
3275   unsigned long time;
3276 #endif
3277 }
3278  smb_messages[] = {
3279
3280     /* CORE PROTOCOL */
3281
3282    {SMBnegprot,"SMBnegprot",reply_negprot,0},
3283    {SMBtcon,"SMBtcon",reply_tcon,0},
3284    {SMBtdis,"SMBtdis",reply_tdis,0},
3285    {SMBexit,"SMBexit",reply_exit,0},
3286    {SMBioctl,"SMBioctl",reply_ioctl,0},
3287    {SMBecho,"SMBecho",reply_echo,0},
3288    {SMBsesssetupX,"SMBsesssetupX",reply_sesssetup_and_X,0},
3289    {SMBtconX,"SMBtconX",reply_tcon_and_X,0},
3290    {SMBulogoffX, "SMBulogoffX", reply_ulogoffX, 0}, 
3291    {SMBgetatr,"SMBgetatr",reply_getatr,AS_USER},
3292    {SMBsetatr,"SMBsetatr",reply_setatr,AS_USER | NEED_WRITE},
3293    {SMBchkpth,"SMBchkpth",reply_chkpth,AS_USER},
3294    {SMBsearch,"SMBsearch",reply_search,AS_USER},
3295    {SMBopen,"SMBopen",reply_open,AS_USER},
3296
3297    /* note that SMBmknew and SMBcreate are deliberately overloaded */   
3298    {SMBcreate,"SMBcreate",reply_mknew,AS_USER},
3299    {SMBmknew,"SMBmknew",reply_mknew,AS_USER}, 
3300
3301    {SMBunlink,"SMBunlink",reply_unlink,AS_USER | NEED_WRITE},
3302    {SMBread,"SMBread",reply_read,AS_USER},
3303    {SMBwrite,"SMBwrite",reply_write,AS_USER},
3304    {SMBclose,"SMBclose",reply_close,AS_USER},
3305    {SMBmkdir,"SMBmkdir",reply_mkdir,AS_USER | NEED_WRITE},
3306    {SMBrmdir,"SMBrmdir",reply_rmdir,AS_USER | NEED_WRITE},
3307    {SMBdskattr,"SMBdskattr",reply_dskattr,AS_USER},
3308    {SMBmv,"SMBmv",reply_mv,AS_USER | NEED_WRITE},
3309
3310    /* this is a Pathworks specific call, allowing the 
3311       changing of the root path */
3312    {pSETDIR,"pSETDIR",reply_setdir,AS_USER}, 
3313
3314    {SMBlseek,"SMBlseek",reply_lseek,AS_USER},
3315    {SMBflush,"SMBflush",reply_flush,AS_USER},
3316    {SMBctemp,"SMBctemp",reply_ctemp,AS_USER},
3317    {SMBsplopen,"SMBsplopen",reply_printopen,AS_USER},
3318    {SMBsplclose,"SMBsplclose",reply_printclose,AS_USER},
3319    {SMBsplretq,"SMBsplretq",reply_printqueue,AS_USER},
3320    {SMBsplwr,"SMBsplwr",reply_printwrite,AS_USER},
3321    {SMBlock,"SMBlock",reply_lock,AS_USER},
3322    {SMBunlock,"SMBunlock",reply_unlock,AS_USER},
3323    
3324    /* CORE+ PROTOCOL FOLLOWS */
3325    
3326    {SMBreadbraw,"SMBreadbraw",reply_readbraw,AS_USER},
3327    {SMBwritebraw,"SMBwritebraw",reply_writebraw,AS_USER},
3328    {SMBwriteclose,"SMBwriteclose",reply_writeclose,AS_USER},
3329    {SMBlockread,"SMBlockread",reply_lockread,AS_USER},
3330    {SMBwriteunlock,"SMBwriteunlock",reply_writeunlock,AS_USER},
3331    
3332    /* LANMAN1.0 PROTOCOL FOLLOWS */
3333    
3334    {SMBreadBmpx,"SMBreadBmpx",reply_readbmpx,AS_USER},
3335    {SMBreadBs,"SMBreadBs",NULL,AS_USER},
3336    {SMBwriteBmpx,"SMBwriteBmpx",reply_writebmpx,AS_USER},
3337    {SMBwriteBs,"SMBwriteBs",reply_writebs,AS_USER},
3338    {SMBwritec,"SMBwritec",NULL,AS_USER},
3339    {SMBsetattrE,"SMBsetattrE",reply_setattrE,AS_USER | NEED_WRITE},
3340    {SMBgetattrE,"SMBgetattrE",reply_getattrE,AS_USER},
3341    {SMBtrans,"SMBtrans",reply_trans,AS_USER | CAN_IPC},
3342    {SMBtranss,"SMBtranss",NULL,AS_USER | CAN_IPC},
3343    {SMBioctls,"SMBioctls",NULL,AS_USER},
3344    {SMBcopy,"SMBcopy",reply_copy,AS_USER | NEED_WRITE},
3345    {SMBmove,"SMBmove",NULL,AS_USER | NEED_WRITE},
3346    
3347    {SMBopenX,"SMBopenX",reply_open_and_X,AS_USER},
3348    {SMBreadX,"SMBreadX",reply_read_and_X,AS_USER},
3349    {SMBwriteX,"SMBwriteX",reply_write_and_X,AS_USER},
3350    {SMBlockingX,"SMBlockingX",reply_lockingX,AS_USER},
3351    
3352    {SMBffirst,"SMBffirst",reply_search,AS_USER},
3353    {SMBfunique,"SMBfunique",reply_search,AS_USER},
3354    {SMBfclose,"SMBfclose",reply_fclose,AS_USER},
3355
3356    /* LANMAN2.0 PROTOCOL FOLLOWS */
3357    {SMBfindnclose, "SMBfindnclose", reply_findnclose, AS_USER},
3358    {SMBfindclose, "SMBfindclose", reply_findclose,AS_USER},
3359    {SMBtrans2, "SMBtrans2", reply_trans2, AS_USER},
3360    {SMBtranss2, "SMBtranss2", reply_transs2, AS_USER},
3361
3362    /* messaging routines */
3363    {SMBsends,"SMBsends",reply_sends,AS_GUEST},
3364    {SMBsendstrt,"SMBsendstrt",reply_sendstrt,AS_GUEST},
3365    {SMBsendend,"SMBsendend",reply_sendend,AS_GUEST},
3366    {SMBsendtxt,"SMBsendtxt",reply_sendtxt,AS_GUEST},
3367
3368    /* NON-IMPLEMENTED PARTS OF THE CORE PROTOCOL */
3369    
3370    {SMBsendb,"SMBsendb",NULL,AS_GUEST},
3371    {SMBfwdname,"SMBfwdname",NULL,AS_GUEST},
3372    {SMBcancelf,"SMBcancelf",NULL,AS_GUEST},
3373    {SMBgetmac,"SMBgetmac",NULL,AS_GUEST}
3374  };
3375
3376 /****************************************************************************
3377 return a string containing the function name of a SMB command
3378 ****************************************************************************/
3379 char *smb_fn_name(int type)
3380 {
3381   static char *unknown_name = "SMBunknown";
3382   static int num_smb_messages = 
3383     sizeof(smb_messages) / sizeof(struct smb_message_struct);
3384   int match;
3385
3386   for (match=0;match<num_smb_messages;match++)
3387     if (smb_messages[match].code == type)
3388       break;
3389
3390   if (match == num_smb_messages)
3391     return(unknown_name);
3392
3393   return(smb_messages[match].name);
3394 }
3395
3396
3397 /****************************************************************************
3398 do a switch on the message type, and return the response size
3399 ****************************************************************************/
3400 static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize)
3401 {
3402   static int pid= -1;
3403   int outsize = 0;
3404   static int num_smb_messages = 
3405     sizeof(smb_messages) / sizeof(struct smb_message_struct);
3406   int match;
3407
3408 #if PROFILING
3409   struct timeval msg_start_time;
3410   struct timeval msg_end_time;
3411   static unsigned long total_time = 0;
3412
3413   GetTimeOfDay(&msg_start_time);
3414 #endif
3415
3416   if (pid == -1)
3417     pid = getpid();
3418
3419   errno = 0;
3420   last_message = type;
3421
3422   /* make sure this is an SMB packet */
3423   if (strncmp(smb_base(inbuf),"\377SMB",4) != 0)
3424     {
3425       DEBUG(2,("Non-SMB packet of length %d\n",smb_len(inbuf)));
3426       return(-1);
3427     }
3428
3429   for (match=0;match<num_smb_messages;match++)
3430     if (smb_messages[match].code == type)
3431       break;
3432
3433   if (match == num_smb_messages)
3434     {
3435       DEBUG(0,("Unknown message type %d!\n",type));
3436       outsize = reply_unknown(inbuf,outbuf);
3437     }
3438   else
3439     {
3440       DEBUG(3,("switch message %s (pid %d)\n",smb_messages[match].name,pid));
3441       if (smb_messages[match].fn)
3442         {
3443           int cnum = SVAL(inbuf,smb_tid);
3444           int flags = smb_messages[match].flags;
3445           int uid = SVAL(inbuf,smb_uid);
3446
3447           /* does this protocol need to be run as root? */
3448           if (!(flags & AS_USER))
3449             unbecome_user();
3450
3451           /* does this protocol need to be run as the connected user? */
3452           if ((flags & AS_USER) && !become_user(cnum,uid))
3453             return(ERROR(ERRSRV,ERRinvnid));
3454
3455           /* does it need write permission? */
3456           if ((flags & NEED_WRITE) && !CAN_WRITE(cnum))
3457             return(ERROR(ERRSRV,ERRaccess));
3458
3459           /* ipc services are limited */
3460           if (IS_IPC(cnum) && (flags & AS_USER) && !(flags & CAN_IPC))
3461             return(ERROR(ERRSRV,ERRaccess));        
3462
3463           /* load service specific parameters */
3464           if (OPEN_CNUM(cnum) && !become_service(cnum,(flags & AS_USER)?True:False))
3465             return(ERROR(ERRSRV,ERRaccess));
3466
3467           /* does this protocol need to be run as guest? */
3468           if ((flags & AS_GUEST) && (!become_guest() || !check_access(-1)))
3469             return(ERROR(ERRSRV,ERRaccess));
3470
3471           last_inbuf = inbuf;
3472
3473           outsize = smb_messages[match].fn(inbuf,outbuf,size,bufsize);
3474         }
3475       else
3476         {
3477           outsize = reply_unknown(inbuf,outbuf);
3478         }
3479     }
3480
3481 #if PROFILING
3482   GetTimeOfDay(&msg_end_time);
3483   if (!(smb_messages[match].flags & TIME_INIT))
3484     {
3485       smb_messages[match].time = 0;
3486       smb_messages[match].flags |= TIME_INIT;
3487     }
3488   {
3489     unsigned long this_time =     
3490       (msg_end_time.tv_sec - msg_start_time.tv_sec)*1e6 +
3491         (msg_end_time.tv_usec - msg_start_time.tv_usec);
3492     smb_messages[match].time += this_time;
3493     total_time += this_time;
3494   }
3495   DEBUG(2,("TIME %s  %d usecs   %g pct\n",
3496            smb_fn_name(type),smb_messages[match].time,
3497         (100.0*smb_messages[match].time) / total_time));
3498 #endif
3499
3500   return(outsize);
3501 }
3502
3503
3504 /****************************************************************************
3505 construct a chained reply and add it to the already made reply
3506
3507 inbuf points to the original message start.
3508 inbuf2 points to the smb_wct part of the secondary message
3509 type is the type of the secondary message
3510 outbuf points to the original outbuffer
3511 outbuf2 points to the smb_wct field of the new outbuffer
3512 size is the total length of the incoming message (from inbuf1)
3513 bufsize is the total buffer size
3514
3515 return how many bytes were added to the response
3516 ****************************************************************************/
3517 int chain_reply(int type,char *inbuf,char *inbuf2,char *outbuf,char *outbuf2,int size,int bufsize)
3518 {
3519   int outsize = 0;
3520   char *ibuf,*obuf;
3521   static BOOL in_chain = False;
3522   static char *last_outbuf=NULL;
3523   BOOL was_inchain = in_chain;
3524   int insize_remaining;
3525   static int insize_deleted;
3526  
3527
3528   chain_size += PTR_DIFF(outbuf2,outbuf) - smb_wct;
3529   if (was_inchain)
3530     outbuf = last_outbuf;
3531   else
3532     insize_deleted = 0;
3533
3534
3535   insize_deleted = 0;
3536   inbuf2 -= insize_deleted;
3537   insize_remaining = size - PTR_DIFF(inbuf2,inbuf);
3538   insize_deleted += size - (insize_remaining + smb_wct);
3539
3540   in_chain = True;
3541   last_outbuf = outbuf;
3542
3543
3544   /* allocate some space for the in and out buffers of the chained message */
3545   ibuf = (char *)malloc(size + SAFETY_MARGIN);
3546   obuf = (char *)malloc(bufsize + SAFETY_MARGIN);
3547
3548   if (!ibuf || !obuf)
3549     {
3550       DEBUG(0,("Out of memory in chain reply\n"));
3551       return(ERROR(ERRSRV,ERRnoresource));
3552     }
3553
3554   ibuf += SMB_ALIGNMENT;
3555   obuf += SMB_ALIGNMENT;
3556
3557   /* create the in buffer */
3558   memcpy(ibuf,inbuf,smb_wct);
3559   memcpy(ibuf+smb_wct,inbuf2,insize_remaining);
3560   CVAL(ibuf,smb_com) = type;
3561
3562   /* create the out buffer */
3563   bzero(obuf,smb_size);
3564
3565   set_message(obuf,0,0,True);
3566   CVAL(obuf,smb_com) = CVAL(ibuf,smb_com);
3567   
3568   memcpy(obuf+4,ibuf+4,4);
3569   CVAL(obuf,smb_rcls) = SUCCESS;
3570   CVAL(obuf,smb_reh) = 0;
3571   CVAL(obuf,smb_flg) = 0x80 | (CVAL(ibuf,smb_flg) & 0x8); /* bit 7 set 
3572                                                              means a reply */
3573   SSVAL(obuf,smb_flg2,1); /* say we support long filenames */
3574   SSVAL(obuf,smb_err,SUCCESS);
3575   SSVAL(obuf,smb_tid,SVAL(inbuf,smb_tid));
3576   SSVAL(obuf,smb_pid,SVAL(inbuf,smb_pid));
3577   SSVAL(obuf,smb_uid,SVAL(inbuf,smb_uid));
3578   SSVAL(obuf,smb_mid,SVAL(inbuf,smb_mid));
3579
3580   DEBUG(3,("Chained message\n"));
3581   show_msg(ibuf);
3582
3583   /* process the request */
3584   outsize = switch_message(type,ibuf,obuf,smb_wct+insize_remaining,
3585                            bufsize-chain_size);
3586
3587   /* copy the new reply header over the old one, but preserve 
3588      the smb_com field */
3589   memcpy(outbuf+smb_com+1,obuf+smb_com+1,smb_wct-(smb_com+1));
3590
3591   /* and copy the data from the reply to the right spot */
3592   memcpy(outbuf2,obuf+smb_wct,outsize - smb_wct);
3593
3594   /* free the allocated buffers */
3595   if (ibuf) free(ibuf-SMB_ALIGNMENT);
3596   if (obuf) free(obuf-SMB_ALIGNMENT);
3597
3598   in_chain = was_inchain;
3599
3600   /* return how much extra has been added to the packet */
3601   return(outsize - smb_wct);
3602 }
3603
3604
3605
3606 /****************************************************************************
3607   construct a reply to the incoming packet
3608 ****************************************************************************/
3609 int construct_reply(char *inbuf,char *outbuf,int size,int bufsize)
3610 {
3611   int type = CVAL(inbuf,smb_com);
3612   int outsize = 0;
3613   int msg_type = CVAL(inbuf,0);
3614
3615   smb_last_time = time(NULL);
3616
3617   chain_size = 0;
3618
3619   bzero(outbuf,smb_size);
3620
3621   if (msg_type != 0)
3622     return(reply_special(inbuf,outbuf));  
3623
3624   CVAL(outbuf,smb_com) = CVAL(inbuf,smb_com);
3625   set_message(outbuf,0,0,True);
3626   
3627   memcpy(outbuf+4,inbuf+4,4);
3628   CVAL(outbuf,smb_rcls) = SUCCESS;
3629   CVAL(outbuf,smb_reh) = 0;
3630   CVAL(outbuf,smb_flg) = 0x80 | (CVAL(inbuf,smb_flg) & 0x8); /* bit 7 set 
3631                                                              means a reply */
3632   SSVAL(outbuf,smb_flg2,1); /* say we support long filenames */
3633   SSVAL(outbuf,smb_err,SUCCESS);
3634   SSVAL(outbuf,smb_tid,SVAL(inbuf,smb_tid));
3635   SSVAL(outbuf,smb_pid,SVAL(inbuf,smb_pid));
3636   SSVAL(outbuf,smb_uid,SVAL(inbuf,smb_uid));
3637   SSVAL(outbuf,smb_mid,SVAL(inbuf,smb_mid));
3638
3639   outsize = switch_message(type,inbuf,outbuf,size,bufsize);
3640
3641   if(outsize > 4)
3642     smb_setlen(outbuf,outsize - 4);
3643   return(outsize);
3644 }
3645
3646
3647 /****************************************************************************
3648   process commands from the client
3649 ****************************************************************************/
3650 void process(void )
3651 {
3652   static int trans_num = 0;
3653   int nread;
3654   extern struct from_host Client_info;
3655   extern int Client;
3656
3657   fromhost(Client,&Client_info);
3658   
3659   InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3660   OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
3661   if ((InBuffer == NULL) || (OutBuffer == NULL)) 
3662     return;
3663
3664   InBuffer += SMB_ALIGNMENT;
3665   OutBuffer += SMB_ALIGNMENT;
3666
3667 #if PRIME_NMBD
3668   DEBUG(3,("priming nmbd\n"));
3669   {
3670     struct in_addr ip;
3671     ip = *interpret_addr2("localhost");
3672     if (zero_ip(ip)) ip = *interpret_addr2("127.0.0.1");
3673     *OutBuffer = 0;
3674     send_one_packet(OutBuffer,1,ip,137,SOCK_DGRAM);
3675   }
3676 #endif    
3677
3678   last_user.cnum = -1;
3679   
3680   while (True)
3681     {
3682       int32 len;      
3683       int msg_type;
3684       int msg_flags;
3685       int type;
3686       int deadtime = lp_deadtime()*60;
3687       int counter;
3688       int last_keepalive=0;
3689
3690       if (deadtime <= 0)
3691         deadtime = DEFAULT_SMBD_TIMEOUT;
3692
3693       if (lp_readprediction())
3694         do_read_prediction();
3695
3696       {
3697         extern pstring share_del_pending;
3698         if (*share_del_pending) {
3699           unbecome_user();
3700           if (!unlink(share_del_pending))
3701             DEBUG(3,("Share file deleted %s\n",share_del_pending));
3702           else
3703             DEBUG(2,("Share del failed of %s\n",share_del_pending));
3704           share_del_pending[0] = 0;
3705         }
3706       }
3707
3708       if (share_mode_pending) {
3709         unbecome_user();
3710         check_share_modes();
3711         share_mode_pending=False;
3712       }
3713
3714       errno = 0;      
3715
3716       for (counter=SMBD_SELECT_LOOP; 
3717            !receive_smb(Client,InBuffer,SMBD_SELECT_LOOP*1000); 
3718            counter += SMBD_SELECT_LOOP)
3719         {
3720           int i;
3721           time_t t;
3722           BOOL allidle = True;
3723           extern int keepalive;
3724
3725           /* check for socket failure */
3726           if (errno) {
3727             DEBUG(3,("receive_smb error (%s) exiting\n",strerror(errno)));
3728             return;
3729           }
3730
3731           t = time(NULL);
3732
3733           /* become root again if waiting */
3734           unbecome_user();
3735
3736           /* check for smb.conf reload */
3737           if (!(counter%SMBD_RELOAD_CHECK))
3738             reload_services(True);
3739
3740           /* check the share modes every 10 secs */
3741           if (!(counter%SHARE_MODES_CHECK))
3742             check_share_modes();
3743
3744           /* clean the share modes every 5 minutes */
3745           if (!(counter%SHARE_MODES_CLEAN))
3746             clean_share_files();
3747
3748           /* automatic timeout if all connections are closed */      
3749           if (num_connections_open==0 && counter >= IDLE_CLOSED_TIMEOUT) {
3750             DEBUG(2,("%s Closing idle connection\n",timestring()));
3751             return;
3752           }
3753
3754           if (keepalive && (counter-last_keepalive)>keepalive) {
3755             extern int password_client;
3756             if (!send_keepalive(Client)) {
3757               DEBUG(2,("%s Keepalive failed - exiting\n",timestring()));
3758               return;
3759             }       
3760             /* also send a keepalive to the password server if its still
3761                connected */
3762             if (password_client != -1)
3763               send_keepalive(password_client);
3764             last_keepalive = counter;
3765           }
3766
3767           /* check for connection timeouts */
3768           for (i=0;i<MAX_CONNECTIONS;i++)
3769             if (Connections[i].open)
3770               {
3771                 /* close dirptrs on connections that are idle */
3772                 if ((t-Connections[i].lastused)>DPTR_IDLE_TIMEOUT)
3773                   dptr_idlecnum(i);
3774
3775                 if (Connections[i].num_files_open > 0 ||
3776                     (t-Connections[i].lastused)<deadtime)
3777                   allidle = False;
3778            &n