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