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