charcnv.c: Fixed silly bugs detected on IRIX.
[kai/samba.git] / source3 / smbd / server.c
index 3889440975a7620d4f4e3e386deeaecadd77767b..51710b7b77959517bff320749b797f5ae2ba305c 100644 (file)
@@ -2,7 +2,7 @@
    Unix SMB/Netbios implementation.
    Version 1.9.
    Main SMB server routines
-   Copyright (C) Andrew Tridgell 1992-1995
+   Copyright (C) Andrew Tridgell 1992-1997
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 pstring servicesf = CONFIGFILE;
 extern pstring debugf;
 extern pstring sesssetup_user;
+extern fstring myworkgroup;
 
 char *InBuffer = NULL;
 char *OutBuffer = NULL;
 char *last_inbuf = NULL;
 
-BOOL share_mode_pending = False;
+int am_parent = 1;
+int atexit_set = 0;
 
 /* the last message the was processed */
 int last_message = -1;
@@ -55,11 +57,26 @@ extern pstring user_socket_options;
 connection_struct Connections[MAX_CONNECTIONS];
 files_struct Files[MAX_OPEN_FILES];
 
-extern int Protocol;
+/*
+ * Indirection for file fd's. Needed as POSIX locking
+ * is based on file/process, not fd/process.
+ */
+file_fd_struct FileFd[MAX_OPEN_FILES];
+int max_file_fd_used = 0;
 
-int maxxmit = BUFFER_SIZE;
+extern int Protocol;
 
-int chain_size = 0;
+/* 
+ * Size of data we can send to client. Set
+ *  by the client for all protocols above CORE.
+ *  Set by us for CORE protocol.
+ */
+int max_send = BUFFER_SIZE;
+/*
+ * Size of the data we can receive. Set by us.
+ * Can be modified by the max xmit parameter.
+ */
+int max_recv = BUFFER_SIZE;
 
 /* a fnum to use when chaining */
 int chain_fnum = -1;
@@ -69,6 +86,7 @@ static int num_connections_open = 0;
 
 extern fstring remote_machine;
 
+pstring OriginalDir;
 
 /* these can be set by some functions to override the error codes */
 int unix_ERR_class=SUCCESS;
@@ -88,7 +106,21 @@ static int find_free_connection(int hash);
 #define IS_DOS_SYSTEM(test_mode) (((test_mode) & aSYSTEM) != 0)
 #define IS_DOS_HIDDEN(test_mode) (((test_mode) & aHIDDEN) != 0)
 
-
+/****************************************************************************
+  when exiting, take the whole family
+****************************************************************************/
+void  *dflt_sig(void)
+{
+  exit_server("caught signal");
+  return 0; /* Keep -Wall happy :-) */
+}
+/****************************************************************************
+  Send a SIGTERM to our process group.
+*****************************************************************************/
+void  killkids(void)
+{
+  if(am_parent) kill(0,SIGTERM);
+}
 
 /****************************************************************************
   change a dos mode to a unix mode
@@ -108,19 +140,21 @@ mode_t unix_mode(int cnum,int dosmode)
   if ( !IS_DOS_READONLY(dosmode) )
     result |= (S_IWUSR | S_IWGRP | S_IWOTH);
  
-  if (IS_DOS_DIR(dosmode))
+  if (IS_DOS_DIR(dosmode)) {
     result |= (S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH | S_IWUSR);
-  if (MAP_ARCHIVE(cnum) && IS_DOS_ARCHIVE(dosmode))
-    result |= S_IXUSR;
+    result &= (lp_dir_mode(SNUM(cnum)) | 0700);
+  } else { 
+    if (MAP_ARCHIVE(cnum) && IS_DOS_ARCHIVE(dosmode))
+      result |= S_IXUSR;
 
-  if (MAP_SYSTEM(cnum) && IS_DOS_SYSTEM(dosmode))
-    result |= S_IXGRP;
+    if (MAP_SYSTEM(cnum) && IS_DOS_SYSTEM(dosmode))
+      result |= S_IXGRP;
  
-  if (MAP_HIDDEN(cnum) && IS_DOS_HIDDEN(dosmode))
-    result |= S_IXOTH;  
+    if (MAP_HIDDEN(cnum) && IS_DOS_HIDDEN(dosmode))
+      result |= S_IXOTH;  
  
-  result &= CREATE_MODE(cnum);
+    result &= CREATE_MODE(cnum);
+  }
   return(result);
 }
 
@@ -278,7 +312,7 @@ static BOOL mangled_equal(char *name1, char *name2)
 {
   pstring tmpname;
 
-  if (is_8_3(name2))
+  if (is_8_3(name2, True))
     return(False);
 
   strcpy(tmpname,name2);
@@ -356,31 +390,49 @@ for this service.
 
 The function will return False if some part of the name except for the last
 part cannot be resolved
+
+If the saved_last_component != 0, then the unmodified last component
+of the pathname is returned there. This is used in an exceptional
+case in reply_mv (so far). If saved_last_component == 0 then nothing
+is returned there.
 ****************************************************************************/
-BOOL unix_convert(char *name,int cnum)
+BOOL unix_convert(char *name,int cnum,pstring saved_last_component)
 {
   struct stat st;
   char *start, *end;
   pstring dirpath;
 
   *dirpath = 0;
+  if(saved_last_component)
+    *saved_last_component = 0;
 
   /* convert to basic unix format - removing \ chars and cleaning it up */
   unix_format(name);
   unix_clean_name(name);
 
-  if (!case_sensitive && 
-      (!case_preserve || (is_8_3(name) && !short_case_preserve)))
-    strnorm(name);
-
   /* names must be relative to the root of the service - trim any leading /.
    also trim trailing /'s */
   trim_string(name,"/","/");
 
+  /*
+   * Ensure saved_last_component is valid even if file exists.
+   */
+  if(saved_last_component) {
+    end = strrchr(name, '/');
+    if(end)
+      strcpy(saved_last_component, end + 1);
+    else
+      strcpy(saved_last_component, name);
+  }
+
+  if (!case_sensitive && 
+      (!case_preserve || (is_8_3(name, False) && !short_case_preserve)))
+    strnorm(name);
+
   /* check if it's a printer file */
   if (Connections[cnum].printer)
     {
-      if ((! *name) || strchr(name,'/') || !is_8_3(name))
+      if ((! *name) || strchr(name,'/') || !is_8_3(name, True))
        {
          char *s;
          fstring name2;
@@ -420,7 +472,10 @@ BOOL unix_convert(char *name,int cnum)
       end = strchr(start, '/');
 
       /* chop the name at this point */
-      if (end) *end = 0;
+      if (end)         *end = 0;
+
+      if(saved_last_component != 0)
+       strcpy(saved_last_component, end ? end + 1 : start);
 
       /* check if the name exists up to this point */
       if (sys_stat(name, &st) == 0) 
@@ -445,7 +500,6 @@ BOOL unix_convert(char *name,int cnum)
             later */
          if (end) strcpy(rest,end+1);
 
-
          /* try to find this part of the path in the directory */
          if (strchr(start,'?') || strchr(start,'*') ||
              !scan_directory(dirpath, start, SNUM(cnum), end?True:False))
@@ -565,11 +619,11 @@ int disk_free(char *path,int *bsize,int *dfree,int *dsize)
       pstring syscmd;
       pstring outfile;
          
-      sprintf(outfile,"/tmp/dfree.smb.%d",(int)getpid());
+      sprintf(outfile,"%s/dfree.smb.%d",tmpdir(),(int)getpid());
       sprintf(syscmd,"%s %s",df_command,path);
       standard_sub_basic(syscmd);
 
-      ret = smbrun(syscmd,outfile);
+      ret = smbrun(syscmd,outfile,False);
       DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
          
       {
@@ -686,6 +740,12 @@ BOOL check_name(char *name,int cnum)
 
   errno = 0;
 
+  if( is_vetoed_path(name)) 
+    {
+      DEBUG(5,("file path name %s vetoed\n",name));
+      return(0);
+    }
+
   ret = reduce_name(name,Connections[cnum].connectpath,lp_widelinks(SNUM(cnum)));
   if (!ret)
     DEBUG(5,("check_name on %s failed\n",name));
@@ -710,16 +770,182 @@ static void check_for_pipe(char *fname)
     }
 }
 
+/****************************************************************************
+fd support routines - attempt to do a sys_open
+****************************************************************************/
+
+int fd_attempt_open(char *fname, int flags, int mode)
+{
+  int fd = sys_open(fname,flags,mode);
+
+  /* Fix for files ending in '.' */
+  if((fd == -1) && (errno == ENOENT) &&
+     (strchr(fname,'.')==NULL))
+    {
+      strcat(fname,".");
+      fd = sys_open(fname,flags,mode);
+    }
+
+#if (defined(ENAMETOOLONG) && defined(HAVE_PATHCONF))
+  if ((fd == -1) && (errno == ENAMETOOLONG))
+    {
+      int max_len;
+      char *p = strrchr(fname, '/');
+
+      if (p == fname)   /* name is "/xxx" */
+        {
+          max_len = pathconf("/", _PC_NAME_MAX);
+          p++;
+        }
+      else if ((p == NULL) || (p == fname))
+        {
+          p = fname;
+          max_len = pathconf(".", _PC_NAME_MAX);
+        }
+      else
+        {
+          *p = '\0';
+          max_len = pathconf(fname, _PC_NAME_MAX);
+          *p = '/';
+          p++;
+        }
+      if (strlen(p) > max_len)
+        {
+          char tmp = p[max_len];
+
+          p[max_len] = '\0';
+          if ((fd = sys_open(fname,flags,mode)) == -1)
+            p[max_len] = tmp;
+        }
+    }
+#endif
+  return fd;
+}
+
+/****************************************************************************
+fd support routines - attempt to find an already open file by dev
+and inode - increments the ref_count of the returned file_fd_struct *.
+****************************************************************************/
+file_fd_struct *fd_get_already_open(struct stat *sbuf)
+{
+  int i;
+  file_fd_struct *fd_ptr;
+
+  if(sbuf == 0)
+    return 0;
+
+  for(i = 0; i <= max_file_fd_used; i++) {
+    fd_ptr = &FileFd[i];
+    if((fd_ptr->ref_count > 0) &&
+       (((uint32)sbuf->st_dev) == fd_ptr->dev) &&
+       (((uint32)sbuf->st_ino) == fd_ptr->inode)) {
+      fd_ptr->ref_count++;
+      DEBUG(3,
+       ("Re-used file_fd_struct %d, dev = %x, inode = %x, ref_count = %d\n",
+        i, fd_ptr->dev, fd_ptr->inode, fd_ptr->ref_count));
+      return fd_ptr;
+    }
+  }
+  return 0;
+}
+
+/****************************************************************************
+fd support routines - attempt to find a empty slot in the FileFd array.
+Increments the ref_count of the returned entry.
+****************************************************************************/
+file_fd_struct *fd_get_new()
+{
+  int i;
+  file_fd_struct *fd_ptr;
+
+  for(i = 0; i < MAX_OPEN_FILES; i++) {
+    fd_ptr = &FileFd[i];
+    if(fd_ptr->ref_count == 0) {
+      fd_ptr->dev = (uint32)-1;
+      fd_ptr->inode = (uint32)-1;
+      fd_ptr->fd = -1;
+      fd_ptr->fd_readonly = -1;
+      fd_ptr->fd_writeonly = -1;
+      fd_ptr->real_open_flags = -1;
+      fd_ptr->ref_count++;
+      /* Increment max used counter if neccessary, cuts down
+        on search time when re-using */
+      if(i > max_file_fd_used)
+        max_file_fd_used = i;
+      DEBUG(3,("Allocated new file_fd_struct %d, dev = %x, inode = %x\n",
+               i, fd_ptr->dev, fd_ptr->inode));
+      return fd_ptr;
+    }
+  }
+  DEBUG(1,("ERROR! Out of file_fd structures - perhaps increase MAX_OPEN_FILES?\
+n"));
+  return 0;
+}
+
+/****************************************************************************
+fd support routines - attempt to re-open an already open fd as O_RDWR.
+Save the already open fd (we cannot close due to POSIX file locking braindamage.
+****************************************************************************/
+
+void fd_attempt_reopen(char *fname, int mode, file_fd_struct *fd_ptr)
+{
+  int fd = sys_open( fname, O_RDWR, mode);
+
+  if(fd == -1)
+    return;
+
+  if(fd_ptr->real_open_flags == O_RDONLY)
+    fd_ptr->fd_readonly = fd_ptr->fd;
+  if(fd_ptr->real_open_flags == O_WRONLY)
+    fd_ptr->fd_writeonly = fd_ptr->fd;
+
+  fd_ptr->fd = fd;
+  fd_ptr->real_open_flags = O_RDWR;
+}
+
+/****************************************************************************
+fd support routines - attempt to close the file referenced by this fd.
+Decrements the ref_count and returns it.
+****************************************************************************/
+int fd_attempt_close(file_fd_struct *fd_ptr)
+{
+  DEBUG(3,("fd_attempt_close on file_fd_struct %d, fd = %d, dev = %x, inode = %x, open_flags = %d, ref_count = %d.\n",
+          fd_ptr - &FileFd[0],
+          fd_ptr->fd, fd_ptr->dev, fd_ptr->inode,
+          fd_ptr->real_open_flags,
+          fd_ptr->ref_count));
+  if(fd_ptr->ref_count > 0) {
+    fd_ptr->ref_count--;
+    if(fd_ptr->ref_count == 0) {
+      if(fd_ptr->fd != -1)
+        close(fd_ptr->fd);
+      if(fd_ptr->fd_readonly != -1)
+       close(fd_ptr->fd_readonly);
+      if(fd_ptr->fd_writeonly != -1)
+       close(fd_ptr->fd_writeonly);
+      fd_ptr->fd = -1;
+      fd_ptr->fd_readonly = -1;
+      fd_ptr->fd_writeonly = -1;
+      fd_ptr->real_open_flags = -1;
+      fd_ptr->dev = (uint32)-1;
+      fd_ptr->inode = (uint32)-1;
+    }
+  } 
+ return fd_ptr->ref_count;
+}
 
 /****************************************************************************
 open a file
 ****************************************************************************/
-void open_file(int fnum,int cnum,char *fname1,int flags,int mode)
+static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct stat *sbuf)
 {
+  extern struct current_user current_user;
   pstring fname;
+  struct stat statbuf;
+  file_fd_struct *fd_ptr;
 
   Files[fnum].open = False;
-  Files[fnum].fd = -1;
+  Files[fnum].fd_ptr = 0;
   errno = EPERM;
 
   strcpy(fname,fname1);
@@ -749,10 +975,104 @@ void open_file(int fnum,int cnum,char *fname1,int flags,int mode)
     sys_unlink(fname);
 #endif
 
+  /*
+   * Ensure we have a valid struct stat so we can search the
+   * open fd table.
+   */
+  if(sbuf == 0) {
+    if(stat(fname, &statbuf) < 0) {
+      if(errno != ENOENT) {
+        DEBUG(3,("Error doing stat on file %s (%s)\n",
+                 fname,strerror(errno)));
+
+        check_for_pipe(fname);
+        return;
+      }
+      sbuf = 0;
+    } else {
+      sbuf = &statbuf;
+    }
+  }
+
+  /*
+   * Check to see if we have this file already
+   * open. If we do, just use the already open fd and increment the
+   * reference count (fd_get_already_open increments the ref_count).
+   */
+  if((fd_ptr = fd_get_already_open(sbuf))!= 0) {
+
+    int accmode = (flags & (O_RDONLY | O_WRONLY | O_RDWR));
+
+    /* File was already open. */
+    if((flags & O_CREAT) && (flags & O_EXCL)) {
+      fd_ptr->ref_count--;
+      errno = EEXIST;
+      return;
+    }
 
-  Files[fnum].fd = sys_open(fname,flags,mode);
+    /* 
+     * If not opened O_RDWR try
+     * and do that here - a chmod may have been done
+     * between the last open and now. 
+     */
+    if(fd_ptr->real_open_flags != O_RDWR)
+      fd_attempt_reopen(fname, mode, fd_ptr);
+
+    /*
+     * Ensure that if we wanted write access
+     * it has been opened for write, and if we wanted read it
+     * was open for read. 
+     */
+    if(((accmode == O_WRONLY) && (fd_ptr->real_open_flags == O_RDONLY)) ||
+       ((accmode == O_RDONLY) && (fd_ptr->real_open_flags == O_WRONLY)) ||
+       ((accmode == O_RDWR) && (fd_ptr->real_open_flags != O_RDWR))) {
+      DEBUG(3,("Error opening (already open for flags=%d) file %s (%s) (flags=%d)\n",
+               fd_ptr->real_open_flags, fname,strerror(EACCES),flags));
+      check_for_pipe(fname);
+      fd_ptr->ref_count--;
+      return;
+    }
 
-  if ((Files[fnum].fd>=0) && 
+  } else {
+    int open_flags;
+    /* We need to allocate a new file_fd_struct (this increments the
+       ref_count). */
+    if((fd_ptr = fd_get_new()) == 0)
+      return;
+    /*
+     * Whatever the requested flags, attempt read/write access,
+     * as we don't know what flags future file opens may require.
+     * If this fails, try again with the required flags. 
+     * Even if we open read/write when only read access was 
+     * requested the setting of the can_write flag in
+     * the file_struct will protect us from errant
+     * write requests. We never need to worry about O_APPEND
+     * as this is not set anywhere in Samba.
+     */
+    fd_ptr->real_open_flags = O_RDWR;
+    /* Set the flags as needed without the read/write modes. */
+    open_flags = flags & ~(O_RDWR|O_WRONLY|O_RDONLY);
+    fd_ptr->fd = fd_attempt_open(fname, open_flags|O_RDWR, mode);
+    /*
+     * On some systems opening a file for R/W access on a read only
+     * filesystems sets errno to EROFS.
+     */
+#ifdef EROFS
+    if((fd_ptr->fd == -1) && ((errno == EACCES) || (errno == EROFS))) {
+#else /* No EROFS */
+    if((fd_ptr->fd == -1) && (errno == EACCES)) {
+#endif /* EROFS */
+      if(flags & O_WRONLY) {
+        fd_ptr->fd = fd_attempt_open(fname, open_flags|O_WRONLY, mode);
+        fd_ptr->real_open_flags = O_WRONLY;
+      } else {
+       fd_ptr->fd = fd_attempt_open(fname, open_flags|O_RDONLY, mode);
+        fd_ptr->real_open_flags = O_RDONLY;
+      }
+    }
+  }
+
+  if ((fd_ptr->fd >=0) && 
       Connections[cnum].printer && lp_minprintspace(SNUM(cnum))) {
     pstring dname;
     int dum1,dum2,dum3;
@@ -762,72 +1082,48 @@ void open_file(int fnum,int cnum,char *fname1,int flags,int mode)
     if (p) *p = 0;
     if (sys_disk_free(dname,&dum1,&dum2,&dum3) < 
        lp_minprintspace(SNUM(cnum))) {
-      close(Files[fnum].fd);
-      Files[fnum].fd = -1;
-      sys_unlink(fname);
+      fd_attempt_close(fd_ptr);
+      Files[fnum].fd_ptr = 0;
+      if(fd_ptr->ref_count == 0)
+        sys_unlink(fname);
       errno = ENOSPC;
       return;
     }
   }
     
-
-  /* Fix for files ending in '.' */
-  if((Files[fnum].fd == -1) && (errno == ENOENT) && 
-     (strchr(fname,'.')==NULL))
-    {
-      strcat(fname,".");
-      Files[fnum].fd = sys_open(fname,flags,mode);
-    }
-
-#if (defined(ENAMETOOLONG) && defined(HAVE_PATHCONF))
-  if ((Files[fnum].fd == -1) && (errno == ENAMETOOLONG))
-    {
-      int max_len;
-      char *p = strrchr(fname, '/');
-
-      if (p == fname)  /* name is "/xxx" */
-       {
-         max_len = pathconf("/", _PC_NAME_MAX);
-         p++;
-       }
-      else if ((p == NULL) || (p == fname))
-       {
-         p = fname;
-         max_len = pathconf(".", _PC_NAME_MAX);
-       }
-      else
-       {
-         *p = '\0';
-         max_len = pathconf(fname, _PC_NAME_MAX);
-         *p = '/';
-         p++;
-       }
-      if (strlen(p) > max_len)
-       {
-         char tmp = p[max_len];
-
-         p[max_len] = '\0';
-         if ((Files[fnum].fd = sys_open(fname,flags,mode)) == -1)
-           p[max_len] = tmp;
-       }
-    }
-#endif
-
-  if (Files[fnum].fd < 0)
+  if (fd_ptr->fd < 0)
     {
       DEBUG(3,("Error opening file %s (%s) (flags=%d)\n",
               fname,strerror(errno),flags));
+      /* Ensure the ref_count is decremented. */
+      fd_attempt_close(fd_ptr);
       check_for_pipe(fname);
       return;
     }
 
-  if (Files[fnum].fd >= 0)
+  if (fd_ptr->fd >= 0)
     {
-      struct stat st;
+      if(sbuf == 0) {
+        /* Do the fstat */
+        if(fstat(fd_ptr->fd, &statbuf) == -1) {
+          /* Error - backout !! */
+          DEBUG(3,("Error doing fstat on fd %d, file %s (%s)\n",
+                   fd_ptr->fd, fname,strerror(errno)));
+          /* Ensure the ref_count is decremented. */
+          fd_attempt_close(fd_ptr);
+          return;
+        }
+        sbuf = &statbuf;
+      }
+      /* Set the correct entries in fd_ptr. */
+      fd_ptr->dev = (uint32)sbuf->st_dev;
+      fd_ptr->inode = (uint32)sbuf->st_ino;
+
+      Files[fnum].fd_ptr = fd_ptr;
       Connections[cnum].num_files_open++;
-      fstat(Files[fnum].fd,&st);
-      Files[fnum].mode = st.st_mode;
-      Files[fnum].open_time = time(NULL);
+      Files[fnum].mode = sbuf->st_mode;
+      GetTimeOfDay(&Files[fnum].open_time);
+      Files[fnum].uid = current_user.id;
       Files[fnum].size = 0;
       Files[fnum].pos = -1;
       Files[fnum].open = True;
@@ -837,11 +1133,10 @@ void open_file(int fnum,int cnum,char *fname1,int flags,int mode)
       Files[fnum].can_read = ((flags & O_WRONLY)==0);
       Files[fnum].can_write = ((flags & (O_WRONLY|O_RDWR))!=0);
       Files[fnum].share_mode = 0;
-      Files[fnum].share_pending = False;
       Files[fnum].print_file = Connections[cnum].printer;
       Files[fnum].modified = False;
       Files[fnum].cnum = cnum;
-      string_set(&Files[fnum].name,fname);
+      string_set(&Files[fnum].name,dos_to_unix(fname,False));
       Files[fnum].wbmpx_ptr = NULL;      
 
       /*
@@ -871,7 +1166,7 @@ void open_file(int fnum,int cnum,char *fname1,int flags,int mode)
     {
       Files[fnum].mmap_size = file_size(fname);
       Files[fnum].mmap_ptr = (char *)mmap(NULL,Files[fnum].mmap_size,
-                                         PROT_READ,MAP_SHARED,Files[fnum].fd,0);
+                                         PROT_READ,MAP_SHARED,Files[fnum].fd_ptr->fd,0);
 
       if (Files[fnum].mmap_ptr == (char *)-1 || !Files[fnum].mmap_ptr)
        {
@@ -888,7 +1183,7 @@ sync a file
 void sync_file(int fnum)
 {
 #ifndef NO_FSYNC
-  fsync(Files[fnum].fd);
+  fsync(Files[fnum].fd_ptr->fd);
 #endif
 }
 
@@ -925,7 +1220,7 @@ static void check_magic(int fnum,int cnum)
       sprintf(magic_output,"%s.out",fname);
 
     chmod(fname,0755);
-    ret = smbrun(fname,magic_output);
+    ret = smbrun(fname,magic_output,False);
     DEBUG(3,("Invoking magic command %s gave %d\n",fname,ret));
     unlink(fname);
   }
@@ -937,38 +1232,49 @@ close a file - possibly invalidating the read prediction
 ****************************************************************************/
 void close_file(int fnum)
 {
-  int cnum = Files[fnum].cnum;
-  invalidate_read_prediction(Files[fnum].fd);
-  Files[fnum].open = False;
+  files_struct *fs_p = &Files[fnum];
+  int cnum = fs_p->cnum;
+  uint32 dev = fs_p->fd_ptr->dev;
+  uint32 inode = fs_p->fd_ptr->inode;
+  share_lock_token token;
+
+  invalidate_read_prediction(fs_p->fd_ptr->fd);
+  fs_p->open = False;
   Connections[cnum].num_files_open--;
-  if(Files[fnum].wbmpx_ptr) 
+  if(fs_p->wbmpx_ptr) 
     {
-      free((char *)Files[fnum].wbmpx_ptr);
-      Files[fnum].wbmpx_ptr = NULL;
+      free((char *)fs_p->wbmpx_ptr);
+      fs_p->wbmpx_ptr = NULL;
     }
 
 #if USE_MMAP
-  if(Files[fnum].mmap_ptr) 
+  if(fs_p->mmap_ptr) 
     {
-      munmap(Files[fnum].mmap_ptr,Files[fnum].mmap_size);
-      Files[fnum].mmap_ptr = NULL;
+      munmap(fs_p->mmap_ptr,fs_p->mmap_size);
+      fs_p->mmap_ptr = NULL;
     }
 #endif
 
   if (lp_share_modes(SNUM(cnum)))
-    del_share_mode(fnum);
+  {
+    lock_share_entry( cnum, dev, inode, &token);
+    del_share_mode(token, fnum);
+  }
+
+  fd_attempt_close(fs_p->fd_ptr);
 
-  close(Files[fnum].fd);
+  if (lp_share_modes(SNUM(cnum)))
+    unlock_share_entry( cnum, dev, inode, token);
 
   /* NT uses smbclose to start a print - weird */
-  if (Files[fnum].print_file)
+  if (fs_p->print_file)
     print_file(fnum);
 
   /* check for magic scripts */
   check_magic(fnum,cnum);
 
   DEBUG(2,("%s %s closed file %s (numopen=%d)\n",
-          timestring(),Connections[cnum].user,Files[fnum].name,
+          timestring(),Connections[cnum].user,fs_p->name,
           Connections[cnum].num_files_open));
 }
 
@@ -1030,17 +1336,44 @@ return True if sharing doesn't prevent the operation
 ********************************************************************/
 BOOL check_file_sharing(int cnum,char *fname)
 {
-  int pid=0;
-  int share_mode = get_share_mode_byname(cnum,fname,&pid);
+  int i;
+  int ret = False;
+  min_share_mode_entry *old_shares = 0;
+  int num_share_modes;
+  struct stat sbuf;
+  share_lock_token token;
+  int pid = getpid();
 
-  if (!pid || !share_mode) return(True);
-  if (share_mode == DENY_DOS)
-    return(pid == getpid());
+  if(!lp_share_modes(SNUM(cnum)))
+    return True;
+
+  if (stat(fname,&sbuf) == -1) return(True);
+
+  lock_share_entry(cnum, (uint32)sbuf.st_dev, (uint32)sbuf.st_ino, &token);
+  num_share_modes = get_share_modes(cnum, token, 
+                     (uint32)sbuf.st_dev, (uint32)sbuf.st_ino, &old_shares);
+
+  for( i = 0; i < num_share_modes; i++)
+  {
+    if (old_shares[i].share_mode != DENY_DOS)
+      goto free_and_exit;
+
+    if(old_shares[i].pid != pid)
+      goto free_and_exit;
+  }
 
   /* XXXX exactly what share mode combinations should be allowed for
      deleting/renaming? */
-  return(False);
+  /* If we got here then either there were no share modes or
+     all share modes were DENY_DOS and the pid == getpid() */
+  ret = True;
+
+free_and_exit:
+
+  unlock_share_entry(cnum, (uint32)sbuf.st_dev, (uint32)sbuf.st_ino, token);
+  if(old_shares != NULL)
+    free((char *)old_shares);
+  return(ret);
 }
 
 /****************************************************************************
@@ -1048,17 +1381,25 @@ BOOL check_file_sharing(int cnum,char *fname)
   Helper for open_file_shared. 
   Truncate a file after checking locking; close file if locked.
   **************************************************************************/
-static void truncate_unless_locked(int fnum, int cnum)
+static void truncate_unless_locked(int fnum, int cnum, share_lock_token token, 
+       BOOL *share_locked)
 {
   if (Files[fnum].can_write){
     if (is_locked(fnum,cnum,0x3FFFFFFF,0)){
+      /* If share modes are in force for this connection we
+         have the share entry locked. Unlock it before closing. */
+      if (*share_locked && lp_share_modes(SNUM(cnum)))
+        unlock_share_entry( cnum, Files[fnum].fd_ptr->dev, 
+                            Files[fnum].fd_ptr->inode, token);
       close_file(fnum);   
+      /* Share mode no longer locked. */
+      *share_locked = False;
       errno = EACCES;
       unix_ERR_class = ERRDOS;
       unix_ERR_code = ERRlock;
     }
     else
-      ftruncate(Files[fnum].fd,0); 
+      ftruncate(Files[fnum].fd_ptr->fd,0); 
   }
 }
 
@@ -1069,25 +1410,31 @@ open a file with a share mode
 void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
                      int mode,int *Access,int *action)
 {
+  files_struct *fs_p = &Files[fnum];
   int flags=0;
   int flags2=0;
   int deny_mode = (share_mode>>4)&7;
   struct stat sbuf;
   BOOL file_existed = file_exist(fname,&sbuf);
+  BOOL share_locked = False;
   BOOL fcbopen = False;
-  int share_pid=0;
+  share_lock_token token;
+  uint32 dev = 0;
+  uint32 inode = 0;
 
-  Files[fnum].open = False;
-  Files[fnum].fd = -1;
+  fs_p->open = False;
+  fs_p->fd_ptr = 0;
 
   /* this is for OS/2 EAs - try and say we don't support them */
-  if (strstr(fname,".+,;=[].")) {
+  if (strstr(fname,".+,;=[].")) 
+  {
     unix_ERR_class = ERRDOS;
     unix_ERR_code = ERROR_EAS_NOT_SUPPORTED;
     return;
   }
 
-  if ((ofun & 0x3) == 0 && file_existed) {
+  if ((ofun & 0x3) == 0 && file_existed)  
+  {
     errno = EEXIST;
     return;
   }
@@ -1101,7 +1448,7 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
      append does not mean the same thing under dos and unix */
 
   switch (share_mode&0xF)
-    {
+  {
     case 1: 
       flags = O_WRONLY; 
       break;
@@ -1115,18 +1462,21 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
     default:
       flags = O_RDONLY;
       break;
-    }
+  }
   
   if (flags != O_RDONLY && file_existed && 
-      (!CAN_WRITE(cnum) || IS_DOS_READONLY(dos_mode(cnum,fname,&sbuf)))) {
-    if (!fcbopen) {
+      (!CAN_WRITE(cnum) || IS_DOS_READONLY(dos_mode(cnum,fname,&sbuf)))) 
+  {
+    if (!fcbopen) 
+    {
       errno = EACCES;
       return;
     }
     flags = O_RDONLY;
   }
 
-  if (deny_mode > DENY_NONE && deny_mode!=DENY_FCB) {
+  if (deny_mode > DENY_NONE && deny_mode!=DENY_FCB) 
+  {
     DEBUG(2,("Invalid deny mode %d on file %s\n",deny_mode,fname));
     errno = EINVAL;
     return;
@@ -1134,21 +1484,36 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
 
   if (deny_mode == DENY_FCB) deny_mode = DENY_DOS;
 
-  if (lp_share_modes(SNUM(cnum))) {
-    int old_share=0;
+  if (lp_share_modes(SNUM(cnum))) 
+  {
+    int num_shares = 0;
+    int i;
+    min_share_mode_entry *old_shares = 0;
+
 
     if (file_existed)
-      old_share = get_share_mode(cnum,&sbuf,&share_pid);
+    {
+      dev = (uint32)sbuf.st_dev;
+      inode = (uint32)sbuf.st_ino;
+      lock_share_entry(cnum, dev, inode, &token);
+      share_locked = True;
+      num_shares = get_share_modes(cnum, token, dev, inode, &old_shares);
+    }
 
-    if (share_pid) {
+    for(i = 0; i < num_shares; i++)
+    {
       /* someone else has a share lock on it, check to see 
         if we can too */
-      int old_open_mode = old_share&0xF;
-      int old_deny_mode = (old_share>>4)&7;
+      int old_open_mode = old_shares[i].share_mode &0xF;
+      int old_deny_mode = (old_shares[i].share_mode >>4)&7;
 
-      if (deny_mode > 4 || old_deny_mode > 4 || old_open_mode > 2) {
+      if (deny_mode > 4 || old_deny_mode > 4 || old_open_mode > 2) 
+      {
        DEBUG(2,("Invalid share mode (%d,%d,%d) on file %s\n",
                 deny_mode,old_deny_mode,old_open_mode,fname));
+        free((char *)old_shares);
+        if(share_locked)
+          unlock_share_entry(cnum, dev, inode, token);
        errno = EACCES;
        unix_ERR_class = ERRDOS;
        unix_ERR_code = ERRbadshare;
@@ -1157,20 +1522,25 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
 
       {
        int access_allowed = access_table(deny_mode,old_deny_mode,old_open_mode,
-                                         share_pid,fname);
+                                         old_shares[i].pid,fname);
 
        if ((access_allowed == AFAIL) ||
+           (!fcbopen && (access_allowed == AREAD && flags == O_RDWR)) ||
            (access_allowed == AREAD && flags == O_WRONLY) ||
-           (access_allowed == AWRITE && flags == O_RDONLY)) {
+           (access_allowed == AWRITE && flags == O_RDONLY)) 
+        {
          DEBUG(2,("Share violation on file (%d,%d,%d,%d,%s) = %d\n",
                   deny_mode,old_deny_mode,old_open_mode,
-                  share_pid,fname,
+                  old_shares[i].pid,fname,
                   access_allowed));
+          free((char *)old_shares);
+          if(share_locked)
+            unlock_share_entry(cnum, dev, inode, token);
          errno = EACCES;
          unix_ERR_class = ERRDOS;
          unix_ERR_code = ERRbadshare;
          return;
-       }
+        }
        
        if (access_allowed == AREAD)
          flags = O_RDONLY;
@@ -1179,76 +1549,72 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
          flags = O_WRONLY;
       }
     }
+    if(old_shares != 0)
+      free((char *)old_shares);
   }
 
   DEBUG(4,("calling open_file with flags=0x%X flags2=0x%X mode=0%o\n",
           flags,flags2,mode));
 
-  open_file(fnum,cnum,fname,flags|(flags2&~(O_TRUNC)),mode);
-  if (!Files[fnum].open && flags==O_RDWR && errno!=ENOENT && fcbopen) {
+  open_file(fnum,cnum,fname,flags|(flags2&~(O_TRUNC)),mode,file_existed ? &sbuf : 0);
+  if (!fs_p->open && flags==O_RDWR && errno!=ENOENT && fcbopen) 
+  {
     flags = O_RDONLY;
-    open_file(fnum,cnum,fname,flags,mode);
+    open_file(fnum,cnum,fname,flags,mode,file_existed ? &sbuf : 0 );
   }
 
-  if (Files[fnum].open) {
+  if (fs_p->open) 
+  {
     int open_mode=0;
-    switch (flags) {
-    case O_RDONLY:
-      open_mode = 0;
-      break;
-    case O_RDWR:
-      open_mode = 2;
-      break;
-    case O_WRONLY:
-      open_mode = 1;
-      break;
+
+    if((share_locked == False) && lp_share_modes(SNUM(cnum)))
+    {
+      /* We created the file - thus we must now lock the share entry before creating it. */
+      dev = fs_p->fd_ptr->dev;
+      inode = fs_p->fd_ptr->inode;
+      lock_share_entry(cnum, dev, inode, &token);
+      share_locked = True;
+    }
+
+    switch (flags) 
+    {
+      case O_RDONLY:
+        open_mode = 0;
+        break;
+      case O_RDWR:
+        open_mode = 2;
+        break;
+      case O_WRONLY:
+        open_mode = 1;
+        break;
     }
 
-    Files[fnum].share_mode = (deny_mode<<4) | open_mode;
-    Files[fnum].share_pending = True;
+    fs_p->share_mode = (deny_mode<<4) | open_mode;
 
-    if (Access) {
+    if (Access)
       (*Access) = open_mode;
-    }
-    
-    if (action) {
+
+    if (action) 
+    {
       if (file_existed && !(flags2 & O_TRUNC)) *action = 1;
       if (!file_existed) *action = 2;
       if (file_existed && (flags2 & O_TRUNC)) *action = 3;
     }
-
-    if (!share_pid)
-      share_mode_pending = True;
+    /* We must create the share mode entry before truncate as
+       truncate can fail due to locking and have to close the
+       file (which expects the share_mode_entry to be there).
+     */
+    if (lp_share_modes(SNUM(cnum)))
+      set_share_mode(token, fnum);
 
     if ((flags2&O_TRUNC) && file_existed)
-      truncate_unless_locked(fnum,cnum);
+      truncate_unless_locked(fnum,cnum,token,&share_locked);
   }
-}
-
 
-
-/*******************************************************************
-check for files that we should now set our share modes on
-********************************************************************/
-static void check_share_modes(void)
-{
-  int i;
-  for (i=0;i<MAX_OPEN_FILES;i++)
-    if(Files[i].open && Files[i].share_pending) {
-      if (lp_share_modes(SNUM(Files[i].cnum))) {
-       int pid=0;
-       get_share_mode_by_fnum(Files[i].cnum,i,&pid);
-       if (!pid) {
-         set_share_mode(i,Files[i].share_mode);
-         Files[i].share_pending = False;
-       }
-      } else {
-       Files[i].share_pending = False; 
-      }
-    }
+  if (share_locked && lp_share_modes(SNUM(cnum)))
+    unlock_share_entry( cnum, dev, inode, token);
 }
 
-
 /****************************************************************************
 seek a file. Try to avoid the seek if possible
 ****************************************************************************/
@@ -1258,7 +1624,7 @@ int seek_file(int fnum,int pos)
   if (Files[fnum].print_file && POSTSCRIPT(Files[fnum].cnum))
     offset = 3;
 
-  Files[fnum].pos = lseek(Files[fnum].fd,pos+offset,SEEK_SET) - offset;
+  Files[fnum].pos = lseek(Files[fnum].fd_ptr->fd,pos+offset,SEEK_SET) - offset;
   return(Files[fnum].pos);
 }
 
@@ -1271,7 +1637,7 @@ int read_file(int fnum,char *data,int pos,int n)
 
   if (!Files[fnum].can_write)
     {
-      ret = read_predict(Files[fnum].fd,pos,data,NULL,n);
+      ret = read_predict(Files[fnum].fd_ptr->fd,pos,data,NULL,n);
 
       data += ret;
       n -= ret;
@@ -1303,7 +1669,7 @@ int read_file(int fnum,char *data,int pos,int n)
     }
   
   if (n > 0) {
-    readret = read(Files[fnum].fd,data,n);
+    readret = read(Files[fnum].fd_ptr->fd,data,n);
     if (readret > 0) ret += readret;
   }
 
@@ -1324,7 +1690,7 @@ int write_file(int fnum,char *data,int n)
   if (!Files[fnum].modified) {
     struct stat st;
     Files[fnum].modified = True;
-    if (fstat(Files[fnum].fd,&st) == 0) {
+    if (fstat(Files[fnum].fd_ptr->fd,&st) == 0) {
       int dosmode = dos_mode(Files[fnum].cnum,Files[fnum].name,&st);
       if (MAP_ARCHIVE(Files[fnum].cnum) && !IS_DOS_ARCHIVE(dosmode)) { 
        dos_chmod(Files[fnum].cnum,Files[fnum].name,dosmode | aARCH,&st);
@@ -1332,7 +1698,7 @@ int write_file(int fnum,char *data,int n)
     }  
   }
 
-  return(write_data(Files[fnum].fd,data,n));
+  return(write_data(Files[fnum].fd_ptr->fd,data,n));
 }
 
 
@@ -1588,7 +1954,7 @@ static int sig_cld()
   DEBUG(5,("got SIGCLD\n"));
 
 #ifdef USE_WAITPID
-  while (waitpid((pid_t)-1,(int *)NULL, WNOHANG) > 0);
+  while (sys_waitpid((pid_t)-1,(int *)NULL, WNOHANG) > 0);
 #endif
 
   /* Stop zombies */
@@ -1620,6 +1986,20 @@ static int sig_cld()
   **************************************************************************/
 static int sig_pipe()
 {
+  extern int password_client;
+  BlockSignals(True,SIGPIPE);
+
+  if (password_client != -1) {
+    DEBUG(3,("lost connection to password server\n"));
+    close(password_client);
+    password_client = -1;
+#ifndef DONT_REINSTALL_SIG
+    signal(SIGPIPE, SIGNAL_CAST sig_pipe);
+#endif
+    BlockSignals(False,SIGPIPE);
+    return 0;
+  }
+
   exit_server("Got sigpipe\n");
   return(0);
 }
@@ -1645,7 +2025,7 @@ static BOOL open_sockets(BOOL is_daemon,int port)
 #endif
 
       /* open an incoming socket */
-      s = open_socket_in(SOCK_STREAM, port, 0);
+      s = open_socket_in(SOCK_STREAM, port, 0,interpret_addr(lp_socket_address()));
       if (s == -1)
        return(False);
 
@@ -1657,6 +2037,9 @@ static BOOL open_sockets(BOOL is_daemon,int port)
          return False;
        }
       
+      if(atexit_set == 0)
+        atexit(killkids);
+
       /* now accept incoming connections - forking a new process
         for each incoming connection */
       DEBUG(2,("waiting for a connection\n"));
@@ -1691,6 +2074,7 @@ static BOOL open_sockets(BOOL is_daemon,int port)
 
              /* close our standard file descriptors */
              close_low_fds();
+              am_parent = 0;
   
              set_socket_options(Client,"SO_KEEPALIVE");
              set_socket_options(Client,user_socket_options);
@@ -1879,7 +2263,7 @@ int setup_groups(char *user, int uid, int gid, int *p_ngroups,
 /****************************************************************************
   make a connection to a service
 ****************************************************************************/
-int make_connection(char *service,char *user,char *password, int pwlen, char *dev,int vuid)
+int make_connection(char *service,char *user,char *password, int pwlen, char *dev,uint16 vuid)
 {
   int cnum;
   int snum;
@@ -1999,6 +2383,7 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
     pcon->admin_user = False;
     
   pcon->force_user = force;
+  pcon->vuid = vuid;
   pcon->uid = pass->pw_uid;
   pcon->gid = pass->pw_gid;
   pcon->num_files_open = 0;
@@ -2014,14 +2399,21 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
 #if HAVE_GETGRNAM 
   if (*lp_force_group(snum))
     {
-      struct group *gptr = (struct group *)getgrnam(lp_force_group(snum));
+      struct group *gptr;
+      pstring gname;
+
+      StrnCpy(gname,lp_force_group(snum),sizeof(pstring)-1);
+      /* default service may be a group name           */
+      string_sub(gname,"%S",service);
+      gptr = (struct group *)getgrnam(gname);
+
       if (gptr)
        {
          pcon->gid = gptr->gr_gid;
-         DEBUG(3,("Forced group %s\n",lp_force_group(snum)));
+         DEBUG(3,("Forced group %s\n",gname));
        }
       else
-       DEBUG(1,("Couldn't find group %s\n",lp_force_group(snum)));
+       DEBUG(1,("Couldn't find group %s\n",gname));
     }
 #endif
 
@@ -2084,10 +2476,10 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
       strcpy(cmd,lp_rootpreexec(SNUM(cnum)));
       standard_sub(cnum,cmd);
       DEBUG(5,("cmd=%s\n",cmd));
-      smbrun(cmd,NULL);
+      smbrun(cmd,NULL,False);
     }
 
-  if (!become_user(cnum,pcon->uid))
+  if (!become_user(cnum,pcon->vuid))
     {
       DEBUG(0,("Can't become connected user!\n"));
       pcon->open = False;
@@ -2137,17 +2529,17 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
       pstring cmd;
       strcpy(cmd,lp_preexec(SNUM(cnum)));
       standard_sub(cnum,cmd);
-      smbrun(cmd,NULL);
+      smbrun(cmd,NULL,False);
     }
   
   /* we've finished with the sensitive stuff */
   unbecome_user();
 
   {
-    extern struct from_host Client_info;
     DEBUG(IS_IPC(cnum)?3:1,("%s %s (%s) connect to service %s as user %s (uid=%d,gid=%d) (pid %d)\n",
                            timestring(),
-                           Client_info.name,Client_info.addr,
+                           remote_machine,
+                           client_addr(),
                            lp_servicename(SNUM(cnum)),user,
                            pcon->uid,
                            pcon->gid,
@@ -2249,6 +2641,11 @@ int reply_lanman1(char *outbuf)
   int secword=0;
   BOOL doencrypt = SMBENCRYPT();
   time_t t = time(NULL);
+  /* We need to save and restore this as it can be destroyed
+     if we call another server if security=server
+     Thanks to Paul Nelson @ Thursby for pointing this out.
+   */
+  uint16 mid = SVAL(outbuf, smb_mid);
 
   if (lp_security()>=SEC_USER) secword |= 1;
   if (doencrypt) secword |= 2;
@@ -2271,7 +2668,8 @@ int reply_lanman1(char *outbuf)
   }
 
   CVAL(outbuf,smb_flg) = 0x81; /* Reply, SMBlockread, SMBwritelock supported */
-  SSVAL(outbuf,smb_vwv2,maxxmit);
+  SSVAL(outbuf,smb_mid,mid); /* Restore possibly corrupted mid */
+  SSVAL(outbuf,smb_vwv2,max_recv);
   SSVAL(outbuf,smb_vwv3,lp_maxmux()); /* maxmux */
   SSVAL(outbuf,smb_vwv4,1);
   SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support
@@ -2294,6 +2692,11 @@ int reply_lanman2(char *outbuf)
   int secword=0;
   BOOL doencrypt = SMBENCRYPT();
   time_t t = time(NULL);
+  /* We need to save and restore this as it can be destroyed
+     if we call another server if security=server
+     Thanks to Paul Nelson @ Thursby for pointing this out.
+   */
+  uint16 mid = SVAL(outbuf, smb_mid);
 
   if (lp_security()>=SEC_USER) secword |= 1;
   if (doencrypt) secword |= 2;
@@ -2318,7 +2721,8 @@ int reply_lanman2(char *outbuf)
   }
 
   CVAL(outbuf,smb_flg) = 0x81; /* Reply, SMBlockread, SMBwritelock supported */
-  SSVAL(outbuf,smb_vwv2,maxxmit);
+  SSVAL(outbuf,smb_mid,mid); /* Restore possibly corrupted mid */
+  SSVAL(outbuf,smb_vwv2,max_recv);
   SSVAL(outbuf,smb_vwv3,lp_maxmux()); 
   SSVAL(outbuf,smb_vwv4,1);
   SSVAL(outbuf,smb_vwv5,raw); /* readbraw and/or writebraw */
@@ -2328,32 +2732,72 @@ int reply_lanman2(char *outbuf)
   return (smb_len(outbuf)+4);
 }
 
+
 /****************************************************************************
 reply for the nt protocol
 ****************************************************************************/
 int reply_nt1(char *outbuf)
 {
-  int capabilities=0x300; /* has dual names + lock_and_read */
+  /* dual names + lock_and_read + nt SMBs + remote API calls */
+  int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ;
+/*
+  other valid capabilities which we may support at some time...
+                     CAP_LARGE_FILES|CAP_NT_SMBS|CAP_RPC_REMOTE_APIS;
+                     CAP_LARGE_FILES|CAP_LARGE_READX|
+                     CAP_STATUS32|CAP_LEVEL_II_OPLOCKS;
+ */
+
   int secword=0;
   BOOL doencrypt = SMBENCRYPT();
   time_t t = time(NULL);
+  int data_len;
+  int encrypt_len;
+  char challenge_len = 8;
+  /* We need to save and restore this as it can be destroyed
+     if we call another server if security=server
+     Thanks to Paul Nelson @ Thursby for pointing this out.
+   */
+  uint16 mid = SVAL(outbuf, smb_mid);
+
+  if (lp_readraw() && lp_writeraw())
+  {
+    capabilities |= CAP_RAW_MODE;
+  }
 
   if (lp_security()>=SEC_USER) secword |= 1;
   if (doencrypt) secword |= 2;
 
-  set_message(outbuf,17,doencrypt?8:0,True);
+  /* decide where (if) to put the encryption challenge, and
+     follow it with the OEM'd domain name
+   */
+  encrypt_len = doencrypt?challenge_len:0;
+#if UNICODE
+  data_len = encrypt_len + 2*(strlen(myworkgroup)+1);
+#else
+  data_len = encrypt_len + strlen(myworkgroup) + 1;
+#endif
+
+  set_message(outbuf,17,data_len,True);
+
+#if UNICODE
+  /* put the OEM'd domain name */
+  PutUniCode(smb_buf(outbuf)+encrypt_len,myworkgroup);
+#else
+  strcpy(smb_buf(outbuf)+encrypt_len, myworkgroup);
+#endif
+
   CVAL(outbuf,smb_vwv1) = secword;
 #ifdef SMB_PASSWD
   /* Create a token value and add it to the outgoing packet. */
-  if (doencrypt) {
+  if (doencrypt)
+  {
     generate_next_challenge(smb_buf(outbuf));
+
     /* Tell the nt machine how long the challenge is. */
-    SSVALS(outbuf,smb_vwv16+1,8);
+    SSVALS(outbuf,smb_vwv16+1,challenge_len);
   }
 #endif
 
-  SIVAL(outbuf,smb_vwv7+1,getpid()); /* session key */
-
   Protocol = PROTOCOL_NT1;
 
   if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) {
@@ -2363,21 +2807,20 @@ int reply_nt1(char *outbuf)
 #endif
   }
 
-  if (lp_readraw() && lp_writeraw())
-    capabilities |= 1;
-
+  SSVAL(outbuf,smb_mid,mid); /* Restore possibly corrupted mid */
   SSVAL(outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */
   SSVAL(outbuf,smb_vwv2+1,1); /* num vcs */
-  SIVAL(outbuf,smb_vwv3+1,0xFFFF); /* max buffer */
-  SIVAL(outbuf,smb_vwv5+1,0xFFFF); /* raw size */
+  SIVAL(outbuf,smb_vwv3+1,0xffff); /* max buffer. LOTS! */
+  SIVAL(outbuf,smb_vwv5+1,0xffff); /* raw size. LOTS! */
+  SIVAL(outbuf,smb_vwv7+1,getpid()); /* session key */
   SIVAL(outbuf,smb_vwv9+1,capabilities); /* capabilities */
   put_long_date(outbuf+smb_vwv11+1,t);
   SSVALS(outbuf,smb_vwv15+1,TimeDiff(t)/60);
+  SSVAL(outbuf,smb_vwv17,data_len); /* length of challenge+domain strings */
 
   return (smb_len(outbuf)+4);
 }
 
-
 /* these are the protocol lists used for auto architecture detection:
 
 WinNT 3.51:
@@ -2565,41 +3008,6 @@ static int reply_negprot(char *inbuf,char *outbuf)
 }
 
 
-/****************************************************************************
-  parse a connect packet
-****************************************************************************/
-void parse_connect(char *buf,char *service,char *user,char *password,int *pwlen,char *dev)
-{
-  char *p = smb_buf(buf) + 1;
-  char *p2;
-
-  DEBUG(4,("parsing connect string %s\n",p));
-    
-  p2 = strrchr(p,'\\');
-  if (p2 == NULL)
-    strcpy(service,p);
-  else
-    strcpy(service,p2+1);
-  
-  p += strlen(p) + 2;
-  
-  strcpy(password,p);
-  *pwlen = strlen(password);
-
-  p += strlen(p) + 2;
-
-  strcpy(dev,p);
-  
-  *user = 0;
-  p = strchr(service,'%');
-  if (p != NULL)
-    {
-      *p = 0;
-      strcpy(user,p+1);
-    }
-}
-
-
 /****************************************************************************
 close all open files for a connection
 ****************************************************************************/
@@ -2617,10 +3025,8 @@ static void close_open_files(int cnum)
 /****************************************************************************
 close a cnum
 ****************************************************************************/
-void close_cnum(int cnum, int uid)
+void close_cnum(int cnum, uint16 vuid)
 {
-  extern struct from_host Client_info;
-
   DirCacheFlush(SNUM(cnum));
 
   unbecome_user();
@@ -2633,7 +3039,7 @@ void close_cnum(int cnum, int uid)
 
   DEBUG(IS_IPC(cnum)?3:1,("%s %s (%s) closed connection to service %s\n",
                          timestring(),
-                         Client_info.name,Client_info.addr,
+                         remote_machine,client_addr(),
                          lp_servicename(SNUM(cnum))));
 
   yield_connection(cnum,
@@ -2647,12 +3053,12 @@ void close_cnum(int cnum, int uid)
   dptr_closecnum(cnum);
 
   /* execute any "postexec = " line */
-  if (*lp_postexec(SNUM(cnum)) && become_user(cnum,uid))
+  if (*lp_postexec(SNUM(cnum)) && become_user(cnum,vuid))
     {
       pstring cmd;
       strcpy(cmd,lp_postexec(SNUM(cnum)));
       standard_sub(cnum,cmd);
-      smbrun(cmd,NULL);
+      smbrun(cmd,NULL,False);
       unbecome_user();
     }
 
@@ -2663,7 +3069,7 @@ void close_cnum(int cnum, int uid)
       pstring cmd;
       strcpy(cmd,lp_rootpostexec(SNUM(cnum)));
       standard_sub(cnum,cmd);
-      smbrun(cmd,NULL);
+      smbrun(cmd,NULL,False);
     }
 
   Connections[cnum].open = False;
@@ -2787,8 +3193,10 @@ BOOL claim_connection(int cnum,char *name,int max_connections,BOOL Clear)
 
   if (!file_exist(fname,NULL))
     {
+      int oldmask = umask(022);
       f = fopen(fname,"w");
       if (f) fclose(f);
+      umask(oldmask);
     }
 
   total_recs = file_size(fname) / sizeof(crec);
@@ -2845,11 +3253,8 @@ BOOL claim_connection(int cnum,char *name,int max_connections,BOOL Clear)
   StrnCpy(crec.name,lp_servicename(snum),sizeof(crec.name)-1);
   crec.start = time(NULL);
 
-  {
-    extern struct from_host Client_info;
-    StrnCpy(crec.machine,Client_info.name,sizeof(crec.machine)-1);
-    StrnCpy(crec.addr,Client_info.addr,sizeof(crec.addr)-1);
-  }
+  StrnCpy(crec.machine,remote_machine,sizeof(crec.machine)-1);
+  StrnCpy(crec.addr,client_addr(),sizeof(crec.addr)-1);
   
   /* make our mark */
   if (fseek(f,foundi*sizeof(crec),SEEK_SET) != 0 ||
@@ -2931,6 +3336,11 @@ void exit_server(char *reason)
     if (dump_core()) return;
 #endif
   }    
+
+#ifdef FAST_SHARE_MODES
+  stop_share_mode_mgmt();
+#endif /* FAST_SHARE_MODES */
+
   DEBUG(3,("%s Server exit  (%s)\n",timestring(),reason?reason:""));
   exit(0);
 }
@@ -2997,7 +3407,7 @@ struct smb_message_struct
    {SMBecho,"SMBecho",reply_echo,0},
    {SMBsesssetupX,"SMBsesssetupX",reply_sesssetup_and_X,0},
    {SMBtconX,"SMBtconX",reply_tcon_and_X,0},
-   {SMBulogoffX, "SMBulogoffX", reply_ulogoffX, 0}, 
+   {SMBulogoffX, "SMBulogoffX", reply_ulogoffX, 0}, /* ulogoff doesn't give a valid TID */
    {SMBgetatr,"SMBgetatr",reply_getatr,AS_USER},
    {SMBsetatr,"SMBsetatr",reply_setatr,AS_USER | NEED_WRITE},
    {SMBchkpth,"SMBchkpth",reply_chkpth,AS_USER},
@@ -3026,7 +3436,7 @@ struct smb_message_struct
    {SMBctemp,"SMBctemp",reply_ctemp,AS_USER},
    {SMBsplopen,"SMBsplopen",reply_printopen,AS_USER},
    {SMBsplclose,"SMBsplclose",reply_printclose,AS_USER},
-   {SMBsplretq,"SMBsplretq",reply_printqueue,AS_USER},
+   {SMBsplretq,"SMBsplretq",reply_printqueue,AS_USER|AS_GUEST},
    {SMBsplwr,"SMBsplwr",reply_printwrite,AS_USER},
    {SMBlock,"SMBlock",reply_lock,AS_USER},
    {SMBunlock,"SMBunlock",reply_unlock,AS_USER},
@@ -3152,15 +3562,24 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize
        {
          int cnum = SVAL(inbuf,smb_tid);
          int flags = smb_messages[match].flags;
-         int uid = SVAL(inbuf,smb_uid);
+         uint16 session_tag = SVAL(inbuf,smb_uid);
 
          /* does this protocol need to be run as root? */
          if (!(flags & AS_USER))
            unbecome_user();
 
          /* does this protocol need to be run as the connected user? */
-         if ((flags & AS_USER) && !become_user(cnum,uid))
-           return(ERROR(ERRSRV,ERRinvnid));
+         if ((flags & AS_USER) && !become_user(cnum,session_tag)) {
+           if (flags & AS_GUEST) 
+             flags &= ~AS_USER;
+           else
+             return(ERROR(ERRSRV,ERRinvnid));
+         }
+         /* this code is to work around a bug is MS client 3 without
+            introducing a security hole - it needs to be able to do
+            print queue checks as guest if it isn't logged in properly */
+         if (flags & AS_USER)
+           flags &= ~AS_GUEST;
 
          /* does it need write permission? */
          if ((flags & NEED_WRITE) && !CAN_WRITE(cnum))
@@ -3212,103 +3631,99 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize
 
 
 /****************************************************************************
-construct a chained reply and add it to the already made reply
-
-inbuf points to the original message start.
-inbuf2 points to the smb_wct part of the secondary message
-type is the type of the secondary message
-outbuf points to the original outbuffer
-outbuf2 points to the smb_wct field of the new outbuffer
-size is the total length of the incoming message (from inbuf1)
-bufsize is the total buffer size
-
-return how many bytes were added to the response
-****************************************************************************/
-int chain_reply(int type,char *inbuf,char *inbuf2,char *outbuf,char *outbuf2,int size,int bufsize)
+  construct a chained reply and add it to the already made reply
+  **************************************************************************/
+int chain_reply(char *inbuf,char *outbuf,int size,int bufsize)
 {
-  int outsize = 0;
-  char *ibuf,*obuf;
-  static BOOL in_chain = False;
-  static char *last_outbuf=NULL;
-  BOOL was_inchain = in_chain;
-  int insize_remaining;
-  static int insize_deleted;
-
-  chain_size += PTR_DIFF(outbuf2,outbuf) - smb_wct;
-  if (was_inchain)
-    outbuf = last_outbuf;
-  else
-    insize_deleted = 0;
+  static char *orig_inbuf;
+  static char *orig_outbuf;
+  int smb_com1, smb_com2 = CVAL(inbuf,smb_vwv0);
+  unsigned smb_off2 = SVAL(inbuf,smb_vwv1);
+  char *inbuf2, *outbuf2;
+  int outsize2;
+  char inbuf_saved[smb_wct];
+  char outbuf_saved[smb_wct];
+  extern int chain_size;
+  int wct = CVAL(outbuf,smb_wct);
+  int outsize = smb_size + 2*wct + SVAL(outbuf,smb_vwv0+2*wct);
+
+  /* maybe its not chained */
+  if (smb_com2 == 0xFF) {
+    CVAL(outbuf,smb_vwv0) = 0xFF;
+    return outsize;
+  }
 
+  if (chain_size == 0) {
+    /* this is the first part of the chain */
+    orig_inbuf = inbuf;
+    orig_outbuf = outbuf;
+  }
 
-  insize_deleted = 0;
-  inbuf2 -= insize_deleted;
-  insize_remaining = size - PTR_DIFF(inbuf2,inbuf);
-  insize_deleted += size - (insize_remaining + smb_wct);
+  /* we need to tell the client where the next part of the reply will be */
+  SSVAL(outbuf,smb_vwv1,smb_offset(outbuf+outsize,outbuf));
+  CVAL(outbuf,smb_vwv0) = smb_com2;
 
-  in_chain = True;
-  last_outbuf = outbuf;
+  /* remember how much the caller added to the chain, only counting stuff
+     after the parameter words */
+  chain_size += outsize - smb_wct;
 
+  /* work out pointers into the original packets. The
+     headers on these need to be filled in */
+  inbuf2 = orig_inbuf + smb_off2 + 4 - smb_wct;
+  outbuf2 = orig_outbuf + SVAL(outbuf,smb_vwv1) + 4 - smb_wct;
 
-  /* allocate some space for the in and out buffers of the chained message */
-  ibuf = (char *)malloc(size + SAFETY_MARGIN);
-  obuf = (char *)malloc(bufsize + SAFETY_MARGIN);
+  /* remember the original command type */
+  smb_com1 = CVAL(orig_inbuf,smb_com);
 
-  if (!ibuf || !obuf)
-    {
-      DEBUG(0,("Out of memory in chain reply\n"));
-      return(ERROR(ERRSRV,ERRnoresource));
-    }
+  /* save the data which will be overwritten by the new headers */
+  memcpy(inbuf_saved,inbuf2,smb_wct);
+  memcpy(outbuf_saved,outbuf2,smb_wct);
 
-  ibuf += SMB_ALIGNMENT;
-  obuf += SMB_ALIGNMENT;
+  /* give the new packet the same header as the last part of the SMB */
+  memmove(inbuf2,inbuf,smb_wct);
 
   /* create the in buffer */
-  memcpy(ibuf,inbuf,smb_wct);
-  memcpy(ibuf+smb_wct,inbuf2,insize_remaining);
-  CVAL(ibuf,smb_com) = type;
+  CVAL(inbuf2,smb_com) = smb_com2;
 
   /* create the out buffer */
-  bzero(obuf,smb_size);
-
-  set_message(obuf,0,0,True);
-  CVAL(obuf,smb_com) = CVAL(ibuf,smb_com);
+  bzero(outbuf2,smb_size);
+  set_message(outbuf2,0,0,True);
+  CVAL(outbuf2,smb_com) = CVAL(inbuf2,smb_com);
   
-  memcpy(obuf+4,ibuf+4,4);
-  CVAL(obuf,smb_rcls) = SUCCESS;
-  CVAL(obuf,smb_reh) = 0;
-  CVAL(obuf,smb_flg) = 0x80 | (CVAL(ibuf,smb_flg) & 0x8); /* bit 7 set 
-                                                            means a reply */
-  SSVAL(obuf,smb_flg2,1); /* say we support long filenames */
-  SSVAL(obuf,smb_err,SUCCESS);
-  SSVAL(obuf,smb_tid,SVAL(inbuf,smb_tid));
-  SSVAL(obuf,smb_pid,SVAL(inbuf,smb_pid));
-  SSVAL(obuf,smb_uid,SVAL(inbuf,smb_uid));
-  SSVAL(obuf,smb_mid,SVAL(inbuf,smb_mid));
+  memcpy(outbuf2+4,inbuf2+4,4);
+  CVAL(outbuf2,smb_rcls) = SUCCESS;
+  CVAL(outbuf2,smb_reh) = 0;
+  CVAL(outbuf2,smb_flg) = 0x80 | (CVAL(inbuf2,smb_flg) & 0x8); /* bit 7 set 
+                                                                 means a reply */
+  SSVAL(outbuf2,smb_flg2,1); /* say we support long filenames */
+  SSVAL(outbuf2,smb_err,SUCCESS);
+  SSVAL(outbuf2,smb_tid,SVAL(inbuf2,smb_tid));
+  SSVAL(outbuf2,smb_pid,SVAL(inbuf2,smb_pid));
+  SSVAL(outbuf2,smb_uid,SVAL(inbuf2,smb_uid));
+  SSVAL(outbuf2,smb_mid,SVAL(inbuf2,smb_mid));
 
   DEBUG(3,("Chained message\n"));
-  show_msg(ibuf);
+  show_msg(inbuf2);
 
   /* process the request */
-  outsize = switch_message(type,ibuf,obuf,smb_wct+insize_remaining,
-                          bufsize-chain_size);
-
-  /* copy the new reply header over the old one, but preserve 
-     the smb_com field */
-  memcpy(outbuf+smb_com+1,obuf+smb_com+1,smb_wct-(smb_com+1));
-
-  /* and copy the data from the reply to the right spot */
-  memcpy(outbuf2,obuf+smb_wct,outsize - smb_wct);
+  outsize2 = switch_message(smb_com2,inbuf2,outbuf2,size-chain_size,
+                           bufsize-chain_size);
 
-  /* free the allocated buffers */
-  if (ibuf) free(ibuf-SMB_ALIGNMENT);
-  if (obuf) free(obuf-SMB_ALIGNMENT);
+  /* copy the new reply and request headers over the old ones, but
+     preserve the smb_com field */
+  memmove(orig_outbuf,outbuf2,smb_wct);
+  CVAL(orig_outbuf,smb_com) = smb_com1;
 
-  in_chain = was_inchain;
+  /* restore the saved data, being careful not to overwrite any
+   data from the reply header */
+  memcpy(inbuf2,inbuf_saved,smb_wct);
+  {
+    int ofs = smb_wct - PTR_DIFF(outbuf2,orig_outbuf);
+    if (ofs < 0) ofs = 0;
+    memmove(outbuf2+ofs,outbuf_saved+ofs,smb_wct-ofs);
+  }
 
-  /* return how much extra has been added to the packet */
-  return(outsize - smb_wct);
+  return outsize2;
 }
 
 
@@ -3321,10 +3736,12 @@ int construct_reply(char *inbuf,char *outbuf,int size,int bufsize)
   int type = CVAL(inbuf,smb_com);
   int outsize = 0;
   int msg_type = CVAL(inbuf,0);
+  extern int chain_size;
 
   smb_last_time = time(NULL);
 
   chain_size = 0;
+  chain_fnum = -1;
 
   bzero(outbuf,smb_size);
 
@@ -3348,6 +3765,8 @@ int construct_reply(char *inbuf,char *outbuf,int size,int bufsize)
 
   outsize = switch_message(type,inbuf,outbuf,size,bufsize);
 
+  outsize += chain_size;
+
   if(outsize > 4)
     smb_setlen(outbuf,outsize - 4);
   return(outsize);
@@ -3361,11 +3780,8 @@ static void process(void)
 {
   static int trans_num = 0;
   int nread;
-  extern struct from_host Client_info;
   extern int Client;
 
-  fromhost(Client,&Client_info);
-  
   InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
   OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
   if ((InBuffer == NULL) || (OutBuffer == NULL)) 
@@ -3401,24 +3817,6 @@ static void process(void)
       if (lp_readprediction())
        do_read_prediction();
 
-      {
-       extern pstring share_del_pending;
-       if (*share_del_pending) {
-         unbecome_user();
-         if (!unlink(share_del_pending))
-           DEBUG(3,("Share file deleted %s\n",share_del_pending));
-         else
-           DEBUG(2,("Share del failed of %s\n",share_del_pending));
-         share_del_pending[0] = 0;
-       }
-      }
-
-      if (share_mode_pending) {
-       unbecome_user();
-       check_share_modes();
-       share_mode_pending=False;
-      }
-
       errno = 0;      
 
       for (counter=SMBD_SELECT_LOOP; 
@@ -3450,6 +3848,7 @@ static void process(void)
          if (!(counter%SMBD_RELOAD_CHECK))
            reload_services(True);
 
+#if 0 /* JRA */
          /* check the share modes every 10 secs */
          if (!(counter%SHARE_MODES_CHECK))
            check_share_modes();
@@ -3457,6 +3856,7 @@ static void process(void)
          /* clean the share modes every 5 minutes */
          if (!(counter%SHARE_MODES_CLEAN))
            clean_share_modes();
+#endif /* JRA */
 
          /* automatic timeout if all connections are closed */      
          if (num_connections_open==0 && counter >= IDLE_CLOSED_TIMEOUT) {
@@ -3519,7 +3919,7 @@ static void process(void)
       if (msg_type == 0)
        show_msg(InBuffer);
 
-      nread = construct_reply(InBuffer,OutBuffer,nread,maxxmit);
+      nread = construct_reply(InBuffer,OutBuffer,nread,max_send);
       
       if(nread > 0) {
         if (CVAL(OutBuffer,0) == 0)
@@ -3563,6 +3963,19 @@ static void init_structs(void )
     {
       Files[i].open = False;
       string_init(&Files[i].name,"");
+
+    }
+
+  for (i=0;i<MAX_OPEN_FILES;i++)
+    {
+      file_fd_struct *fd_ptr = &FileFd[i];
+      fd_ptr->ref_count = 0;
+      fd_ptr->dev = (int32)-1;
+      fd_ptr->inode = (int32)-1;
+      fd_ptr->fd = -1;
+      fd_ptr->fd_readonly = -1;
+      fd_ptr->fd_writeonly = -1;
+      fd_ptr->real_open_flags = -1;
     }
 
   init_dptrs();
@@ -3599,6 +4012,7 @@ static void usage(char *pname)
   int port = SMB_PORT;
   int opt;
   extern char *optarg;
+  char pidFile[100] = { 0 };
 
 #ifdef NEED_AUTH_PARAMETERS
   set_auth_parameters(argc,argv);
@@ -3630,8 +4044,13 @@ static void usage(char *pname)
 #endif
 
   fault_setup(exit_server);
+  signal(SIGTERM , SIGNAL_CAST dflt_sig);
 
-  umask(0777 & ~DEF_CREATE_MASK);
+  /* we want total control over the permissions on created files,
+     so set our umask to 0 */
+  umask(0);
+
+  GetWd(OriginalDir);
 
   init_uid();
 
@@ -3642,9 +4061,12 @@ static void usage(char *pname)
       argc--;
     }
 
-  while ((opt = getopt(argc, argv, "O:i:l:s:d:Dp:hPa")) != EOF)
+  while ((opt = getopt(argc, argv, "O:i:l:s:d:Dp:hPaf:")) != EOF)
     switch (opt)
       {
+      case 'f':
+        strncpy(pidFile, optarg, sizeof(pidFile));
+        break;
       case 'O':
        strcpy(user_socket_options,optarg);
        break;
@@ -3723,6 +4145,8 @@ static void usage(char *pname)
   if (!reload_services(False))
     return(-1);        
 
+  strcpy(myworkgroup, lp_workgroup());
+
 #ifndef NO_SIGNAL_TEST
   signal(SIGHUP,SIGNAL_CAST sig_hup);
 #endif
@@ -3741,18 +4165,43 @@ static void usage(char *pname)
       become_daemon();
     }
 
+  if (*pidFile)
+    {
+      int     fd;
+      char    buf[20];
+
+      if ((fd = open(pidFile,
+         O_NONBLOCK | O_CREAT | O_WRONLY | O_TRUNC, 0644)) < 0)
+        {
+           DEBUG(0,("ERROR: can't open %s: %s\n", pidFile, strerror(errno)));
+           exit(1);
+        }
+      if(fcntl_lock(fd,F_SETLK,0,1,F_WRLCK)==False)
+        {
+          DEBUG(0,("ERROR: smbd is already running\n"));
+          exit(1);
+        }
+      sprintf(buf, "%u\n", (unsigned int) getpid());
+      if (write(fd, buf, strlen(buf)) < 0)
+        {
+          DEBUG(0,("ERROR: can't write to %s: %s\n", pidFile, strerror(errno)));
+          exit(1);
+        }
+      /* Leave pid file open & locked for the duration... */
+    }
+
   if (!open_sockets(is_daemon,port))
     exit(1);
 
 #ifdef FAST_SHARE_MODES
   if (!start_share_mode_mgmt())
     exit(1);
-#endif
+#endif /* FAST_SHARE_MODES */
 
   /* possibly reload the services file. */
   reload_services(True);
 
-  maxxmit = MIN(lp_maxxmit(),BUFFER_SIZE);
+  max_recv = MIN(lp_maxxmit(),BUFFER_SIZE);
 
   if (*lp_rootdir())
     {
@@ -3763,10 +4212,6 @@ static void usage(char *pname)
   process();
   close_sockets();
 
-#ifdef FAST_SHARE_MODES
-  stop_share_mode_mgmt();
-#endif
-
   exit_server("normal exit");
   return(0);
 }