Modified Files:
[samba.git] / source3 / smbd / server.c
index 299ae07aa30330c60764cd95194a5769ef704e49..908cf984b8e4a0b822514bdb55f52a62a4af682e 100644 (file)
@@ -48,7 +48,7 @@ extern BOOL case_preserve;
 extern BOOL use_mangled_map;
 extern BOOL short_case_preserve;
 extern BOOL case_mangle;
-extern time_t smb_last_time;
+time_t smb_last_time=(time_t)0;
 
 extern int smb_read_error;
 
@@ -84,9 +84,17 @@ int chain_fnum = -1;
 /* number of open connections */
 static int num_connections_open = 0;
 
+/* Oplock ipc UDP socket. */
+int oplock_sock = -1;
+uint16 oplock_port = 0;
+/* Current number of oplocks we have outstanding. */
+int32 global_oplocks_open = 0;
+
+BOOL global_oplock_break = False;
+
 extern fstring remote_machine;
 
-pstring OriginalDir;
+extern pstring OriginalDir;
 
 /* these can be set by some functions to override the error codes */
 int unix_ERR_class=SUCCESS;
@@ -130,8 +138,12 @@ void  killkids(void)
          dos archive is represented in unix by the user's execute bit
          dos system is represented in unix by the group's execute bit
          dos hidden is represented in unix by the other's execute bit
+         Then apply create mask,
+         then add force bits.
     base permission for directories:
          dos directory is represented in unix by unix's dir bit and the exec bit
+         Then apply create mask,
+         then add force bits.
 ****************************************************************************/
 mode_t unix_mode(int cnum,int dosmode)
 {
@@ -141,8 +153,13 @@ mode_t unix_mode(int cnum,int dosmode)
     result |= (S_IWUSR | S_IWGRP | S_IWOTH);
  
   if (IS_DOS_DIR(dosmode)) {
+    /* We never make directories read only for the owner as under DOS a user
+       can always create a file in a read-only directory. */
     result |= (S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH | S_IWUSR);
-    result &= (lp_dir_mode(SNUM(cnum)) | 0700);
+    /* Apply directory mask */
+    result &= lp_dir_mode(SNUM(cnum));
+    /* Add in force bits */
+    result |= lp_force_dir_mode(SNUM(cnum));
   } else { 
     if (MAP_ARCHIVE(cnum) && IS_DOS_ARCHIVE(dosmode))
       result |= S_IXUSR;
@@ -153,7 +170,10 @@ mode_t unix_mode(int cnum,int dosmode)
     if (MAP_HIDDEN(cnum) && IS_DOS_HIDDEN(dosmode))
       result |= S_IXOTH;  
  
-    result &= CREATE_MODE(cnum);
+    /* Apply mode mask */
+    result &= lp_create_mode(SNUM(cnum));
+    /* Add in force bits */
+    result |= lp_force_create_mode(SNUM(cnum));
   }
   return(result);
 }
@@ -167,6 +187,8 @@ int dos_mode(int cnum,char *path,struct stat *sbuf)
   int result = 0;
   extern struct current_user current_user;
 
+  DEBUG(8,("dos_mode: %d %s\n", cnum, path));
+
   if (CAN_WRITE(cnum) && !lp_alternate_permissions(SNUM(cnum))) {
     if (!((sbuf->st_mode & S_IWOTH) ||
          Connections[cnum].admin_user ||
@@ -180,7 +202,7 @@ int dos_mode(int cnum,char *path,struct stat *sbuf)
       result |= aRONLY;
   }
 
-  if ((sbuf->st_mode & S_IXUSR) != 0)
+  if (MAP_ARCHIVE(cnum) && ((sbuf->st_mode & S_IXUSR) != 0))
     result |= aARCH;
 
   if (MAP_SYSTEM(cnum) && ((sbuf->st_mode & S_IXGRP) != 0))
@@ -192,9 +214,11 @@ int dos_mode(int cnum,char *path,struct stat *sbuf)
   if (S_ISDIR(sbuf->st_mode))
     result = aDIR | (result & aRONLY);
 
+#ifdef S_ISLNK
 #if LINKS_READ_ONLY
   if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
     result |= aRONLY;
+#endif
 #endif
 
   /* hide files with a name starting with a . */
@@ -210,10 +234,26 @@ int dos_mode(int cnum,char *path,struct stat *sbuf)
        result |= aHIDDEN;
     }
 
+  /* Optimization : Only call is_hidden_path if it's not already
+     hidden. */
+  if (!(result & aHIDDEN) && IS_HIDDEN_PATH(cnum,path))
+  {
+    result |= aHIDDEN;
+  }
+
+  DEBUG(8,("dos_mode returning "));
+
+  if (result & aHIDDEN) DEBUG(8, ("h"));
+  if (result & aRONLY ) DEBUG(8, ("r"));
+  if (result & aSYSTEM) DEBUG(8, ("s"));
+  if (result & aDIR   ) DEBUG(8, ("d"));
+  if (result & aARCH  ) DEBUG(8, ("a"));
+
+  DEBUG(8,("\n"));
+
   return(result);
 }
 
-
 /*******************************************************************
 chmod a file - but preserve some bits
 ********************************************************************/
@@ -267,6 +307,73 @@ int dos_chmod(int cnum,char *fname,int dosmode,struct stat *st)
   return(sys_chmod(fname,unixmode));
 }
 
+/*******************************************************************
+Wrapper around sys_utime that possibly allows DOS semantics rather
+than POSIX.
+*******************************************************************/
+
+int file_utime(int cnum, char *fname, struct utimbuf *times)
+{
+  extern struct current_user current_user;
+  struct stat sb;
+  int ret = -1;
+
+  errno = 0;
+
+  if(sys_utime(fname, times) == 0)
+    return 0;
+
+  if((errno != EPERM) && (errno != EACCES))
+    return -1;
+
+  if(!lp_dos_filetimes(SNUM(cnum)))
+    return -1;
+
+  /* We have permission (given by the Samba admin) to
+     break POSIX semantics and allow a user to change
+     the time on a file they don't own but can write to
+     (as DOS does).
+   */
+
+  if(sys_stat(fname,&sb) != 0)
+    return -1;
+
+  /* Check if we have write access. */
+  if (CAN_WRITE(cnum)) {
+         if (((sb.st_mode & S_IWOTH) ||
+              Connections[cnum].admin_user ||
+              ((sb.st_mode & S_IWUSR) && current_user.uid==sb.st_uid) ||
+              ((sb.st_mode & S_IWGRP) &&
+               in_group(sb.st_gid,current_user.gid,
+                        current_user.ngroups,current_user.igroups)))) {
+                 /* We are allowed to become root and change the filetime. */
+                 become_root(False);
+                 ret = sys_utime(fname, times);
+                 unbecome_root(False);
+         }
+  }
+
+  return ret;
+}
+  
+/*******************************************************************
+Change a filetime - possibly allowing DOS semantics.
+*******************************************************************/
+
+BOOL set_filetime(int cnum, char *fname, time_t mtime)
+{
+  struct utimbuf times;
+
+  if (null_mtime(mtime)) return(True);
+
+  times.modtime = times.actime = mtime;
+
+  if (file_utime(cnum, fname, &times)) {
+    DEBUG(4,("set_filetime(%s) failed: %s\n",fname,strerror(errno)));
+  }
+  
+  return(True);
+} 
 
 /****************************************************************************
 check if two filenames are equal
@@ -327,7 +434,7 @@ scan a directory to find a filename, matching without case sensitivity
 
 If the name looks like a mangled name then try via the mangling functions
 ****************************************************************************/
-static BOOL scan_directory(char *path, char *name,int snum,BOOL docache)
+static BOOL scan_directory(char *path, char *name,int cnum,BOOL docache)
 {
   void *cur_dir;
   char *dname;
@@ -340,7 +447,7 @@ static BOOL scan_directory(char *path, char *name,int snum,BOOL docache)
   if (*path == 0)
     path = ".";
 
-  if (docache && (dname = DirCacheCheck(path,name,snum))) {
+  if (docache && (dname = DirCacheCheck(path,name,SNUM(cnum)))) {
     strcpy(name, dname);       
     return(True);
   }      
@@ -349,7 +456,7 @@ static BOOL scan_directory(char *path, char *name,int snum,BOOL docache)
     check_mangled_stack(name);
 
   /* open the directory */
-  if (!(cur_dir = OpenDir(path))) 
+  if (!(cur_dir = OpenDir(cnum, path, True))) 
     {
       DEBUG(3,("scan dir didn't open dir [%s]\n",path));
       return(False);
@@ -362,14 +469,14 @@ static BOOL scan_directory(char *path, char *name,int snum,BOOL docache)
          (strequal(dname,".") || strequal(dname,"..")))
        continue;
 
-      strcpy(name2,dname);
-      if (!name_map_mangle(name2,False,snum)) continue;
+      pstrcpy(name2,dname);
+      if (!name_map_mangle(name2,False,SNUM(cnum))) continue;
 
       if ((mangled && mangled_equal(name,name2))
-         || fname_equal(name, name2))
+         || fname_equal(name, name2)) /* name2 here was changed to dname - since 1.9.16p2 - not sure of reason (jra) */
        {
          /* we've found the file, change it's name and return */
-         if (docache) DirCacheAdd(path,name,dname,snum);
+         if (docache) DirCacheAdd(path,name,dname,SNUM(cnum));
          strcpy(name, dname);
          CloseDir(cur_dir);
          return(True);
@@ -395,14 +502,22 @@ 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.
+
+The bad_path arg is set to True if the filename walk failed. This is
+used to pick the correct error code to return between ENOENT and ENOTDIR
+as Windows applications depend on ERRbadpath being returned if a component
+of a pathname does not exist.
 ****************************************************************************/
-BOOL unix_convert(char *name,int cnum,pstring saved_last_component)
+BOOL unix_convert(char *name,int cnum,pstring saved_last_component, BOOL *bad_path)
 {
   struct stat st;
   char *start, *end;
   pstring dirpath;
+  int saved_errno;
 
   *dirpath = 0;
+  *bad_path = False;
+
   if(saved_last_component)
     *saved_last_component = 0;
 
@@ -449,12 +564,14 @@ BOOL unix_convert(char *name,int cnum,pstring saved_last_component)
   if (sys_stat(name,&st) == 0)
     return(True);
 
+  saved_errno = errno;
+
   DEBUG(5,("unix_convert(%s,%d)\n",name,cnum));
 
   /* a special case - if we don't have any mangling chars and are case
      sensitive then searching won't help */
   if (case_sensitive && !is_mangled(name) && 
-      !lp_strip_dot() && !use_mangled_map)
+      !lp_strip_dot() && !use_mangled_map && (saved_errno != ENOENT))
     return(False);
 
   /* now we need to recursively match the name against the real 
@@ -475,7 +592,7 @@ BOOL unix_convert(char *name,int cnum,pstring saved_last_component)
       if (end)         *end = 0;
 
       if(saved_last_component != 0)
-       strcpy(saved_last_component, end ? end + 1 : start);
+        strcpy(saved_last_component, end ? end + 1 : start);
 
       /* check if the name exists up to this point */
       if (sys_stat(name, &st) == 0) 
@@ -498,17 +615,24 @@ BOOL unix_convert(char *name,int cnum,pstring saved_last_component)
 
          /* remember the rest of the pathname so it can be restored
             later */
-         if (end) strcpy(rest,end+1);
+         if (end) pstrcpy(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))
+             !scan_directory(dirpath, start, cnum, end?True:False))
            {
              if (end) 
                {
                  /* an intermediate part of the name can't be found */
                  DEBUG(5,("Intermediate not found %s\n",start));
                  *end = '/';
+                  /* We need to return the fact that the intermediate
+                     name resolution failed. This is used to return an
+                     error of ERRbadpath rather than ERRbadfile. Some
+                     Windows applications depend on the difference between
+                     these two errors.
+                   */
+                  *bad_path = True;
                  return(False);
                }
              
@@ -591,6 +715,14 @@ static void disk_norm(int *bsize,int *dfree,int *dsize)
 int disk_free(char *path,int *bsize,int *dfree,int *dsize)
 {
   char *df_command = lp_dfree_command();
+  int dfree_retval;
+#ifdef QUOTAS
+  int dfreeq_retval;
+  int dfreeq = 0;
+  int bsizeq = *bsize;
+  int dsizeq = *dsize;
+#endif
+
 #ifndef NO_STATFS
 #ifdef USE_STATVFS
   struct statvfs fs;
@@ -603,15 +735,6 @@ int disk_free(char *path,int *bsize,int *dfree,int *dsize)
 #endif
 #endif
 
-#ifdef QUOTAS
-  if (disk_quotas(path, bsize, dfree, dsize))
-    {
-      disk_norm(bsize,dfree,dsize);
-      return(((*bsize)/1024)*(*dfree));
-    }
-#endif
-
-
   /* possibly use system() to get the result */
   if (df_command && *df_command)
     {
@@ -627,22 +750,50 @@ int disk_free(char *path,int *bsize,int *dfree,int *dsize)
       DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
          
       {
-       FILE *f = fopen(outfile,"r");   
-       *dsize = 0;
-       *dfree = 0;
-       *bsize = 1024;
-       if (f)
-         {
-           fscanf(f,"%d %d %d",dsize,dfree,bsize);
-           fclose(f);
-         }
-       else
-         DEBUG(0,("Can't open %s\n",outfile));
+        FILE *f = fopen(outfile,"r");  
+        *dsize = 0;
+        *dfree = 0;
+        *bsize = 1024;
+        if (f)
+          {
+            fscanf(f,"%d %d %d",dsize,dfree,bsize);
+            fclose(f);
+          }
+        else
+          DEBUG(0,("Can't open %s\n",outfile));
       }
          
       unlink(outfile);
       disk_norm(bsize,dfree,dsize);
-      return(((*bsize)/1024)*(*dfree));
+      dfree_retval = ((*bsize)/1024)*(*dfree);
+#ifdef QUOTAS
+      /* Ensure we return the min value between the users quota and
+         what's free on the disk. Thanks to Albrecht Gebhardt 
+         <albrecht.gebhardt@uni-klu.ac.at> for this fix.
+      */
+      if (disk_quotas(path, &bsizeq, &dfreeq, &dsizeq))
+        {
+          disk_norm(&bsizeq, &dfreeq, &dsizeq);
+          dfreeq_retval = ((bsizeq)/1024)*(dfreeq);
+          dfree_retval =  ( dfree_retval < dfreeq_retval ) ? 
+                           dfree_retval : dfreeq_retval ;
+          /* maybe dfree and dfreeq are calculated using different bsizes 
+             so convert dfree from bsize into bsizeq */
+          /* avoid overflows due to multiplication, so do not:
+                *dfree = ((*dfree) * (*bsize)) / (bsizeq); 
+             bsize and bsizeq are powers of 2 so its better to
+             to divide them getting a multiplication or division factor
+             for dfree. Rene Nieuwenhuizen (07-10-1997) */
+          if (*bsize >= bsizeq) 
+            *dfree = *dfree * (*bsize / bsizeq);
+          else 
+            *dfree = *dfree / (bsizeq / *bsize);
+          *dfree = ( *dfree < dfreeq ) ? *dfree : dfreeq ; 
+          *bsize = bsizeq;
+          *dsize = dsizeq;
+        }
+#endif
+      return(dfree_retval);
     }
 
 #ifdef NO_STATFS
@@ -712,7 +863,35 @@ if ((*bsize) < 512 || (*bsize)>0xFFFF) *bsize = 1024;
       *dsize = 20*1024*1024/(*bsize);
       *dfree = MAX(1,*dfree);
     }
-  return(((*bsize)/1024)*(*dfree));
+  dfree_retval = ((*bsize)/1024)*(*dfree);
+#ifdef QUOTAS
+  /* Ensure we return the min value between the users quota and
+     what's free on the disk. Thanks to Albrecht Gebhardt 
+     <albrecht.gebhardt@uni-klu.ac.at> for this fix.
+  */
+  if (disk_quotas(path, &bsizeq, &dfreeq, &dsizeq))
+    {
+      disk_norm(&bsizeq, &dfreeq, &dsizeq);
+      dfreeq_retval = ((bsizeq)/1024)*(dfreeq);
+      dfree_retval = ( dfree_retval < dfreeq_retval ) ? 
+                       dfree_retval : dfreeq_retval ;
+      /* maybe dfree and dfreeq are calculated using different bsizes 
+         so convert dfree from bsize into bsizeq */
+      /* avoid overflows due to multiplication, so do not:
+              *dfree = ((*dfree) * (*bsize)) / (bsizeq); 
+       bsize and bsizeq are powers of 2 so its better to
+       to divide them getting a multiplication or division factor
+       for dfree. Rene Nieuwenhuizen (07-10-1997) */
+      if (*bsize >= bsizeq)
+        *dfree = *dfree * (*bsize / bsizeq);
+      else
+        *dfree = *dfree / (bsizeq / *bsize);
+      *dfree = ( *dfree < dfreeq ) ? *dfree : dfreeq ;
+      *bsize = bsizeq;
+      *dsize = dsizeq;
+    }
+#endif
+  return(dfree_retval);
 #endif
 }
 
@@ -740,13 +919,31 @@ BOOL check_name(char *name,int cnum)
 
   errno = 0;
 
-  if( is_vetoed_path(name)) 
+  if( IS_VETO_PATH(cnum, name)) 
     {
       DEBUG(5,("file path name %s vetoed\n",name));
       return(0);
     }
 
   ret = reduce_name(name,Connections[cnum].connectpath,lp_widelinks(SNUM(cnum)));
+
+  /* Check if we are allowing users to follow symlinks */
+  /* Patch from David Clerc <David.Clerc@cui.unige.ch>
+     University of Geneva */
+
+#ifdef S_ISLNK
+  if (!lp_symlinks(SNUM(cnum)))
+    {
+      struct stat statbuf;
+      if ( (sys_lstat(name,&statbuf) != -1) &&
+          (S_ISLNK(statbuf.st_mode)) )
+        {
+          DEBUG(3,("check_name: denied: file path name %s is a symlink\n",name));
+          ret=0; 
+        }
+    }
+#endif
+
   if (!ret)
     DEBUG(5,("check_name on %s failed\n",name));
 
@@ -773,8 +970,7 @@ 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)
+static int fd_attempt_open(char *fname, int flags, int mode)
 {
   int fd = sys_open(fname,flags,mode);
 
@@ -826,7 +1022,7 @@ int fd_attempt_open(char *fname, int flags, int mode)
 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)
+static file_fd_struct *fd_get_already_open(struct stat *sbuf)
 {
   int i;
   file_fd_struct *fd_ptr;
@@ -853,7 +1049,7 @@ file_fd_struct *fd_get_already_open(struct stat *sbuf)
 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()
+static file_fd_struct *fd_get_new()
 {
   int i;
   file_fd_struct *fd_ptr;
@@ -886,8 +1082,7 @@ n"));
 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)
+static void fd_attempt_reopen(char *fname, int mode, file_fd_struct *fd_ptr)
 {
   int fd = sys_open( fname, O_RDWR, mode);
 
@@ -907,7 +1102,7 @@ void fd_attempt_reopen(char *fname, int mode, file_fd_struct *fd_ptr)
 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)
+static 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],
@@ -943,12 +1138,14 @@ static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct
   pstring fname;
   struct stat statbuf;
   file_fd_struct *fd_ptr;
+  files_struct *fsp = &Files[fnum];
 
-  Files[fnum].open = False;
-  Files[fnum].fd_ptr = 0;
+  fsp->open = False;
+  fsp->fd_ptr = 0;
+  fsp->granted_oplock = False;
   errno = EPERM;
 
-  strcpy(fname,fname1);
+  pstrcpy(fname,fname1);
 
   /* check permissions */
   if ((flags != O_RDONLY) && !CAN_WRITE(cnum) && !Connections[cnum].printer)
@@ -968,13 +1165,6 @@ static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct
     DEBUG(3,("Bug in client? Set O_WRONLY without O_CREAT\n"));
 */
 
-#if UTIME_WORKAROUND
-  /* XXXX - is this OK?? */
-  /* this works around a utime bug but can cause other problems */
-  if ((flags & (O_WRONLY|O_RDWR)) && (flags & O_CREAT) && !(flags & O_APPEND))
-    sys_unlink(fname);
-#endif
-
   /*
    * Ensure we have a valid struct stat so we can search the
    * open fd table.
@@ -1077,13 +1267,13 @@ static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct
     pstring dname;
     int dum1,dum2,dum3;
     char *p;
-    strcpy(dname,fname);
+    pstrcpy(dname,fname);
     p = strrchr(dname,'/');
     if (p) *p = 0;
     if (sys_disk_free(dname,&dum1,&dum2,&dum3) < 
        lp_minprintspace(SNUM(cnum))) {
       fd_attempt_close(fd_ptr);
-      Files[fnum].fd_ptr = 0;
+      fsp->fd_ptr = 0;
       if(fd_ptr->ref_count == 0)
         sys_unlink(fname);
       errno = ENOSPC;
@@ -1119,25 +1309,26 @@ static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct
       fd_ptr->dev = (uint32)sbuf->st_dev;
       fd_ptr->inode = (uint32)sbuf->st_ino;
 
-      Files[fnum].fd_ptr = fd_ptr;
+      fsp->fd_ptr = fd_ptr;
       Connections[cnum].num_files_open++;
-      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;
-      Files[fnum].mmap_ptr = NULL;
-      Files[fnum].mmap_size = 0;
-      Files[fnum].can_lock = True;
-      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].print_file = Connections[cnum].printer;
-      Files[fnum].modified = False;
-      Files[fnum].cnum = cnum;
-      string_set(&Files[fnum].name,dos_to_unix(fname,False));
-      Files[fnum].wbmpx_ptr = NULL;      
+      fsp->mode = sbuf->st_mode;
+      GetTimeOfDay(&fsp->open_time);
+      fsp->uid = current_user.id;
+      fsp->size = 0;
+      fsp->pos = -1;
+      fsp->open = True;
+      fsp->mmap_ptr = NULL;
+      fsp->mmap_size = 0;
+      fsp->can_lock = True;
+      fsp->can_read = ((flags & O_WRONLY)==0);
+      fsp->can_write = ((flags & (O_WRONLY|O_RDWR))!=0);
+      fsp->share_mode = 0;
+      fsp->print_file = Connections[cnum].printer;
+      fsp->modified = False;
+      fsp->granted_oplock = False;
+      fsp->cnum = cnum;
+      string_set(&fsp->name,dos_to_unix(fname,False));
+      fsp->wbmpx_ptr = NULL;      
 
       /*
        * If the printer is marked as postscript output a leading
@@ -1146,8 +1337,8 @@ static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct
        * This has a similar effect as CtrlD=0 in WIN.INI file.
        * tim@fsg.com 09/06/94
        */
-      if (Files[fnum].print_file && POSTSCRIPT(cnum) && 
-         Files[fnum].can_write) 
+      if (fsp->print_file && POSTSCRIPT(cnum) && 
+         fsp->can_write) 
        {
          DEBUG(3,("Writing postscript line\n"));
          write_file(fnum,"%!\n",3);
@@ -1155,23 +1346,23 @@ static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct
       
       DEBUG(2,("%s %s opened file %s read=%s write=%s (numopen=%d fnum=%d)\n",
               timestring(),Connections[cnum].user,fname,
-              BOOLSTR(Files[fnum].can_read),BOOLSTR(Files[fnum].can_write),
+              BOOLSTR(fsp->can_read),BOOLSTR(fsp->can_write),
               Connections[cnum].num_files_open,fnum));
 
     }
 
 #if USE_MMAP
   /* mmap it if read-only */
-  if (!Files[fnum].can_write)
+  if (!fsp->can_write)
     {
-      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_ptr->fd,0);
+      fsp->mmap_size = file_size(fname);
+      fsp->mmap_ptr = (char *)mmap(NULL,fsp->mmap_size,
+                                         PROT_READ,MAP_SHARED,fsp->fd_ptr->fd,0);
 
-      if (Files[fnum].mmap_ptr == (char *)-1 || !Files[fnum].mmap_ptr)
+      if (fsp->mmap_ptr == (char *)-1 || !fsp->mmap_ptr)
        {
          DEBUG(3,("Failed to mmap() %s - %s\n",fname,strerror(errno)));
-         Files[fnum].mmap_ptr = NULL;
+         fsp->mmap_ptr = NULL;
        }
     }
 #endif
@@ -1212,10 +1403,10 @@ static void check_magic(int fnum,int cnum)
     int ret;
     pstring magic_output;
     pstring fname;
-    strcpy(fname,Files[fnum].name);
+    pstrcpy(fname,Files[fnum].name);
 
     if (*lp_magicoutput(SNUM(cnum)))
-      strcpy(magic_output,lp_magicoutput(SNUM(cnum)));
+      pstrcpy(magic_output,lp_magicoutput(SNUM(cnum)));
     else
       sprintf(magic_output,"%s.out",fname);
 
@@ -1229,30 +1420,38 @@ static void check_magic(int fnum,int cnum)
 
 /****************************************************************************
 close a file - possibly invalidating the read prediction
+
+If normal_close is 1 then this came from a normal SMBclose (or equivalent)
+operation otherwise it came as the result of some other operation such as
+the closing of the connection. In the latter case printing and
+magic scripts are not run
 ****************************************************************************/
-void close_file(int fnum)
+void close_file(int fnum, BOOL normal_close)
 {
   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;
+  int token;
 
+#if USE_READ_PREDICTION
   invalidate_read_prediction(fs_p->fd_ptr->fd);
+#endif
+
   fs_p->open = False;
   Connections[cnum].num_files_open--;
   if(fs_p->wbmpx_ptr) 
-    {
-      free((char *)fs_p->wbmpx_ptr);
-      fs_p->wbmpx_ptr = NULL;
-    }
+  {
+    free((char *)fs_p->wbmpx_ptr);
+    fs_p->wbmpx_ptr = NULL;
+  }
 
 #if USE_MMAP
   if(fs_p->mmap_ptr) 
-    {
-      munmap(fs_p->mmap_ptr,fs_p->mmap_size);
-      fs_p->mmap_ptr = NULL;
-    }
+  {
+    munmap(fs_p->mmap_ptr,fs_p->mmap_size);
+    fs_p->mmap_ptr = NULL;
+  }
 #endif
 
   if (lp_share_modes(SNUM(cnum)))
@@ -1267,11 +1466,12 @@ void close_file(int fnum)
     unlock_share_entry( cnum, dev, inode, token);
 
   /* NT uses smbclose to start a print - weird */
-  if (fs_p->print_file)
+  if (normal_close && fs_p->print_file)
     print_file(fnum);
 
   /* check for magic scripts */
-  check_magic(fnum,cnum);
+  if (normal_close)
+    check_magic(fnum,cnum);
 
   DEBUG(2,("%s %s closed file %s (numopen=%d)\n",
           timestring(),Connections[cnum].user,fs_p->name,
@@ -1289,7 +1489,8 @@ static int access_table(int new_deny,int old_deny,int old_mode,
   if (new_deny == DENY_ALL || old_deny == DENY_ALL) return(AFAIL);
 
   if (new_deny == DENY_DOS || old_deny == DENY_DOS) {
-    if (old_deny == new_deny && share_pid == getpid()) 
+    int pid = getpid();
+    if (old_deny == new_deny && share_pid == pid) 
        return(AALL);    
 
     if (old_mode == 0) return(AREAD);
@@ -1338,28 +1539,79 @@ BOOL check_file_sharing(int cnum,char *fname)
 {
   int i;
   int ret = False;
-  min_share_mode_entry *old_shares = 0;
+  share_mode_entry *old_shares = 0;
   int num_share_modes;
   struct stat sbuf;
-  share_lock_token token;
+  int token;
   int pid = getpid();
+  uint32 dev, inode;
 
   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);
+  dev = (uint32)sbuf.st_dev;
+  inode = (uint32)sbuf.st_ino;
 
-  for( i = 0; i < num_share_modes; i++)
+  lock_share_entry(cnum, dev, inode, &token);
+  num_share_modes = get_share_modes(cnum, token, dev, inode, &old_shares);
+
+  /*
+   * Check if the share modes will give us access.
+   */
+
+  if(num_share_modes != 0)
   {
-    if (old_shares[i].share_mode != DENY_DOS)
-      goto free_and_exit;
+    BOOL broke_oplock;
+
+    do
+    {
 
-    if(old_shares[i].pid != pid)
-      goto free_and_exit;
+      broke_oplock = False;
+      for(i = 0; i < num_share_modes; i++)
+      {
+        share_mode_entry *share_entry = &old_shares[i];
+
+        /* 
+         * Break oplocks before checking share modes. See comment in
+         * open_file_shared for details. 
+         * Check if someone has an oplock on this file. If so we must 
+         * break it before continuing. 
+         */
+        if(share_entry->op_type & BATCH_OPLOCK)
+        {
+
+          DEBUG(5,("check_file_sharing: breaking oplock (%x) on file %s, \
+dev = %x, inode = %x\n", share_entry->op_type, fname, dev, inode));
+
+          /* Oplock break.... */
+          unlock_share_entry(cnum, dev, inode, token);
+          if(request_oplock_break(share_entry, dev, inode) == False)
+          {
+            free((char *)old_shares);
+            DEBUG(0,("check_file_sharing: FAILED when breaking oplock (%x) on file %s, \
+dev = %x, inode = %x\n", old_shares[i].op_type, fname, dev, inode));
+            return False;
+          }
+          lock_share_entry(cnum, dev, inode, &token);
+          broke_oplock = True;
+          break;
+        }
+
+        /* someone else has a share lock on it, check to see 
+           if we can too */
+        if ((share_entry->share_mode != DENY_DOS) || (share_entry->pid != pid))
+          goto free_and_exit;
+
+      } /* end for */
+
+      if(broke_oplock)
+      {
+        free((char *)old_shares);
+        num_share_modes = get_share_modes(cnum, token, dev, inode, &old_shares);
+      }
+    } while(broke_oplock);
   }
 
   /* XXXX exactly what share mode combinations should be allowed for
@@ -1370,7 +1622,7 @@ BOOL check_file_sharing(int cnum,char *fname)
 
 free_and_exit:
 
-  unlock_share_entry(cnum, (uint32)sbuf.st_dev, (uint32)sbuf.st_ino, token);
+  unlock_share_entry(cnum, dev, inode, token);
   if(old_shares != NULL)
     free((char *)old_shares);
   return(ret);
@@ -1381,8 +1633,8 @@ free_and_exit:
   Helper for open_file_shared. 
   Truncate a file after checking locking; close file if locked.
   **************************************************************************/
-static void truncate_unless_locked(int fnum, int cnum, share_lock_token token, 
-       BOOL *share_locked)
+static void truncate_unless_locked(int fnum, int cnum, int token, 
+                                  BOOL *share_locked)
 {
   if (Files[fnum].can_write){
     if (is_locked(fnum,cnum,0x3FFFFFFF,0)){
@@ -1391,7 +1643,7 @@ static void truncate_unless_locked(int fnum, int cnum, share_lock_token token,
       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);   
+      close_file(fnum,False);   
       /* Share mode no longer locked. */
       *share_locked = False;
       errno = EACCES;
@@ -1403,12 +1655,52 @@ static void truncate_unless_locked(int fnum, int cnum, share_lock_token token,
   }
 }
 
+/****************************************************************************
+check if we can open a file with a share mode
+****************************************************************************/
+int check_share_mode( share_mode_entry *share, int deny_mode, char *fname,
+                      BOOL fcbopen, int *flags)
+{
+  int old_open_mode = share->share_mode &0xF;
+  int old_deny_mode = (share->share_mode >>4)&7;
+
+  if (old_deny_mode > 4 || old_open_mode > 2)
+  {
+    DEBUG(0,("Invalid share mode found (%d,%d,%d) on file %s\n",
+               deny_mode,old_deny_mode,old_open_mode,fname));
+    return False;
+  }
+
+  {
+    int access_allowed = access_table(deny_mode,old_deny_mode,old_open_mode,
+                                share->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))
+    {
+      DEBUG(2,("Share violation on file (%d,%d,%d,%d,%s) = %d\n",
+                deny_mode,old_deny_mode,old_open_mode,
+                share->pid,fname, access_allowed));
+      return False;
+    }
+
+    if (access_allowed == AREAD)
+      *flags = O_RDONLY;
+
+    if (access_allowed == AWRITE)
+      *flags = O_WRONLY;
+
+  }
+  return True;
+}
 
 /****************************************************************************
 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)
+                     int mode,int oplock_request, int *Access,int *action)
 {
   files_struct *fs_p = &Files[fnum];
   int flags=0;
@@ -1418,9 +1710,10 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
   BOOL file_existed = file_exist(fname,&sbuf);
   BOOL share_locked = False;
   BOOL fcbopen = False;
-  share_lock_token token;
+  int token;
   uint32 dev = 0;
   uint32 inode = 0;
+  int num_share_modes = 0;
 
   fs_p->open = False;
   fs_p->fd_ptr = 0;
@@ -1429,7 +1722,13 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
   if (strstr(fname,".+,;=[].")) 
   {
     unix_ERR_class = ERRDOS;
+    /* OS/2 Workplace shell fix may be main code stream in a later release. */ 
+#ifdef OS2_WPS_FIX
+    unix_ERR_code = ERRcannotopen;
+#else /* OS2_WPS_FIX */
     unix_ERR_code = ERROR_EAS_NOT_SUPPORTED;
+#endif /* OS2_WPS_FIX */
+
     return;
   }
 
@@ -1486,10 +1785,8 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
 
   if (lp_share_modes(SNUM(cnum))) 
   {
-    int num_shares = 0;
     int i;
-    min_share_mode_entry *old_shares = 0;
-
+    share_mode_entry *old_shares = 0;
 
     if (file_existed)
     {
@@ -1497,58 +1794,77 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
       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);
+      num_share_modes = get_share_modes(cnum, token, dev, inode, &old_shares);
     }
 
-    for(i = 0; i < num_shares; i++)
+    /*
+     * Check if the share modes will give us access.
+     */
+
+    if(share_locked && (num_share_modes != 0))
     {
-      /* someone else has a share lock on it, check to see 
-        if we can too */
-      int old_open_mode = old_shares[i].share_mode &0xF;
-      int old_deny_mode = (old_shares[i].share_mode >>4)&7;
+      BOOL broke_oplock;
 
-      if (deny_mode > 4 || old_deny_mode > 4 || old_open_mode > 2) 
+      do
       {
-       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;
-       return;
-      }
 
-      {
-       int access_allowed = access_table(deny_mode,old_deny_mode,old_open_mode,
-                                         old_shares[i].pid,fname);
+        broke_oplock = False;
+        for(i = 0; i < num_share_modes; i++)
+        {
+          share_mode_entry *share_entry = &old_shares[i];
+
+          /* 
+           * By observation of NetBench, oplocks are broken *before* share
+           * modes are checked. This allows a file to be closed by the client
+           * if the share mode would deny access and the client has an oplock. 
+           * Check if someone has an oplock on this file. If so we must break 
+           * it before continuing. 
+           */
+          if(share_entry->op_type & (EXCLUSIVE_OPLOCK|BATCH_OPLOCK))
+          {
+
+            DEBUG(5,("open_file_shared: breaking oplock (%x) on file %s, \
+dev = %x, inode = %x\n", share_entry->op_type, fname, dev, inode));
+
+            /* Oplock break.... */
+            unlock_share_entry(cnum, dev, inode, token);
+            if(request_oplock_break(share_entry, dev, inode) == False)
+            {
+              free((char *)old_shares);
+              DEBUG(0,("open_file_shared: FAILED when breaking oplock (%x) on file %s, \
+dev = %x, inode = %x\n", old_shares[i].op_type, fname, dev, inode));
+              errno = EACCES;
+              unix_ERR_class = ERRDOS;
+              unix_ERR_code = ERRbadshare;
+              return;
+            }
+            lock_share_entry(cnum, dev, inode, &token);
+            broke_oplock = True;
+            break;
+          }
+
+          /* someone else has a share lock on it, check to see 
+             if we can too */
+          if(check_share_mode(share_entry, deny_mode, fname, fcbopen, &flags) == False)
+          {
+            free((char *)old_shares);
+            unlock_share_entry(cnum, dev, inode, token);
+            errno = EACCES;
+            unix_ERR_class = ERRDOS;
+            unix_ERR_code = ERRbadshare;
+            return;
+          }
+
+        } /* end for */
 
-       if ((access_allowed == AFAIL) ||
-           (!fcbopen && (access_allowed == AREAD && flags == O_RDWR)) ||
-           (access_allowed == AREAD && flags == O_WRONLY) ||
-           (access_allowed == AWRITE && flags == O_RDONLY)) 
+        if(broke_oplock)
         {
-         DEBUG(2,("Share violation on file (%d,%d,%d,%d,%s) = %d\n",
-                  deny_mode,old_deny_mode,old_open_mode,
-                  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;
+          num_share_modes = get_share_modes(cnum, token, dev, inode, &old_shares);
         }
-       
-       if (access_allowed == AREAD)
-         flags = O_RDONLY;
-       
-       if (access_allowed == AWRITE)
-         flags = O_WRONLY;
-      }
+      } while(broke_oplock);
     }
+
     if(old_shares != 0)
       free((char *)old_shares);
   }
@@ -1605,7 +1921,30 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
        file (which expects the share_mode_entry to be there).
      */
     if (lp_share_modes(SNUM(cnum)))
-      set_share_mode(token, fnum);
+    {
+      uint16 port = 0;
+      /* JRA. Currently this only services Exlcusive and batch
+         oplocks (no other opens on this file). This needs to
+         be extended to level II oplocks (multiple reader
+         oplocks). */
+
+      if(oplock_request && (num_share_modes == 0) && lp_oplocks(SNUM(cnum)))
+      {
+        fs_p->granted_oplock = True;
+        global_oplocks_open++;
+        port = oplock_port;
+
+        DEBUG(5,("open_file_shared: granted oplock (%x) on file %s, \
+dev = %x, inode = %x\n", oplock_request, fname, dev, inode));
+
+      }
+      else
+      {
+        port = 0;
+        oplock_request = 0;
+      }
+      set_share_mode(token, fnum, port, oplock_request);
+    }
 
     if ((flags2&O_TRUNC) && file_existed)
       truncate_unless_locked(fnum,cnum,token,&share_locked);
@@ -1618,23 +1957,25 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
 /****************************************************************************
 seek a file. Try to avoid the seek if possible
 ****************************************************************************/
-int seek_file(int fnum,int pos)
+int seek_file(int fnum,uint32 pos)
 {
-  int offset = 0;
+  uint32 offset = 0;
   if (Files[fnum].print_file && POSTSCRIPT(Files[fnum].cnum))
     offset = 3;
 
-  Files[fnum].pos = lseek(Files[fnum].fd_ptr->fd,pos+offset,SEEK_SET) - offset;
+  Files[fnum].pos = (int)(lseek(Files[fnum].fd_ptr->fd,pos+offset,SEEK_SET) 
+                                  - offset);
   return(Files[fnum].pos);
 }
 
 /****************************************************************************
 read from a file
 ****************************************************************************/
-int read_file(int fnum,char *data,int pos,int n)
+int read_file(int fnum,char *data,uint32 pos,int n)
 {
   int ret=0,readret;
 
+#if USE_READ_PREDICTION
   if (!Files[fnum].can_write)
     {
       ret = read_predict(Files[fnum].fd_ptr->fd,pos,data,NULL,n);
@@ -1643,11 +1984,12 @@ int read_file(int fnum,char *data,int pos,int n)
       n -= ret;
       pos += ret;
     }
+#endif
 
 #if USE_MMAP
   if (Files[fnum].mmap_ptr)
     {
-      int num = MIN(n,Files[fnum].mmap_size-pos);
+      int num = MIN(n,(int)(Files[fnum].mmap_size-pos));
       if (num > 0)
        {
          memcpy(data,Files[fnum].mmap_ptr+pos,num);
@@ -1853,6 +2195,7 @@ struct
   {EPERM,ERRDOS,ERRnoaccess},
   {EACCES,ERRDOS,ERRnoaccess},
   {ENOENT,ERRDOS,ERRbadfile},
+  {ENOTDIR,ERRDOS,ERRbadpath},
   {EIO,ERRHRD,ERRgeneral},
   {EBADF,ERRSRV,ERRsrverror},
   {EINVAL,ERRSRV,ERRsrverror},
@@ -1873,7 +2216,6 @@ struct
   {0,0,0}
 };
 
-
 /****************************************************************************
   create an error packet from errno
 ****************************************************************************/
@@ -1893,15 +2235,15 @@ int unix_error_packet(char *inbuf,char *outbuf,int def_class,uint32 def_code,int
   else
     {
       while (unix_smb_errmap[i].smbclass != 0)
-       {
-         if (unix_smb_errmap[i].unixerror == errno)
+      {
+           if (unix_smb_errmap[i].unixerror == errno)
            {
              eclass = unix_smb_errmap[i].smbclass;
              ecode = unix_smb_errmap[i].smbcode;
              break;
            }
          i++;
-       }
+      }
     }
 
   return(error_packet(inbuf,outbuf,eclass,ecode,line));
@@ -1935,182 +2277,811 @@ int error_packet(char *inbuf,char *outbuf,int error_class,uint32 error_code,int
 }
 
 
-#ifndef SIGCLD_IGNORE
-/****************************************************************************
-this prevents zombie child processes
-****************************************************************************/
-static int sig_cld()
-{
-  static int depth = 0;
-  if (depth != 0)
+#ifndef SIGCLD_IGNORE
+/****************************************************************************
+this prevents zombie child processes
+****************************************************************************/
+static int sig_cld()
+{
+  static int depth = 0;
+  if (depth != 0)
+    {
+      DEBUG(0,("ERROR: Recursion in sig_cld? Perhaps you need `#define USE_WAITPID'?\n"));
+      depth=0;
+      return(0);
+    }
+  depth++;
+
+  BlockSignals(True,SIGCLD);
+  DEBUG(5,("got SIGCLD\n"));
+
+#ifdef USE_WAITPID
+  while (sys_waitpid((pid_t)-1,(int *)NULL, WNOHANG) > 0);
+#endif
+
+  /* Stop zombies */
+  /* Stevens, Adv. Unix Prog. says that on system V you must call
+     wait before reinstalling the signal handler, because the kernel
+     calls the handler from within the signal-call when there is a
+     child that has exited. This would lead to an infinite recursion
+     if done vice versa. */
+        
+#ifndef DONT_REINSTALL_SIG
+#ifdef SIGCLD_IGNORE
+  signal(SIGCLD, SIG_IGN);  
+#else
+  signal(SIGCLD, SIGNAL_CAST sig_cld);
+#endif
+#endif
+
+#ifndef USE_WAITPID
+  while (wait3(WAIT3_CAST1 NULL, WNOHANG, WAIT3_CAST2 NULL) > 0);
+#endif
+  depth--;
+  BlockSignals(False,SIGCLD);
+  return 0;
+}
+#endif
+
+/****************************************************************************
+  this is called when the client exits abruptly
+  **************************************************************************/
+static int sig_pipe()
+{
+       struct cli_state *cli;
+       BlockSignals(True,SIGPIPE);
+
+       if ((cli = server_client()) && cli->initialised) {
+               DEBUG(3,("lost connection to password server\n"));
+               cli_shutdown(cli);
+#ifndef DONT_REINSTALL_SIG
+               signal(SIGPIPE, SIGNAL_CAST sig_pipe);
+#endif
+               BlockSignals(False,SIGPIPE);
+               return 0;
+       }
+
+       exit_server("Got sigpipe\n");
+       return(0);
+}
+
+/****************************************************************************
+  open the socket communication
+****************************************************************************/
+static BOOL open_sockets(BOOL is_daemon,int port)
+{
+  extern int Client;
+
+  if (is_daemon)
+  {
+    int num_interfaces = iface_count();
+    int fd_listenset[FD_SETSIZE];
+    fd_set listen_set;
+    int s;
+    int i;
+
+    /* Stop zombies */
+#ifdef SIGCLD_IGNORE
+    signal(SIGCLD, SIG_IGN);
+#else
+    signal(SIGCLD, SIGNAL_CAST sig_cld);
+#endif
+
+    if(atexit_set == 0)
+      atexit(killkids);
+
+    FD_ZERO(&listen_set);
+
+    if(lp_interfaces() && lp_bind_interfaces_only())
+    {
+       /* We have been given an interfaces line, and been 
+          told to only bind to those interfaces. Create a
+          socket per interface and bind to only these.
+        */
+
+      if(num_interfaces > FD_SETSIZE)
+      {
+        DEBUG(0,("open_sockets: Too many interfaces specified to bind to. Number was %d \
+max can be %d\n", num_interfaces, FD_SETSIZE));
+        return False;
+      }
+
+      /* Now open a listen socket for each of the interfaces. */
+      for(i = 0; i < num_interfaces; i++)
+      {
+        struct in_addr *ifip = iface_n_ip(i);
+
+        if(ifip == NULL)
+        {
+          DEBUG(0,("open_sockets: interface %d has NULL IP address !\n", i));
+          continue;
+        }
+        s = fd_listenset[i] = open_socket_in(SOCK_STREAM, port, 0, ifip->s_addr);
+        if(s == -1)
+          return False;
+        /* ready to listen */
+        if (listen(s, 5) == -1) 
+        {
+          DEBUG(0,("listen: %s\n",strerror(errno)));
+          close(s);
+          return False;
+        }
+        FD_SET(s,&listen_set);
+      }
+    }
+    else
+    {
+      /* Just bind to 0.0.0.0 - accept connections from anywhere. */
+      num_interfaces = 1;
+
+      /* open an incoming socket */
+      s = open_socket_in(SOCK_STREAM, port, 0,interpret_addr(lp_socket_address()));
+      if (s == -1)
+        return(False);
+
+      /* ready to listen */
+      if (listen(s, 5) == -1) 
+      {
+        DEBUG(0,("open_sockets: listen: %s\n",strerror(errno)));
+        close(s);
+        return False;
+      }
+
+      fd_listenset[0] = s;
+      FD_SET(s,&listen_set);
+    }      
+
+    /* now accept incoming connections - forking a new process
+       for each incoming connection */
+    DEBUG(2,("waiting for a connection\n"));
+    while (1)
+    {
+      fd_set lfds;
+      int num;
+
+      memcpy((char *)&lfds, (char *)&listen_set, sizeof(listen_set));
+
+      num = sys_select(&lfds,NULL);
+
+      if (num == -1 && errno == EINTR)
+        continue;
+
+      /* Find the sockets that are read-ready - accept on these. */
+      for( ; num > 0; num--)
+      {
+        struct sockaddr addr;
+        int in_addrlen = sizeof(addr);
+
+        s = -1;
+        for(i = 0; i < num_interfaces; i++)
+        {
+          if(FD_ISSET(fd_listenset[i],&lfds))
+          {
+            s = fd_listenset[i];
+            /* Clear this so we don't look at it again. */
+            FD_CLR(fd_listenset[i],&lfds);
+            break;
+          }
+        }
+
+        Client = accept(s,&addr,&in_addrlen);
+
+        if (Client == -1 && errno == EINTR)
+          continue;
+
+        if (Client == -1)
+        {
+          DEBUG(0,("open_sockets: accept: %s\n",strerror(errno)));
+          continue;
+        }
+
+#ifdef NO_FORK_DEBUG
+#ifndef NO_SIGNAL_TEST
+        signal(SIGPIPE, SIGNAL_CAST sig_pipe);
+        signal(SIGCLD, SIGNAL_CAST SIG_DFL);
+#endif /* NO_SIGNAL_TEST */
+        return True;
+#else /* NO_FORK_DEBUG */
+        if (Client != -1 && fork()==0)
+        {
+          /* Child code ... */
+
+#ifndef NO_SIGNAL_TEST
+          signal(SIGPIPE, SIGNAL_CAST sig_pipe);
+          signal(SIGCLD, SIGNAL_CAST SIG_DFL);
+#endif /* NO_SIGNAL_TEST */
+          /* close the listening socket(s) */
+          for(i = 0; i < num_interfaces; i++)
+            close(fd_listenset[i]);
+
+          /* close our standard file descriptors */
+          close_low_fds();
+          am_parent = 0;
+  
+          set_socket_options(Client,"SO_KEEPALIVE");
+          set_socket_options(Client,user_socket_options);
+
+          /* Reset global variables in util.c so that
+             client substitutions will be done correctly
+             in the process.
+           */
+          reset_globals_after_fork();
+          return True; 
+        }
+        close(Client); /* The parent doesn't need this socket */
+#endif /NO_FORK_DEBUG */
+      } /* end for num */
+    } /* end while 1 */
+  } /* end if is_daemon */
+  else
+  {
+    /* Started from inetd. fd 0 is the socket. */
+    /* We will abort gracefully when the client or remote system 
+       goes away */
+#ifndef NO_SIGNAL_TEST
+    signal(SIGPIPE, SIGNAL_CAST sig_pipe);
+#endif
+    Client = dup(0);
+
+    /* close our standard file descriptors */
+    close_low_fds();
+
+    set_socket_options(Client,"SO_KEEPALIVE");
+    set_socket_options(Client,user_socket_options);
+  }
+
+  return True;
+}
+
+/****************************************************************************
+  process an smb from the client - split out from the process() code so
+  it can be used by the oplock break code.
+****************************************************************************/
+
+static void process_smb(char *inbuf, char *outbuf)
+{
+  extern int Client;
+  static int trans_num;
+  int msg_type = CVAL(inbuf,0);
+  int32 len = smb_len(inbuf);
+  int nread = len + 4;
+
+  if (trans_num == 0) {
+         /* on the first packet, check the global hosts allow/ hosts
+            deny parameters before doing any parsing of the packet
+            passed to us by the client.  This prevents attacks on our
+            parsing code from hosts not in the hosts allow list */
+         if (!check_access(-1)) {
+                 /* send a negative session response "not listining on calling
+                  name" */
+                 static unsigned char buf[5] = {0x83, 0, 0, 1, 0x81};
+                 DEBUG(1,("%s Connection denied from %s\n",
+                          timestring(),client_addr()));
+                 send_smb(Client,(char *)buf);
+                 exit_server("connection denied");
+         }
+  }
+
+  DEBUG(6,("got message type 0x%x of len 0x%x\n",msg_type,len));
+  DEBUG(3,("%s Transaction %d of length %d\n",timestring(),trans_num,nread));
+
+#ifdef WITH_VTP
+  if(trans_num == 1 && VT_Check(inbuf)) 
+  {
+    VT_Process();
+    return;
+  }
+#endif
+
+  if (msg_type == 0)
+    show_msg(inbuf);
+
+  nread = construct_reply(inbuf,outbuf,nread,max_send);
+      
+  if(nread > 0) 
+  {
+    if (CVAL(outbuf,0) == 0)
+      show_msg(outbuf);
+       
+    if (nread != smb_len(outbuf) + 4) 
+    {
+      DEBUG(0,("ERROR: Invalid message response size! %d %d\n",
+                 nread, smb_len(outbuf)));
+    }
+    else
+      send_smb(Client,outbuf);
+  }
+  trans_num++;
+}
+
+/****************************************************************************
+  open the oplock IPC socket communication
+****************************************************************************/
+static BOOL open_oplock_ipc()
+{
+  struct sockaddr_in sock_name;
+  int len = sizeof(sock_name);
+
+  DEBUG(3,("open_oplock_ipc: opening loopback UDP socket.\n"));
+
+  /* Open a lookback UDP socket on a random port. */
+  oplock_sock = open_socket_in(SOCK_DGRAM, 0, 0, htonl(INADDR_LOOPBACK));
+  if (oplock_sock == -1)
+  {
+    DEBUG(0,("open_oplock_ipc: Failed to get local UDP socket for \
+address %x. Error was %s\n", htonl(INADDR_LOOPBACK), strerror(errno)));
+    oplock_port = 0;
+    return(False);
+  }
+
+  /* Find out the transient UDP port we have been allocated. */
+  if(getsockname(oplock_sock, (struct sockaddr *)&sock_name, &len)<0)
+  {
+    DEBUG(0,("open_oplock_ipc: Failed to get local UDP port. Error was %s\n",
+            strerror(errno)));
+    close(oplock_sock);
+    oplock_sock = -1;
+    oplock_port = 0;
+    return False;
+  }
+  oplock_port = ntohs(sock_name.sin_port);
+
+  DEBUG(3,("open_oplock ipc: pid = %d, oplock_port = %u\n", 
+            getpid(), oplock_port));
+
+  return True;
+}
+
+/****************************************************************************
+  process an oplock break message.
+****************************************************************************/
+static BOOL process_local_message(int sock, char *buffer, int buf_size)
+{
+  int32 msg_len;
+  uint16 from_port;
+  char *msg_start;
+
+  msg_len = IVAL(buffer,UDP_CMD_LEN_OFFSET);
+  from_port = SVAL(buffer,UDP_CMD_PORT_OFFSET);
+
+  msg_start = &buffer[UDP_CMD_HEADER_LEN];
+
+  DEBUG(5,("process_local_message: Got a message of length %d from port (%d)\n", 
+            msg_len, from_port));
+
+  /* Switch on message command - currently OPLOCK_BREAK_CMD is the
+     only valid request. */
+
+  switch(SVAL(msg_start,UDP_MESSAGE_CMD_OFFSET))
+  {
+    case OPLOCK_BREAK_CMD:
+      /* Ensure that the msg length is correct. */
+      if(msg_len != OPLOCK_BREAK_MSG_LEN)
+      {
+        DEBUG(0,("process_local_message: incorrect length for OPLOCK_BREAK_CMD (was %d, \
+should be %d).\n", msg_len, OPLOCK_BREAK_MSG_LEN));
+        return False;
+      }
+      {
+        uint32 remotepid = IVAL(msg_start,OPLOCK_BREAK_PID_OFFSET);
+        uint32 dev = IVAL(msg_start,OPLOCK_BREAK_DEV_OFFSET);
+        uint32 inode = IVAL(msg_start, OPLOCK_BREAK_INODE_OFFSET);
+        struct timeval tval;
+        struct sockaddr_in toaddr;
+
+        tval.tv_sec = IVAL(msg_start, OPLOCK_BREAK_SEC_OFFSET);
+        tval.tv_usec = IVAL(msg_start, OPLOCK_BREAK_USEC_OFFSET);
+
+        DEBUG(5,("process_local_message: oplock break request from \
+pid %d, port %d, dev = %x, inode = %x\n", remotepid, from_port, dev, inode));
+
+        /*
+         * If we have no record of any currently open oplocks,
+         * it's not an error, as a close command may have
+         * just been issued on the file that was oplocked.
+         * Just return success in this case.
+         */
+
+        if(global_oplocks_open != 0)
+        {
+          if(oplock_break(dev, inode, &tval) == False)
+          {
+            DEBUG(0,("process_local_message: oplock break failed - \
+not returning udp message.\n"));
+            return False;
+          }
+        }
+        else
+        {
+          DEBUG(3,("process_local_message: oplock break requested with no outstanding \
+oplocks. Returning success.\n"));
+        }
+
+        /* Send the message back after OR'ing in the 'REPLY' bit. */
+        SSVAL(msg_start,UDP_MESSAGE_CMD_OFFSET,OPLOCK_BREAK_CMD | CMD_REPLY);
+  
+        bzero((char *)&toaddr,sizeof(toaddr));
+        toaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+        toaddr.sin_port = htons(from_port);
+        toaddr.sin_family = AF_INET;
+
+        if(sendto( sock, msg_start, OPLOCK_BREAK_MSG_LEN, 0,
+                (struct sockaddr *)&toaddr, sizeof(toaddr)) < 0) 
+        {
+          DEBUG(0,("process_local_message: sendto process %d failed. Errno was %s\n",
+                    remotepid, strerror(errno)));
+          return False;
+        }
+
+        DEBUG(5,("process_local_message: oplock break reply sent to \
+pid %d, port %d, for file dev = %x, inode = %x\n", remotepid, 
+                from_port, dev, inode));
+
+      }
+      break;
+    /* 
+     * Keep this as a debug case - eventually we can remove it.
+     */
+    case 0x8001:
+      DEBUG(0,("process_local_message: Received unsolicited break \
+reply - dumping info.\n"));
+
+      if(msg_len != OPLOCK_BREAK_MSG_LEN)
+      {
+        DEBUG(0,("process_local_message: ubr: incorrect length for reply \
+(was %d, should be %d).\n", msg_len, OPLOCK_BREAK_MSG_LEN));
+        return False;
+      }
+
+      {
+        uint32 remotepid = IVAL(msg_start,OPLOCK_BREAK_PID_OFFSET);
+        uint32 dev = IVAL(msg_start,OPLOCK_BREAK_DEV_OFFSET);
+        uint32 inode = IVAL(msg_start, OPLOCK_BREAK_INODE_OFFSET);
+
+        DEBUG(0,("process_local_message: unsolicited oplock break reply from \
+pid %d, port %d, dev = %x, inode = %x\n", remotepid, from_port, dev, inode));
+
+       }
+       return False;
+
+    default:
+      DEBUG(0,("process_local_message: unknown UDP message command code (%x) - ignoring.\n",
+                (unsigned int)SVAL(msg_start,0)));
+      return False;
+  }
+  return True;
+}
+
+/****************************************************************************
+ Process an oplock break directly.
+****************************************************************************/
+BOOL oplock_break(uint32 dev, uint32 inode, struct timeval *tval)
+{
+  extern int Client;
+  static char *inbuf = NULL;
+  static char *outbuf = NULL;
+  files_struct *fsp = NULL;
+  int fnum;
+  time_t start_time;
+  BOOL shutdown_server = False;
+
+  DEBUG(3,("%s oplock_break: called for dev = %x, inode = %x. Current \
+global_oplocks_open = %d\n", timestring(), dev, inode, global_oplocks_open));
+
+  if(inbuf == NULL)
+  {
+    inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+    if(inbuf == NULL) {
+      DEBUG(0,("oplock_break: malloc fail for input buffer.\n"));
+      return False;
+    } 
+    outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+    if(outbuf == NULL) {
+      DEBUG(0,("oplock_break: malloc fail for output buffer.\n"));
+      free(inbuf);
+      inbuf = NULL;
+      return False;
+    }
+  } 
+
+  /* We need to search the file open table for the
+     entry containing this dev and inode, and ensure
+     we have an oplock on it. */
+  for( fnum = 0; fnum < MAX_OPEN_FILES; fnum++)
+  {
+    if(OPEN_FNUM(fnum))
+    {
+      fsp = &Files[fnum];
+      if((fsp->fd_ptr->dev == dev) && (fsp->fd_ptr->inode == inode) &&
+         (fsp->open_time.tv_sec == tval->tv_sec) && 
+         (fsp->open_time.tv_usec == tval->tv_usec))
+        break;
+    }
+  }
+
+  if(fsp == NULL)
+  {
+    /* The file could have been closed in the meantime - return success. */
+    DEBUG(3,("%s oplock_break: cannot find open file with dev = %x, inode = %x (fnum = %d) \
+allowing break to succeed.\n", timestring(), dev, inode, fnum));
+    return True;
+  }
+
+  /* Ensure we have an oplock on the file */
+
+  /* There is a potential race condition in that an oplock could
+     have been broken due to another udp request, and yet there are
+     still oplock break messages being sent in the udp message
+     queue for this file. So return true if we don't have an oplock,
+     as we may have just freed it.
+   */
+
+  if(!fsp->granted_oplock)
+  {
+    DEBUG(3,("%s oplock_break: file %s (fnum = %d, dev = %x, inode = %x) has no oplock. \
+Allowing break to succeed regardless.\n", timestring(), fsp->name, fnum, dev, inode));
+    return True;
+  }
+
+  /* Now comes the horrid part. We must send an oplock break to the client,
+     and then process incoming messages until we get a close or oplock release.
+   */
+
+  /* Prepare the SMBlockingX message. */
+  bzero(outbuf,smb_size);
+  set_message(outbuf,8,0,True);
+
+  SCVAL(outbuf,smb_com,SMBlockingX);
+  SSVAL(outbuf,smb_tid,fsp->cnum);
+  SSVAL(outbuf,smb_pid,0xFFFF);
+  SSVAL(outbuf,smb_uid,0);
+  SSVAL(outbuf,smb_mid,0xFFFF);
+  SCVAL(outbuf,smb_vwv0,0xFF);
+  SSVAL(outbuf,smb_vwv2,fnum);
+  SCVAL(outbuf,smb_vwv3,LOCKING_ANDX_OPLOCK_RELEASE);
+  /* Change this when we have level II oplocks. */
+  SCVAL(outbuf,smb_vwv3+1,OPLOCKLEVEL_NONE);
+  send_smb(Client, outbuf);
+
+  global_oplock_break = True;
+  /* Process incoming messages. */
+
+  /* JRA - If we don't get a break from the client in OPLOCK_BREAK_TIMEOUT
+     seconds we should just die.... */
+
+  start_time = time(NULL);
+
+  while(OPEN_FNUM(fnum) && fsp->granted_oplock)
+  {
+    if(receive_smb(Client,inbuf,OPLOCK_BREAK_TIMEOUT * 1000) == False)
+    {
+      /*
+       * Die if we got an error.
+       */
+
+      if (smb_read_error == READ_EOF)
+        DEBUG(0,("%s oplock_break: end of file from client\n", timestring()));
+      if (smb_read_error == READ_ERROR)
+        DEBUG(0,("%s oplock_break: receive_smb error (%s)\n",
+                  timestring(), strerror(errno)));
+
+      if (smb_read_error == READ_TIMEOUT)
+        DEBUG(0,("%s oplock_break: receive_smb timed out after %d seconds.\n",
+                  timestring(), OPLOCK_BREAK_TIMEOUT));
+
+      DEBUG(0,("%s oplock_break failed for file %s (fnum = %d, dev = %x, \
+inode = %x).\n", timestring(), fsp->name, fnum, dev, inode));
+      shutdown_server = True;
+      break;
+    }
+    process_smb(inbuf, outbuf);
+
+    /* We only need this in case a readraw crossed on the wire. */
+    if(global_oplock_break)
+      global_oplock_break = False;
+
+    /*
+     * Die if we go over the time limit.
+     */
+
+    if((time(NULL) - start_time) > OPLOCK_BREAK_TIMEOUT)
     {
-      DEBUG(0,("ERROR: Recursion in sig_cld? Perhaps you need `#define USE_WAITPID'?\n"));
-      depth=0;
-      return(0);
+      DEBUG(0,("%s oplock_break: no break received from client within \
+%d seconds.\n", timestring(), OPLOCK_BREAK_TIMEOUT));
+      DEBUG(0,("%s oplock_break failed for file %s (fnum = %d, dev = %x, \
+inode = %x).\n", timestring(), fsp->name, fnum, dev, inode));
+      shutdown_server = True;
+      break;
     }
-  depth++;
-
-  BlockSignals(True,SIGCLD);
-  DEBUG(5,("got SIGCLD\n"));
+  }
 
-#ifdef USE_WAITPID
-  while (sys_waitpid((pid_t)-1,(int *)NULL, WNOHANG) > 0);
-#endif
+  /*
+   * If the client did not respond we must die.
+   */
 
-  /* Stop zombies */
-  /* Stevens, Adv. Unix Prog. says that on system V you must call
-     wait before reinstalling the signal handler, because the kernel
-     calls the handler from within the signal-call when there is a
-     child that has exited. This would lead to an infinite recursion
-     if done vice versa. */
-        
-#ifndef DONT_REINSTALL_SIG
-#ifdef SIGCLD_IGNORE
-  signal(SIGCLD, SIG_IGN);  
-#else
-  signal(SIGCLD, SIGNAL_CAST sig_cld);
-#endif
-#endif
+  if(shutdown_server)
+  {
+    DEBUG(0,("%s oplock_break: client failure in break - shutting down this smbd.\n",
+          timestring()));
+    close_sockets();
+    close(oplock_sock);
+    exit_server("oplock break failure");
+  }
 
-#ifndef USE_WAITPID
-  while (wait3(WAIT3_CAST1 NULL, WNOHANG, WAIT3_CAST2 NULL) > 0);
-#endif
-  depth--;
-  BlockSignals(False,SIGCLD);
-  return 0;
-}
-#endif
+  if(OPEN_FNUM(fnum))
+  {
+    /* The lockingX reply will have removed the oplock flag 
+       from the sharemode. */
+    /* Paranoia.... */
+    fsp->granted_oplock = False;
+  }
 
-/****************************************************************************
-  this is called when the client exits abruptly
-  **************************************************************************/
-static int sig_pipe()
-{
-  extern int password_client;
-  BlockSignals(True,SIGPIPE);
+  global_oplocks_open--;
 
-  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;
+  /* Santity check - remove this later. JRA */
+  if(global_oplocks_open < 0)
+  {
+    DEBUG(0,("oplock_break: global_oplocks_open < 0 (%d). PANIC ERROR\n",
+              global_oplocks_open));
+    exit_server("oplock_break: global_oplocks_open < 0");
   }
 
-  exit_server("Got sigpipe\n");
-  return(0);
+  DEBUG(3,("%s oplock_break: returning success for fnum = %d, dev = %x, inode = %x. Current \
+global_oplocks_open = %d\n", timestring(), fnum, dev, inode, global_oplocks_open));
+
+  return True;
 }
 
 /****************************************************************************
-  open the socket communication
+Send an oplock break message to another smbd process. If the oplock is held 
+by the local smbd then call the oplock break function directly.
 ****************************************************************************/
-static BOOL open_sockets(BOOL is_daemon,int port)
+
+BOOL request_oplock_break(share_mode_entry *share_entry, 
+                          uint32 dev, uint32 inode)
 {
-  extern int Client;
+  char op_break_msg[OPLOCK_BREAK_MSG_LEN];
+  struct sockaddr_in addr_out;
+  int pid = getpid();
 
-  if (is_daemon)
+  if(pid == share_entry->pid)
+  {
+    /* We are breaking our own oplock, make sure it's us. */
+    if(share_entry->op_port != oplock_port)
     {
-      int s;
-      struct sockaddr addr;
-      int in_addrlen = sizeof(addr);
-       
-      /* Stop zombies */
-#ifdef SIGCLD_IGNORE
-      signal(SIGCLD, SIG_IGN);
-#else
-      signal(SIGCLD, SIGNAL_CAST sig_cld);
-#endif
+      DEBUG(0,("request_oplock_break: corrupt share mode entry - pid = %d, port = %d \
+should be %d\n", pid, share_entry->op_port, oplock_port));
+      return False;
+    }
 
-      /* open an incoming socket */
-      s = open_socket_in(SOCK_STREAM, port, 0,interpret_addr(lp_socket_address()));
-      if (s == -1)
-       return(False);
+    DEBUG(5,("request_oplock_break: breaking our own oplock\n"));
 
-      /* ready to listen */
-      if (listen(s, 5) == -1) 
-       {
-         DEBUG(0,("listen: %s",strerror(errno)));
-         close(s);
-         return False;
-       }
-      
-      if(atexit_set == 0)
-        atexit(killkids);
+    /* Call oplock break direct. */
+    return oplock_break(dev, inode, &share_entry->time);
+  }
 
-      /* now accept incoming connections - forking a new process
-        for each incoming connection */
-      DEBUG(2,("waiting for a connection\n"));
-      while (1)
-       {
-         Client = accept(s,&addr,&in_addrlen);
+  /* We need to send a OPLOCK_BREAK_CMD message to the
+     port in the share mode entry. */
+
+  SSVAL(op_break_msg,UDP_MESSAGE_CMD_OFFSET,OPLOCK_BREAK_CMD);
+  SIVAL(op_break_msg,OPLOCK_BREAK_PID_OFFSET,pid);
+  SIVAL(op_break_msg,OPLOCK_BREAK_DEV_OFFSET,dev);
+  SIVAL(op_break_msg,OPLOCK_BREAK_INODE_OFFSET,inode);
+  SIVAL(op_break_msg,OPLOCK_BREAK_SEC_OFFSET,(uint32)share_entry->time.tv_sec);
+  SIVAL(op_break_msg,OPLOCK_BREAK_USEC_OFFSET,(uint32)share_entry->time.tv_usec);
+
+  /* set the address and port */
+  bzero((char *)&addr_out,sizeof(addr_out));
+  addr_out.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+  addr_out.sin_port = htons( share_entry->op_port );
+  addr_out.sin_family = AF_INET;
+   
+  DEBUG(3,("%s request_oplock_break: sending a oplock break message to pid %d on port %d \
+for dev = %x, inode = %x\n", timestring(), share_entry->pid, share_entry->op_port, dev, inode));
 
-         if (Client == -1 && errno == EINTR)
-           continue;
+  if(sendto(oplock_sock,op_break_msg,OPLOCK_BREAK_MSG_LEN,0,
+         (struct sockaddr *)&addr_out,sizeof(addr_out)) < 0)
+  {
+    DEBUG(0,("%s request_oplock_break: failed when sending a oplock break message \
+to pid %d on port %d for dev = %x, inode = %x. Error was %s\n",
+         timestring(), share_entry->pid, share_entry->op_port, dev, inode,
+         strerror(errno)));
+    return False;
+  }
 
-         if (Client == -1)
-           {
-             DEBUG(0,("accept: %s",strerror(errno)));
-             continue;
-           }
+  /*
+   * Now we must await the oplock broken message coming back
+   * from the target smbd process. Timeout if it fails to
+   * return in (OPLOCK_BREAK_TIMEOUT + OPLOCK_BREAK_TIMEOUT_FUDGEFACTOR) seconds.
+   * While we get messages that aren't ours, loop.
+   */
 
-#ifdef NO_FORK_DEBUG
-#ifndef NO_SIGNAL_TEST
-          signal(SIGPIPE, SIGNAL_CAST sig_pipe);
-          signal(SIGCLD, SIGNAL_CAST SIG_DFL);
-#endif
-         return True;
-#else
-         if (Client != -1 && fork()==0)
-           {
-              /* Child code ... */
-#ifndef NO_SIGNAL_TEST
-             signal(SIGPIPE, SIGNAL_CAST sig_pipe);
-             signal(SIGCLD, SIGNAL_CAST SIG_DFL);
-#endif
-             /* close the listening socket */
-             close(s);
+  while(1)
+  {
+    char op_break_reply[UDP_CMD_HEADER_LEN+OPLOCK_BREAK_MSG_LEN];
+    int32 reply_msg_len;
+    uint16 reply_from_port;
+    char *reply_msg_start;
 
-             /* close our standard file descriptors */
-             close_low_fds();
-              am_parent = 0;
-  
-             set_socket_options(Client,"SO_KEEPALIVE");
-             set_socket_options(Client,user_socket_options);
-
-              /* Reset global variables in util.c so that
-                 client substitutions will be done correctly
-                 in the process.
-               */
-              reset_globals_after_fork();
-             return True; 
-           }
-          close(Client); /* The parent doesn't need this socket */
-#endif
-       }
-    }
-  else
+    if(receive_local_message(oplock_sock, op_break_reply, sizeof(op_break_reply),
+               (OPLOCK_BREAK_TIMEOUT+OPLOCK_BREAK_TIMEOUT_FUDGEFACTOR) * 1000) == False)
     {
-      /* We will abort gracefully when the client or remote system 
-        goes away */
-#ifndef NO_SIGNAL_TEST
-      signal(SIGPIPE, SIGNAL_CAST sig_pipe);
-#endif
-      Client = dup(0);
+      if(smb_read_error == READ_TIMEOUT)
+      {
+        DEBUG(0,("%s request_oplock_break: no response received to oplock break request to \
+pid %d on port %d for dev = %x, inode = %x\n", timestring(), share_entry->pid, 
+                           share_entry->op_port, dev, inode));
+        /*
+         * This is a hack to make handling of failing clients more robust.
+         * If a oplock break response message is not received in the timeout
+         * period we may assume that the smbd servicing that client holding
+         * the oplock has died and the client changes were lost anyway, so
+         * we should continue to try and open the file.
+         */
+        break;
+      }
+      else
+        DEBUG(0,("%s request_oplock_break: error in response received to oplock break request to \
+pid %d on port %d for dev = %x, inode = %x. Error was (%s).\n", timestring, share_entry->pid, 
+                         share_entry->op_port, dev, inode, strerror(errno)));
+      return False;
+    }
 
-      /* close our standard file descriptors */
-      close_low_fds();
+    /* 
+     * If the response we got was not an answer to our message, but
+     * was a completely different request, push it onto the pending
+     * udp message stack so that we can deal with it in the main loop.
+     * It may be another oplock break request to us.
+     */
 
-      set_socket_options(Client,"SO_KEEPALIVE");
-      set_socket_options(Client,user_socket_options);
+    /*
+     * Local note from JRA. There exists the possibility of a denial
+     * of service attack here by allowing non-root processes running
+     * on a local machine sending many of these pending messages to
+     * a smbd port. Currently I'm not sure how to restrict the messages
+     * I will queue (although I could add a limit to the queue) to
+     * those received by root processes only. There should be a 
+     * way to make this bulletproof....
+     */
+
+    reply_msg_len = IVAL(op_break_reply,UDP_CMD_LEN_OFFSET);
+    reply_from_port = SVAL(op_break_reply,UDP_CMD_PORT_OFFSET);
+
+    reply_msg_start = &op_break_reply[UDP_CMD_HEADER_LEN];
+
+    if(reply_msg_len != OPLOCK_BREAK_MSG_LEN)
+    {
+      /* Ignore it. */
+      DEBUG(0,("%s request_oplock_break: invalid message length received. Ignoring\n",
+             timestring()));
+      continue;
+    }
+
+    if(((SVAL(reply_msg_start,UDP_MESSAGE_CMD_OFFSET) & CMD_REPLY) == 0) ||
+       (reply_from_port != share_entry->op_port) ||
+       (memcmp(&reply_msg_start[OPLOCK_BREAK_PID_OFFSET], 
+               &op_break_msg[OPLOCK_BREAK_PID_OFFSET],
+               OPLOCK_BREAK_MSG_LEN - OPLOCK_BREAK_PID_OFFSET) != 0))
+    {
+      DEBUG(3,("%s request_oplock_break: received other message whilst awaiting \
+oplock break response from pid %d on port %d for dev = %x, inode = %x.\n",
+             timestring(), share_entry->pid, share_entry->op_port, dev, inode));
+      if(push_local_message(op_break_reply, sizeof(op_break_reply)) == False)
+        return False;
+      continue;
     }
 
+    break;
+  }
+
+  DEBUG(3,("%s request_oplock_break: broke oplock.\n", timestring()));
+
   return True;
 }
 
-
 /****************************************************************************
 check if a snum is in use
 ****************************************************************************/
@@ -2133,10 +3104,10 @@ BOOL reload_services(BOOL test)
   if (lp_loaded())
     {
       pstring fname;
-      strcpy(fname,lp_configfile());
+      pstrcpy(fname,lp_configfile());
       if (file_exist(fname,NULL) && !strcsequal(fname,servicesf))
        {
-         strcpy(servicesf,fname);
+         pstrcpy(servicesf,fname);
          test = False;
        }
     }
@@ -2166,7 +3137,7 @@ BOOL reload_services(BOOL test)
     }
   }
 
-  create_mangled_stack(lp_mangledstack());
+  reset_mangled_stack( lp_mangledstack() );
 
   /* this forces service parameters to be flushed */
   become_service(-1,True);
@@ -2195,7 +3166,8 @@ static int sig_hup()
 Setup the groups a user belongs to.
 ****************************************************************************/
 int setup_groups(char *user, int uid, int gid, int *p_ngroups, 
-                int **p_igroups, gid_t **p_groups)
+                int **p_igroups, gid_t **p_groups,
+         int **p_attrs)
 {
   if (-1 == initgroups(user,gid))
     {
@@ -2210,19 +3182,25 @@ int setup_groups(char *user, int uid, int gid, int *p_ngroups,
     {
       int i,ngroups;
       int *igroups;
+      int *attrs;
       gid_t grp = 0;
       ngroups = getgroups(0,&grp);
       if (ngroups <= 0)
         ngroups = 32;
       igroups = (int *)malloc(sizeof(int)*ngroups);
+      attrs   = (int *)malloc(sizeof(int)*ngroups);
       for (i=0;i<ngroups;i++)
+      {
+        attrs  [i] = 0x7; /* XXXX don't know what NT user attributes are yet! */
         igroups[i] = 0x42424242;
+      }
       ngroups = getgroups(ngroups,(gid_t *)igroups);
 
       if (igroups[0] == 0x42424242)
         ngroups = 0;
 
       *p_ngroups = ngroups;
+      *p_attrs   = attrs;
 
       /* The following bit of code is very strange. It is due to the
          fact that some OSes use int* and some use gid_t* for
@@ -2244,16 +3222,18 @@ int setup_groups(char *user, int uid, int gid, int *p_ngroups,
              groups_use_ints = False;
              
           if (groups_use_ints)
-            {
+          {
              *p_igroups = igroups;
              *p_groups = (gid_t *)igroups;       
-            }
+          }
           else
-            {
+          {
              gid_t *groups = (gid_t *)igroups;
              igroups = (int *)malloc(sizeof(int)*ngroups);
              for (i=0;i<ngroups;i++)
+          {
                igroups[i] = groups[i];
+          }
              *p_igroups = igroups;
              *p_groups = (gid_t *)groups;
            }
@@ -2379,8 +3359,17 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
   }
 
   /* admin user check */
-  if (user_in_list(user,lp_admin_users(snum)) &&
-      !pcon->read_only)
+
+  /* JRA - original code denied admin user if the share was
+     marked read_only. Changed as I don't think this is needed,
+     but old code left in case there is a problem here.
+   */
+  if (user_in_list(user,lp_admin_users(snum)) 
+#if 0
+      && !pcon->read_only)
+#else
+      )
+#endif
     {
       pcon->admin_user = True;
       DEBUG(0,("%s logged in as admin user (root privileges)\n",user));
@@ -2399,6 +3388,8 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
   pcon->printer = (strncmp(dev,"LPT",3) == 0);
   pcon->ipc = (strncmp(dev,"IPC",3) == 0);
   pcon->dirptr = NULL;
+  pcon->veto_list = NULL;
+  pcon->hide_list = NULL;
   string_set(&pcon->dirpath,"");
   string_set(&pcon->user,user);
 
@@ -2427,13 +3418,13 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
     {
       struct passwd *pass2;
       fstring fuser;
-      strcpy(fuser,lp_force_user(snum));
+      fstrcpy(fuser,lp_force_user(snum));
       pass2 = (struct passwd *)Get_Pwnam(fuser,True);
       if (pass2)
        {
          pcon->uid = pass2->pw_uid;
          string_set(&pcon->user,fuser);
-         strcpy(user,fuser);
+         fstrcpy(user,fuser);
          pcon->force_user = True;
          DEBUG(3,("Forced user %s\n",fuser));    
        }
@@ -2443,7 +3434,7 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
 
   {
     pstring s;
-    strcpy(s,lp_pathname(snum));
+    pstrcpy(s,lp_pathname(snum));
     standard_sub(cnum,s);
     string_set(&pcon->connectpath,s);
     DEBUG(3,("Connect path is %s\n",s));
@@ -2451,12 +3442,15 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
 
   /* groups stuff added by ih */
   pcon->ngroups = 0;
+  pcon->igroups = NULL;
   pcon->groups = NULL;
+  pcon->attrs = NULL;
 
   if (!IS_IPC(cnum))
     {
       /* Find all the groups this uid is in and store them. Used by become_user() */
-      setup_groups(pcon->user,pcon->uid,pcon->gid,&pcon->ngroups,&pcon->igroups,&pcon->groups);
+      setup_groups(pcon->user,pcon->uid,pcon->gid,
+                  &pcon->ngroups,&pcon->igroups,&pcon->groups,&pcon->attrs);
       
       /* check number of connections */
       if (!claim_connection(cnum,
@@ -2479,13 +3473,13 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
   if (*lp_rootpreexec(SNUM(cnum)))
     {
       pstring cmd;
-      strcpy(cmd,lp_rootpreexec(SNUM(cnum)));
+      pstrcpy(cmd,lp_rootpreexec(SNUM(cnum)));
       standard_sub(cnum,cmd);
       DEBUG(5,("cmd=%s\n",cmd));
       smbrun(cmd,NULL,False);
     }
 
-  if (!become_user(cnum,pcon->vuid))
+  if (!become_user(&Connections[cnum], cnum,pcon->vuid))
     {
       DEBUG(0,("Can't become connected user!\n"));
       pcon->open = False;
@@ -2519,7 +3513,7 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
   /* resolve any soft links early */
   {
     pstring s;
-    strcpy(s,pcon->connectpath);
+    pstrcpy(s,pcon->connectpath);
     GetWd(s);
     string_set(&pcon->connectpath,s);
     ChDir(pcon->connectpath);
@@ -2533,7 +3527,7 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
   if (*lp_preexec(SNUM(cnum)))
     {
       pstring cmd;
-      strcpy(cmd,lp_preexec(SNUM(cnum)));
+      pstrcpy(cmd,lp_preexec(SNUM(cnum)));
       standard_sub(cnum,cmd);
       smbrun(cmd,NULL,False);
     }
@@ -2541,6 +3535,13 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
   /* we've finished with the sensitive stuff */
   unbecome_user();
 
+  /* Add veto/hide lists */
+  if (!IS_IPC(cnum) && !IS_PRINT(cnum))
+  {
+    set_namearray( &pcon->veto_list, lp_veto_files(SNUM(cnum)));
+    set_namearray( &pcon->hide_list, lp_hide_files(SNUM(cnum)));
+  }
+
   {
     DEBUG(IS_IPC(cnum)?3:1,("%s %s (%s) connect to service %s as user %s (uid=%d,gid=%d) (pid %d)\n",
                            timestring(),
@@ -2647,34 +3648,19 @@ 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;
 
   set_message(outbuf,13,doencrypt?8:0,True);
   SSVAL(outbuf,smb_vwv1,secword); 
-#ifdef SMB_PASSWD
   /* Create a token value and add it to the outgoing packet. */
   if (doencrypt) 
     generate_next_challenge(smb_buf(outbuf));
-#endif
 
   Protocol = PROTOCOL_LANMAN1;
 
-  if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) {
-    DEBUG(3,("using password server validation\n"));
-#ifdef SMB_PASSWD
-  if (doencrypt) set_challenge(smb_buf(outbuf));    
-#endif
-  }
-
   CVAL(outbuf,smb_flg) = 0x81; /* Reply, SMBlockread, SMBwritelock supported */
-  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);
@@ -2698,36 +3684,41 @@ 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);
+  struct cli_state *cli = NULL;
+  char cryptkey[8];
+  char crypt_len = 0;
+
+  if (lp_security() == SEC_SERVER) {
+         cli = server_cryptkey();
+  }
+
+  if (cli) {
+         DEBUG(3,("using password server validation\n"));
+         doencrypt = ((cli->sec_mode & 2) != 0);
+  }
 
   if (lp_security()>=SEC_USER) secword |= 1;
   if (doencrypt) secword |= 2;
 
-  set_message(outbuf,13,doencrypt?8:0,True);
-  SSVAL(outbuf,smb_vwv1,secword); 
-#ifdef SMB_PASSWD
-  /* Create a token value and add it to the outgoing packet. */
-  if (doencrypt) 
-    generate_next_challenge(smb_buf(outbuf));
-#endif
+  if (doencrypt) {
+         crypt_len = 8;
+         if (!cli) {
+                 generate_next_challenge(cryptkey);
+         } else {
+                 memcpy(cryptkey, cli->cryptkey, 8);
+                 set_challenge(cli->cryptkey);
+         }
+  }
 
+  set_message(outbuf,13,crypt_len,True);
+  SSVAL(outbuf,smb_vwv1,secword); 
   SIVAL(outbuf,smb_vwv6,getpid());
+  if (doencrypt) 
+         memcpy(smb_buf(outbuf), cryptkey, 8);
 
   Protocol = PROTOCOL_LANMAN2;
 
-  if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) {
-    DEBUG(3,("using password server validation\n"));
-#ifdef SMB_PASSWD
-    if (doencrypt) set_challenge(smb_buf(outbuf));    
-#endif
-  }
-
   CVAL(outbuf,smb_flg) = 0x81; /* Reply, SMBlockread, SMBwritelock supported */
-  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);
@@ -2749,71 +3740,58 @@ int reply_nt1(char *outbuf)
 /*
   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;
+                     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);
+  struct cli_state *cli = NULL;
+  char cryptkey[8];
+  char crypt_len = 0;
 
-  if (lp_readraw() && lp_writeraw())
-  {
-    capabilities |= CAP_RAW_MODE;
+  if (lp_security() == SEC_SERVER) {
+         cli = server_cryptkey();
   }
 
-  if (lp_security()>=SEC_USER) secword |= 1;
+  if (cli) {
+         DEBUG(3,("using password server validation\n"));
+         doencrypt = ((cli->sec_mode & 2) != 0);
+  }
+
+  if (doencrypt) {
+         crypt_len = 8;
+         if (!cli) {
+                 generate_next_challenge(cryptkey);
+         } else {
+                 memcpy(cryptkey, cli->cryptkey, 8);
+                 set_challenge(cli->cryptkey);
+         }
+  }
+
+  if (lp_readraw() && lp_writeraw()) {
+         capabilities |= CAP_RAW_MODE;
+  }
+
+  if (lp_security() >= SEC_USER) secword |= 1;
   if (doencrypt) secword |= 2;
 
   /* 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
+  data_len = crypt_len + strlen(myworkgroup) + 1;
 
   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
+  strcpy(smb_buf(outbuf)+crypt_len, myworkgroup);
 
   CVAL(outbuf,smb_vwv1) = secword;
-#ifdef SMB_PASSWD
-  /* Create a token value and add it to the outgoing packet. */
-  if (doencrypt)
-  {
-    generate_next_challenge(smb_buf(outbuf));
-
-    /* Tell the nt machine how long the challenge is. */
-    SSVALS(outbuf,smb_vwv16+1,challenge_len);
-  }
-#endif
+  SSVALS(outbuf,smb_vwv16+1,crypt_len);
+  if (doencrypt) 
+         memcpy(smb_buf(outbuf), cryptkey, 8);
 
   Protocol = PROTOCOL_NT1;
 
-  if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) {
-    DEBUG(3,("using password server validation\n"));
-#ifdef SMB_PASSWD
-    if (doencrypt) set_challenge(smb_buf(outbuf));    
-#endif
-  }
-
-  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. LOTS! */
@@ -2911,7 +3889,6 @@ struct {
 ****************************************************************************/
 static int reply_negprot(char *inbuf,char *outbuf)
 {
-  extern fstring remote_arch;
   int outsize = set_message(outbuf,1,0,True);
   int Index=0;
   int choice= -1;
@@ -2951,22 +3928,22 @@ static int reply_negprot(char *inbuf,char *outbuf)
     
   switch ( arch ) {
   case ARCH_SAMBA:
-    strcpy(remote_arch,"Samba");
+    set_remote_arch(RA_SAMBA);
     break;
   case ARCH_WFWG:
-    strcpy(remote_arch,"WfWg");
+    set_remote_arch(RA_WFWG);
     break;
   case ARCH_WIN95:
-    strcpy(remote_arch,"Win95");
+    set_remote_arch(RA_WIN95);
     break;
   case ARCH_WINNT:
-    strcpy(remote_arch,"WinNT");
+    set_remote_arch(RA_WINNT);
     break;
   case ARCH_OS2:
-    strcpy(remote_arch,"OS2");
+    set_remote_arch(RA_OS2);
     break;
   default:
-    strcpy(remote_arch,"UNKNOWN");
+    set_remote_arch(RA_UNKNOWN);
     break;
   }
  
@@ -2998,7 +3975,7 @@ static int reply_negprot(char *inbuf,char *outbuf)
   SSVAL(outbuf,smb_vwv0,choice);
   if(choice != -1) {
     extern fstring remote_proto;
-    strcpy(remote_proto,supported_protocols[protocol].short_name);
+    fstrcpy(remote_proto,supported_protocols[protocol].short_name);
     reload_services(True);          
     outsize = supported_protocols[protocol].proto_reply_fn(outbuf);
     DEBUG(3,("Selected protocol %s\n",supported_protocols[protocol].proto_name));
@@ -3022,7 +3999,7 @@ static void close_open_files(int cnum)
   int i;
   for (i=0;i<MAX_OPEN_FILES;i++)
     if( Files[i].cnum == cnum && Files[i].open) {
-      close_file(i);
+      close_file(i,False);
     }
 }
 
@@ -3059,7 +4036,7 @@ void close_cnum(int cnum, uint16 vuid)
   dptr_closecnum(cnum);
 
   /* execute any "postexec = " line */
-  if (*lp_postexec(SNUM(cnum)) && become_user(cnum,vuid))
+  if (*lp_postexec(SNUM(cnum)) && become_user(&Connections[cnum], cnum,vuid))
     {
       pstring cmd;
       strcpy(cmd,lp_postexec(SNUM(cnum)));
@@ -3090,6 +4067,9 @@ void close_cnum(int cnum, uint16 vuid)
       Connections[cnum].ngroups = 0;
     }
 
+  free_namearray(Connections[cnum].veto_list);
+  free_namearray(Connections[cnum].hide_list);
+
   string_set(&Connections[cnum].user,"");
   string_set(&Connections[cnum].dirpath,"");
   string_set(&Connections[cnum].connectpath,"");
@@ -3114,7 +4094,7 @@ BOOL yield_connection(int cnum,char *name,int max_connections)
 
   bzero(&crec,sizeof(crec));
 
-  strcpy(fname,lp_lockdir());
+  pstrcpy(fname,lp_lockdir());
   standard_sub(cnum,fname);
   trim_string(fname,"","/");
 
@@ -3186,7 +4166,7 @@ BOOL claim_connection(int cnum,char *name,int max_connections,BOOL Clear)
 
   DEBUG(5,("trying claim %s %s %d\n",lp_lockdir(),name,max_connections));
 
-  strcpy(fname,lp_lockdir());
+  pstrcpy(fname,lp_lockdir());
   standard_sub(cnum,fname);
   trim_string(fname,"","/");
 
@@ -3282,7 +4262,7 @@ static BOOL dump_core(void)
 {
   char *p;
   pstring dname;
-  strcpy(dname,debugf);
+  pstrcpy(dname,debugf);
   if ((p=strrchr(dname,'/'))) *p=0;
   strcat(dname,"/corefiles");
   mkdir(dname,0700);
@@ -3325,7 +4305,7 @@ void exit_server(char *reason)
   DEBUG(2,("Closing connections\n"));
   for (i=0;i<MAX_CONNECTIONS;i++)
     if (Connections[i].open)
-      close_cnum(i,-1);
+      close_cnum(i,(uint16)-1);
 #ifdef DFS_AUTH
   if (dcelogin_atmost_once)
     dfs_unlogin();
@@ -3343,9 +4323,7 @@ void exit_server(char *reason)
 #endif
   }    
 
-#ifdef FAST_SHARE_MODES
-  stop_share_mode_mgmt();
-#endif /* FAST_SHARE_MODES */
+  locking_end();
 
   DEBUG(3,("%s Server exit  (%s)\n",timestring(),reason?reason:""));
   exit(0);
@@ -3354,22 +4332,28 @@ void exit_server(char *reason)
 /****************************************************************************
 do some standard substitutions in a string
 ****************************************************************************/
-void standard_sub(int cnum,char *s)
+void standard_sub(int cnum,char *str)
 {
-  if (!strchr(s,'%')) return;
-
-  if (VALID_CNUM(cnum))
-    {
-      string_sub(s,"%S",lp_servicename(Connections[cnum].service));
-      string_sub(s,"%P",Connections[cnum].connectpath);
-      string_sub(s,"%u",Connections[cnum].user);
-      if (strstr(s,"%H")) {
-       char *home = get_home_dir(Connections[cnum].user);
-       if (home) string_sub(s,"%H",home);
+  if (VALID_CNUM(cnum)) {
+    char *p, *s, *home;
+
+    for ( s=str ; (p=strchr(s, '%')) != NULL ; s=p ) {
+      switch (*(p+1)) {
+        case 'H' : if ((home = get_home_dir(Connections[cnum].user))!=NULL)
+                     string_sub(p,"%H",home);
+                   else
+                     p += 2;
+                   break;
+        case 'P' : string_sub(p,"%P",Connections[cnum].connectpath); break;
+        case 'S' : string_sub(p,"%S",lp_servicename(Connections[cnum].service)); break;
+        case 'g' : string_sub(p,"%g",gidtoname(Connections[cnum].gid)); break;
+        case 'u' : string_sub(p,"%u",Connections[cnum].user); break;
+        case '\0' : p++; break; /* don't run off the end of the string */
+        default  : p+=2; break;
       }
-      string_sub(s,"%g",gidtoname(Connections[cnum].gid));
     }
-  standard_sub_basic(s);
+  }
+  standard_sub_basic(str);
 }
 
 /*
@@ -3575,7 +4559,7 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize
            unbecome_user();
 
          /* does this protocol need to be run as the connected user? */
-         if ((flags & AS_USER) && !become_user(cnum,session_tag)) {
+         if ((flags & AS_USER) && !become_user(&Connections[cnum], cnum,session_tag)) {
            if (flags & AS_GUEST) 
              flags &= ~AS_USER;
            else
@@ -3748,6 +4732,7 @@ int construct_reply(char *inbuf,char *outbuf,int size,int bufsize)
 
   chain_size = 0;
   chain_fnum = -1;
+  reset_chain_pnum();
 
   bzero(outbuf,smb_size);
 
@@ -3778,14 +4763,11 @@ int construct_reply(char *inbuf,char *outbuf,int size,int bufsize)
   return(outsize);
 }
 
-
 /****************************************************************************
   process commands from the client
 ****************************************************************************/
 static void process(void)
 {
-  static int trans_num = 0;
-  int nread;
   extern int Client;
 
   InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
@@ -3807,141 +4789,116 @@ static void process(void)
   }
 #endif    
 
-  while (True)
-    {
-      int32 len;      
-      int msg_type;
-      int msg_flags;
-      int type;
-      int deadtime = lp_deadtime()*60;
-      int counter;
-      int last_keepalive=0;
-
-      if (deadtime <= 0)
-       deadtime = DEFAULT_SMBD_TIMEOUT;
-
-      if (lp_readprediction())
-       do_read_prediction();
-
-      errno = 0;      
-
-      for (counter=SMBD_SELECT_LOOP; 
-          !receive_smb(Client,InBuffer,SMBD_SELECT_LOOP*1000); 
-          counter += SMBD_SELECT_LOOP)
-       {
-         int i;
-         time_t t;
-         BOOL allidle = True;
-         extern int keepalive;
-
-         if (smb_read_error == READ_EOF) {
-           DEBUG(3,("end of file from client\n"));
-           return;
-         }
-
-         if (smb_read_error == READ_ERROR) {
-           DEBUG(3,("receive_smb error (%s) exiting\n",
-                    strerror(errno)));
-           return;
-         }
-
-         t = time(NULL);
-
-         /* become root again if waiting */
-         unbecome_user();
+  /* re-initialise the timezone */
+  TimeInit();
 
-         /* check for smb.conf reload */
-         if (!(counter%SMBD_RELOAD_CHECK))
-           reload_services(True);
+  while (True)
+  {
+    int deadtime = lp_deadtime()*60;
+    int counter;
+    int last_keepalive=0;
+    int service_load_counter = 0;
+    BOOL got_smb = False;
+
+    if (deadtime <= 0)
+      deadtime = DEFAULT_SMBD_TIMEOUT;
+
+#if USE_READ_PREDICTION
+    if (lp_readprediction())
+      do_read_prediction();
+#endif
 
-#if 0 /* JRA */
-         /* check the share modes every 10 secs */
-         if (!(counter%SHARE_MODES_CHECK))
-           check_share_modes();
+    errno = 0;      
 
-         /* clean the share modes every 5 minutes */
-         if (!(counter%SHARE_MODES_CLEAN))
-           clean_share_modes();
-#endif /* JRA */
+    for (counter=SMBD_SELECT_LOOP; 
+          !receive_message_or_smb(Client,oplock_sock,
+                      InBuffer,BUFFER_SIZE,SMBD_SELECT_LOOP*1000,&got_smb); 
+          counter += SMBD_SELECT_LOOP)
+    {
+      int i;
+      time_t t;
+      BOOL allidle = True;
+      extern int keepalive;
 
-         /* automatic timeout if all connections are closed */      
-         if (num_connections_open==0 && counter >= IDLE_CLOSED_TIMEOUT) {
-           DEBUG(2,("%s Closing idle connection\n",timestring()));
-           return;
-         }
+      if (counter > 365 * 3600) /* big number of seconds. */
+      {
+        counter = 0;
+        service_load_counter = 0;
+      }
 
-         if (keepalive && (counter-last_keepalive)>keepalive) {
-           extern int password_client;
-           if (!send_keepalive(Client)) {
-             DEBUG(2,("%s Keepalive failed - exiting\n",timestring()));
-             return;
-           }       
-           /* also send a keepalive to the password server if its still
-              connected */
-           if (password_client != -1)
-             send_keepalive(password_client);
-           last_keepalive = counter;
-         }
+      if (smb_read_error == READ_EOF) 
+      {
+        DEBUG(3,("end of file from client\n"));
+        return;
+      }
 
-         /* check for connection timeouts */
-         for (i=0;i<MAX_CONNECTIONS;i++)
-           if (Connections[i].open)
-             {
-               /* close dirptrs on connections that are idle */
-               if ((t-Connections[i].lastused)>DPTR_IDLE_TIMEOUT)
-                 dptr_idlecnum(i);
-
-               if (Connections[i].num_files_open > 0 ||
-                   (t-Connections[i].lastused)<deadtime)
-                 allidle = False;
-             }
-
-         if (allidle && num_connections_open>0) {
-           DEBUG(2,("%s Closing idle connection 2\n",timestring()));
-           return;
-         }
-       }
+      if (smb_read_error == READ_ERROR) 
+      {
+        DEBUG(3,("receive_smb error (%s) exiting\n",
+                  strerror(errno)));
+        return;
+      }
 
-      msg_type = CVAL(InBuffer,0);
-      msg_flags = CVAL(InBuffer,1);
-      type = CVAL(InBuffer,smb_com);
+      t = time(NULL);
 
-      len = smb_len(InBuffer);
+      /* become root again if waiting */
+      unbecome_user();
 
-      DEBUG(6,("got message type 0x%x of len 0x%x\n",msg_type,len));
+      /* check for smb.conf reload */
+      if (counter >= service_load_counter + SMBD_RELOAD_CHECK)
+      {
+        service_load_counter = counter;
 
-      nread = len + 4;
-      
-      DEBUG(3,("%s Transaction %d of length %d\n",timestring(),trans_num,nread));
+        /* reload services, if files have changed. */
+        reload_services(True);
+      }
 
-#ifdef WITH_VTP
-      if(trans_num == 1 && VT_Check(InBuffer)) {
-        VT_Process();
+      /* automatic timeout if all connections are closed */      
+      if (num_connections_open==0 && counter >= IDLE_CLOSED_TIMEOUT) 
+      {
+        DEBUG(2,("%s Closing idle connection\n",timestring()));
         return;
       }
-#endif
 
+      if (keepalive && (counter-last_keepalive)>keepalive) 
+      {
+             struct cli_state *cli = server_client();
+             if (!send_keepalive(Client)) { 
+                     DEBUG(2,("%s Keepalive failed - exiting\n",timestring()));
+                     return;
+             }     
+             /* also send a keepalive to the password server if its still
+                connected */
+             if (cli && cli->initialised)
+                     send_keepalive(cli->fd);
+             last_keepalive = counter;
+      }
 
-      if (msg_type == 0)
-       show_msg(InBuffer);
+      /* check for connection timeouts */
+      for (i=0;i<MAX_CONNECTIONS;i++)
+        if (Connections[i].open)
+        {
+          /* close dirptrs on connections that are idle */
+          if ((t-Connections[i].lastused)>DPTR_IDLE_TIMEOUT)
+            dptr_idlecnum(i);
 
-      nread = construct_reply(InBuffer,OutBuffer,nread,max_send);
-      
-      if(nread > 0) {
-        if (CVAL(OutBuffer,0) == 0)
-         show_msg(OutBuffer);
-       
-        if (nread != smb_len(OutBuffer) + 4) 
-         {
-           DEBUG(0,("ERROR: Invalid message response size! %d %d\n",
-                    nread,
-                    smb_len(OutBuffer)));
-         }
-       else
-         send_smb(Client,OutBuffer);
+          if (Connections[i].num_files_open > 0 ||
+                     (t-Connections[i].lastused)<deadtime)
+            allidle = False;
+        }
+
+      if (allidle && num_connections_open>0) 
+      {
+        DEBUG(2,("%s Closing idle connection 2\n",timestring()));
+        return;
       }
-      trans_num++;
     }
+
+    if(got_smb)
+      process_smb(InBuffer, OutBuffer);
+    else
+      process_local_message(oplock_sock, InBuffer, BUFFER_SIZE);
+  }
 }
 
 
@@ -3984,6 +4941,14 @@ static void init_structs(void )
       fd_ptr->real_open_flags = -1;
     }
 
+  /* for RPC pipes */
+  init_rpc_pipe_hnd();
+
+#ifdef NTDOMAIN
+  /* for LSA handles */
+  init_lsa_policy_hnd();
+#endif
+
   init_dptrs();
 }
 
@@ -4121,7 +5086,7 @@ static void usage(char *pname)
   reopen_logs();
 
   DEBUG(2,("%s smbd version %s started\n",timestring(),VERSION));
-  DEBUG(2,("Copyright Andrew Tridgell 1992-1995\n"));
+  DEBUG(2,("Copyright Andrew Tridgell 1992-1997\n"));
 
 #ifndef NO_GETRLIMIT
 #ifdef RLIMIT_NOFILE
@@ -4151,6 +5116,8 @@ static void usage(char *pname)
   if (!reload_services(False))
     return(-1);        
 
+  codepage_initialise(lp_client_code_page());
+
   strcpy(myworkgroup, lp_workgroup());
 
 #ifndef NO_SIGNAL_TEST
@@ -4177,7 +5144,10 @@ static void usage(char *pname)
       char    buf[20];
 
       if ((fd = open(pidFile,
-         O_NONBLOCK | O_CREAT | O_WRONLY | O_TRUNC, 0644)) < 0)
+#ifdef O_NONBLOCK
+         O_NONBLOCK | 
+#endif
+         O_CREAT | O_WRONLY | O_TRUNC, 0644)) < 0)
         {
            DEBUG(0,("ERROR: can't open %s: %s\n", pidFile, strerror(errno)));
            exit(1);
@@ -4199,10 +5169,8 @@ static void usage(char *pname)
   if (!open_sockets(is_daemon,port))
     exit(1);
 
-#ifdef FAST_SHARE_MODES
-  if (!start_share_mode_mgmt())
+  if (!locking_init(0))
     exit(1);
-#endif /* FAST_SHARE_MODES */
 
   /* possibly reload the services file. */
   reload_services(True);
@@ -4215,6 +5183,10 @@ static void usage(char *pname)
        DEBUG(2,("%s changed root to %s\n",timestring(),lp_rootdir()));
     }
 
+  /* Setup the oplock IPC socket. */
+  if(!open_oplock_ipc())
+    exit(1);
+
   process();
   close_sockets();