make the initial logfile names consistent. This should mean that smbd
[samba.git] / source / smbd / server.c
index 110d31b30293a27cc886e6c9cca6425d86eec716..c2880b0e890cc0c11c4bbe23fe32cde0de7b07ec 100644 (file)
@@ -2,7 +2,7 @@
    Unix SMB/Netbios implementation.
    Version 1.9.
    Main SMB server routines
-   Copyright (C) Andrew Tridgell 1992-1997
+   Copyright (C) Andrew Tridgell 1992-1998
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -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,15 +84,17 @@ int chain_fnum = -1;
 /* number of open connections */
 static int num_connections_open = 0;
 
-#ifdef USE_OPLOCKS
 /* Oplock ipc UDP socket. */
 int oplock_sock = -1;
-int oplock_port = -1;
-#endif /* USE_OPLOCKS */
+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;
@@ -185,7 +187,7 @@ int dos_mode(int cnum,char *path,struct stat *sbuf)
   int result = 0;
   extern struct current_user current_user;
 
-  DEBUG(5,("dos_mode: %d %s\n", cnum, path));
+  DEBUG(8,("dos_mode: %d %s\n", cnum, path));
 
   if (CAN_WRITE(cnum) && !lp_alternate_permissions(SNUM(cnum))) {
     if (!((sbuf->st_mode & S_IWOTH) ||
@@ -212,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 . */
@@ -237,20 +241,19 @@ int dos_mode(int cnum,char *path,struct stat *sbuf)
     result |= aHIDDEN;
   }
 
-  DEBUG(5,("dos_mode returning "));
+  DEBUG(8,("dos_mode returning "));
 
-  if (result & aHIDDEN) DEBUG(5, ("h"));
-  if (result & aRONLY ) DEBUG(5, ("r"));
-  if (result & aSYSTEM) DEBUG(5, ("s"));
-  if (result & aDIR   ) DEBUG(5, ("d"));
-  if (result & aARCH  ) DEBUG(5, ("a"));
+  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(5,("\n"));
+  DEBUG(8,("\n"));
 
   return(result);
 }
 
-
 /*******************************************************************
 chmod a file - but preserve some bits
 ********************************************************************/
@@ -304,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
@@ -382,8 +452,20 @@ static BOOL scan_directory(char *path, char *name,int cnum,BOOL docache)
     return(True);
   }      
 
+#if 0 
+  /* 
+   * This code I believe is incorrect - and commenting it out
+   * is the correct fix for the bug mentioned below in the
+   * comment 'name2 here was changed to dname - since 1.9.16p2 - not sure of reason (jra)'.
+   * The incoming name can be mangled, and if we de-mangle it
+   * here it will not compare correctly against the filename (name2)
+   * read from the directory and then mangled by the name_map_mangle()
+   * call. We need to mangle both names or neither.
+   * (JRA).
+   */
   if (mangled)
     check_mangled_stack(name);
+#endif 
 
   /* open the directory */
   if (!(cur_dir = OpenDir(cnum, path, True))) 
@@ -399,7 +481,7 @@ static BOOL scan_directory(char *path, char *name,int cnum,BOOL docache)
          (strequal(dname,".") || strequal(dname,"..")))
        continue;
 
-      strcpy(name2,dname);
+      pstrcpy(name2,dname);
       if (!name_map_mangle(name2,False,SNUM(cnum))) continue;
 
       if ((mangled && mangled_equal(name,name2))
@@ -545,7 +627,7 @@ BOOL unix_convert(char *name,int cnum,pstring saved_last_component, BOOL *bad_pa
 
          /* 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,'*') ||
@@ -709,7 +791,15 @@ int disk_free(char *path,int *bsize,int *dfree,int *dsize)
                            dfree_retval : dfreeq_retval ;
           /* maybe dfree and dfreeq are calculated using different bsizes 
              so convert dfree from bsize into bsizeq */
-          *dfree = ((*dfree) * (*bsize)) / (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;
@@ -799,7 +889,15 @@ if ((*bsize) < 512 || (*bsize)>0xFFFF) *bsize = 1024;
                        dfree_retval : dfreeq_retval ;
       /* maybe dfree and dfreeq are calculated using different bsizes 
          so convert dfree from bsize into bsizeq */
-      *dfree = ((*dfree) * (*bsize)) / (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;
@@ -845,6 +943,7 @@ BOOL check_name(char *name,int cnum)
   /* Patch from David Clerc <David.Clerc@cui.unige.ch>
      University of Geneva */
 
+#ifdef S_ISLNK
   if (!lp_symlinks(SNUM(cnum)))
     {
       struct stat statbuf;
@@ -855,6 +954,7 @@ BOOL check_name(char *name,int cnum)
           ret=0; 
         }
     }
+#endif
 
   if (!ret)
     DEBUG(5,("check_name on %s failed\n",name));
@@ -882,8 +982,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);
 
@@ -935,7 +1034,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;
@@ -962,7 +1061,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;
@@ -995,8 +1094,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);
 
@@ -1016,7 +1114,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],
@@ -1052,20 +1150,43 @@ 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];
+  int accmode = (flags & (O_RDONLY | O_WRONLY | O_RDWR));
 
-  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)
-    {
+
+  /*
+   * This code was changed after seeing a client open request 
+   * containing the open mode of (DENY_WRITE/read-only) with
+   * the 'create if not exist' bit set. The previous code
+   * would fail to open the file read only on a read-only share
+   * as it was checking the flags parameter  directly against O_RDONLY,
+   * this was failing as the flags parameter was set to O_RDONLY|O_CREAT.
+   * JRA.
+   */
+
+  if (!CAN_WRITE(cnum) && !Connections[cnum].printer) {
+    /* It's a read-only share - fail if we wanted to write. */
+    if(accmode != O_RDONLY) {
       DEBUG(3,("Permission denied opening %s\n",fname));
       check_for_pipe(fname);
       return;
     }
+    else if(flags & O_CREAT) {
+      /* We don't want to write - but we must make sure that O_CREAT
+         doesn't create the file if we have write access into the
+         directory.
+       */
+      flags &= ~O_CREAT;
+    }
+  }
 
   /* this handles a bug in Win95 - it doesn't say to create the file when it 
      should */
@@ -1077,13 +1198,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.
@@ -1110,8 +1224,6 @@ static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct
    */
   if((fd_ptr = fd_get_already_open(sbuf))!= 0) {
 
-    int accmode = (flags & (O_RDONLY | O_WRONLY | O_RDWR));
-
     /* File was already open. */
     if((flags & O_CREAT) && (flags & O_EXCL)) {
       fd_ptr->ref_count--;
@@ -1186,13 +1298,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;
@@ -1228,25 +1340,27 @@ 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->vuid = current_user.vuid;
+      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->sent_oplock_break = 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
@@ -1255,8 +1369,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);
@@ -1264,23 +1378,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
@@ -1321,10 +1435,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);
 
@@ -1338,30 +1452,40 @@ 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;
 
+  Files[fnum].reserved = False;
+
+#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)))
@@ -1376,11 +1500,17 @@ 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);
+
+  if(fs_p->granted_oplock == True)
+    global_oplocks_open--;
+
+  fs_p->sent_oplock_break = False;
 
   DEBUG(2,("%s %s closed file %s (numopen=%d)\n",
           timestring(),Connections[cnum].user,fs_p->name,
@@ -1398,7 +1528,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);
@@ -1443,32 +1574,112 @@ static int access_table(int new_deny,int old_deny,int old_mode,
 check if the share mode on a file allows it to be deleted or unlinked
 return True if sharing doesn't prevent the operation
 ********************************************************************/
-BOOL check_file_sharing(int cnum,char *fname)
+BOOL check_file_sharing(int cnum,char *fname, BOOL rename_op)
 {
   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
+    {
+
+      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)
+        {
+
+          /*
+           * It appears that the NT redirector may have a bug, in that
+           * it tries to do an SMBmv on a file that it has open with a
+           * batch oplock, and then fails to respond to the oplock break
+           * request. This only seems to occur when the client is doing an
+           * SMBmv to the smbd it is using - thus we try and detect this
+           * condition by checking if the file being moved is open and oplocked by
+           * this smbd process, and then not sending the oplock break in this
+           * special case. If the file was open with a deny mode that 
+           * prevents the move the SMBmv will fail anyway with a share
+           * violation error. JRA.
+           */
+          if(rename_op && (share_entry->pid == pid))
+          {
+            DEBUG(0,("check_file_sharing: NT redirector workaround - rename attempted on \
+batch oplocked file %s, dev = %x, inode = %x\n", fname, dev, inode));
+            /* 
+             * This next line is a test that allows the deny-mode
+             * processing to be skipped. This seems to be needed as
+             * NT insists on the rename succeeding (in Office 9x no less !).
+             * This should be removed as soon as (a) MS fix the redirector
+             * bug or (b) NT SMB support in Samba makes NT not issue the
+             * call (as is my fervent hope). JRA.
+             */ 
+            continue;
+          }
+          else
+          {
+            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;
+          }
+        }
 
-    if(old_shares[i].pid != pid)
-      goto free_and_exit;
+        /* 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
@@ -1479,7 +1690,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);
@@ -1490,8 +1701,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)){
@@ -1500,7 +1711,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;
@@ -1512,12 +1723,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,fcbopen = %d, flags = %d) = %d\n",
+                deny_mode,old_deny_mode,old_open_mode,
+                share->pid,fname, fcbopen, *flags, 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;
@@ -1527,9 +1778,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;
@@ -1601,10 +1853,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)
     {
@@ -1612,58 +1862,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 (old_deny_mode > 4 || old_open_mode > 2) 
+      do
       {
-       DEBUG(0,("Invalid share mode found (%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));
 
-       if ((access_allowed == AFAIL) ||
-           (!fcbopen && (access_allowed == AREAD && flags == O_RDWR)) ||
-           (access_allowed == AREAD && flags == O_WRONLY) ||
-           (access_allowed == AWRITE && flags == O_RDONLY)) 
+            /* 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(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);
   }
@@ -1720,7 +1989,32 @@ 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)) && 
+             !IS_VETO_OPLOCK_PATH(cnum,fname))
+      {
+        fs_p->granted_oplock = True;
+        fs_p->sent_oplock_break = False;
+        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);
@@ -1751,6 +2045,7 @@ 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);
@@ -1759,6 +2054,7 @@ int read_file(int fnum,char *data,uint32 pos,int n)
       n -= ret;
       pos += ret;
     }
+#endif
 
 #if USE_MMAP
   if (Files[fnum].mmap_ptr)
@@ -1969,7 +2265,7 @@ struct
   {EPERM,ERRDOS,ERRnoaccess},
   {EACCES,ERRDOS,ERRnoaccess},
   {ENOENT,ERRDOS,ERRbadfile},
-  {ENOTDIR,ERRDOS,ERRbaddirectory},
+  {ENOTDIR,ERRDOS,ERRbadpath},
   {EIO,ERRHRD,ERRgeneral},
   {EBADF,ERRSRV,ERRsrverror},
   {EINVAL,ERRSRV,ERRsrverror},
@@ -1990,20 +2286,6 @@ struct
   {0,0,0}
 };
 
-/* Mapping for old clients. */
-
-struct
-{
-  int new_smb_error;
-  int old_smb_error;
-  int protocol_level;
-  enum remote_arch_types valid_ra_type;
-} old_client_errmap[] =
-{
-  {ERRbaddirectory, ERRbadpath, (int)PROTOCOL_NT1, RA_WINNT},
-  {0,0,0}
-};
-
 /****************************************************************************
   create an error packet from errno
 ****************************************************************************/
@@ -2034,29 +2316,6 @@ int unix_error_packet(char *inbuf,char *outbuf,int def_class,uint32 def_code,int
       }
     }
 
-  /* Make sure we don't return error codes that old
-     clients don't understand. */
-
-  /* JRA - unfortunately, WinNT needs some error codes
-     for apps to work correctly, Win95 will break if
-     these error codes are returned. But they both
-     negotiate the *same* protocol. So we need to use
-     the revolting 'remote_arch' enum to tie break.
-
-     There must be a better way of doing this...
-  */
-
-  for(i = 0; old_client_errmap[i].new_smb_error != 0; i++)
-  {
-    if(((Protocol < old_client_errmap[i].protocol_level) ||
-       (old_client_errmap[i].valid_ra_type != get_remote_arch())) &&
-       (old_client_errmap[i].new_smb_error == ecode))
-    {
-      ecode = old_client_errmap[i].old_smb_error;
-      break;
-    }
-  }
-
   return(error_packet(inbuf,outbuf,eclass,ecode,line));
 }
 
@@ -2134,193 +2393,833 @@ static int sig_cld()
 }
 #endif
 
-/****************************************************************************
-  this is called when the client exits abruptly
-  **************************************************************************/
-static int sig_pipe()
-{
-  extern int password_client;
-  BlockSignals(True,SIGPIPE);
+/****************************************************************************
+  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);
+  else if(msg_type == 0x85)
+    return; /* Keepalive packet. */
+
+  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;
+  char *inbuf = NULL;
+  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));
+
+  /* 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))
+    {
+      if((Files[fnum].fd_ptr->dev == dev) && (Files[fnum].fd_ptr->inode == inode) &&
+         (Files[fnum].open_time.tv_sec == tval->tv_sec) && 
+         (Files[fnum].open_time.tv_usec == tval->tv_usec)) {
+             fsp = &Files[fnum];
+             break;
+      }
+    }
+  }
+
+  if(fsp == NULL)
+  {
+    /* The file could have been closed in the meantime - return success. */
+    DEBUG(0,("%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(0,("%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;
+  }
+
+  /* mark the oplock break as sent - we don't want to send twice! */
+  if (fsp->sent_oplock_break)
+  {
+    DEBUG(0,("%s oplock_break: ERROR: oplock_break already sent for file %s (fnum = %d, dev = %x, inode = %x)\n", timestring(), fsp->name, fnum, dev, inode));
+
+    /* We have to fail the open here as we cannot send another oplock break on this
+       file whilst we are awaiting a response from the client - neither can we
+       allow another open to succeed while we are waiting for the client. */
+    return False;
+  }
+
+  /* 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.
+     At this point we know we need a new inbuf/outbuf buffer pair.
+     We cannot use these staticaly as we may recurse into here due to
+     messages crossing on the wire.
+   */
+
+  if((inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN))==NULL)
+  {
+    DEBUG(0,("oplock_break: malloc fail for input buffer.\n"));
+    return False;
+  }
+
+  if((outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN))==NULL)
+  {
+    DEBUG(0,("oplock_break: malloc fail for output buffer.\n"));
+    free(inbuf);
+    inbuf = NULL;
+    return False;
+  }
+
+  /* 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);
+
+  /* Remember we just sent an oplock break on this file. */
+  fsp->sent_oplock_break = True;
+
+  /* We need this in case a readraw crosses on the wire. */
+  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;
+    }
+
+    /*
+     * There are certain SMB requests that we shouldn't allow
+     * to recurse. opens, renames and deletes are the obvious
+     * ones. This is handled in the switch_message() function.
+     * If global_oplock_break is set they will push the packet onto
+     * the pending smb queue and return -1 (no reply).
+     * JRA.
+     */
+
+    process_smb(inbuf, outbuf);
+
+    /*
+     * Die if we go over the time limit.
+     */
+
+    if((time(NULL) - start_time) > OPLOCK_BREAK_TIMEOUT)
+    {
+      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;
+    }
+  }
+
+  /* Free the buffers we've been using to recurse. */
+  free(inbuf);
+  free(outbuf);
+
+  /* We need this in case a readraw crossed on the wire. */
+  if(global_oplock_break)
+    global_oplock_break = False;
+
+  /*
+   * If the client did not respond we must die.
+   */
+
+  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");
+  }
 
-  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;
+  if(OPEN_FNUM(fnum))
+  {
+    /* The lockingX reply will have removed the oplock flag 
+       from the sharemode. */
+    /* Paranoia.... */
+    fsp->granted_oplock = False;
+    fsp->sent_oplock_break = False;
+    global_oplocks_open--;
   }
 
-  exit_server("Got sigpipe\n");
-  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");
+  }
+
+  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();
+  time_t start_time;
+  int time_left;
 
-  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\n",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\n",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);
+  start_time = time(NULL);
+  time_left = OPLOCK_BREAK_TIMEOUT+OPLOCK_BREAK_TIMEOUT_FUDGEFACTOR;
 
-             /* 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
+  while(time_left >= 0)
+  {
+    char op_break_reply[UDP_CMD_HEADER_LEN+OPLOCK_BREAK_MSG_LEN];
+    int32 reply_msg_len;
+    uint16 reply_from_port;
+    char *reply_msg_start;
+
+    if(receive_local_message(oplock_sock, op_break_reply, sizeof(op_break_reply),
+               time_left ? time_left * 1000 : 1) == 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();
+    reply_msg_len = IVAL(op_break_reply,UDP_CMD_LEN_OFFSET);
+    reply_from_port = SVAL(op_break_reply,UDP_CMD_PORT_OFFSET);
 
-      set_socket_options(Client,"SO_KEEPALIVE");
-      set_socket_options(Client,user_socket_options);
-    }
+    reply_msg_start = &op_break_reply[UDP_CMD_HEADER_LEN];
 
-  return True;
-}
+    if(reply_msg_len != OPLOCK_BREAK_MSG_LEN)
+    {
+      /* Ignore it. */
+      DEBUG(0,("%s request_oplock_break: invalid message length received. Ignoring\n",
+             timestring()));
+      continue;
+    }
 
-#ifdef USE_OPLOCKS
-/****************************************************************************
-  open the oplock IPC socket communication
-****************************************************************************/
-static BOOL open_oplock_ipc()
-{
-  struct sockaddr_in sock_name;
-  int name_len = sizeof(sock_name);
+    /*
+     * Test to see if this is the reply we are awaiting.
+     */
 
-  DEBUG(3,("open_oplock_ipc: opening loopback UDP socket.\n"));
+    if((SVAL(reply_msg_start,UDP_MESSAGE_CMD_OFFSET) & CMD_REPLY) &&
+       (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))
+    {
+      /*
+       * This is the reply we've been waiting for.
+       */
+      break;
+    }
+    else
+    {
+      /*
+       * This is another message - probably a break request.
+       * Process it to prevent potential deadlock.
+       * Note that the code in switch_message() prevents
+       * us from recursing into here as any SMB requests
+       * we might process that would cause another oplock
+       * break request to be made will be queued.
+       * JRA.
+       */
 
-  /* Open a lookback UDP socket on a random port. */
-  oplock_sock = open_socket_in(SOCK_DGRAM, 0, 0,interpret_addr("127.0.0.1"));
-  if (oplock_sock == -1)
-    return(False);
+      process_local_message(oplock_sock, op_break_reply, sizeof(op_break_reply));
+    }
 
-  /* Find out the transient UDP port we have been allocated. */
-  if(getsockname(oplock_sock, (struct sockaddr *)&sock_name, &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;
-    return False;
+    time_left -= (time(NULL) - start_time);
   }
-  oplock_port = ntohs(sock_name.sin_port);
+
+  DEBUG(3,("%s request_oplock_break: broke oplock.\n", timestring()));
 
   return True;
 }
 
 /****************************************************************************
-  process an oplock break message.
+Get the next SMB packet, doing the local message processing automatically.
 ****************************************************************************/
-static BOOL process_local_message(int oplock_sock, char *buffer, int buf_size)
+
+BOOL receive_next_smb(int smbfd, int oplockfd, char *inbuf, int bufsize, int timeout)
 {
-  int32 msg_len;
-  int16 port;
-  struct in_addr from;
-  char *msg_start;
+  BOOL got_smb = False;
+  BOOL ret;
 
-  msg_len = IVAL(buffer,0);
-  port = SVAL(buffer,4);
-  memcpy((char *)&from, &buffer[6], sizeof(struct in_addr));
+  do
+  {
+    ret = receive_message_or_smb(smbfd,oplockfd,inbuf,bufsize,
+                                 timeout,&got_smb);
 
-  msg_start = &buffer[6 + sizeof(struct in_addr)];
+    if(ret && !got_smb)
+    {
+      /* Deal with oplock break requests from other smbd's. */
+      process_local_message(oplock_sock, inbuf, bufsize);
+      continue;
+    }
+
+    if(ret && (CVAL(inbuf,0) == 0x85))
+    {
+      /* Keepalive packet. */
+      got_smb = False;
+    }
 
-  /* Validate message length. */
-  if(msg_len > (buf_size  - (6 + sizeof(struct in_addr))))
-  {
-    DEBUG(0,("process_local_message: invalid msg_len (%d) max can be %d\n",
-              msg_len, buf_size  - (6 + sizeof(struct in_addr))));
-    return False;
   }
+  while(ret && !got_smb);
 
-  /* Validate message from address (must be localhost). */
-  return True;
+  return ret;
 }
-#endif /* USE_OPLOCKS */
 
 /****************************************************************************
 check if a snum is in use
@@ -2344,10 +3243,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;
        }
     }
@@ -2377,7 +3276,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);
@@ -2406,7 +3305,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))
     {
@@ -2421,19 +3321,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
@@ -2455,16 +3361,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;
            }
@@ -2590,8 +3498,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));
@@ -2612,6 +3529,7 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
   pcon->dirptr = NULL;
   pcon->veto_list = NULL;
   pcon->hide_list = NULL;
+  pcon->veto_oplock_list = NULL;
   string_set(&pcon->dirpath,"");
   string_set(&pcon->user,user);
 
@@ -2640,13 +3558,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));    
        }
@@ -2656,7 +3574,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));
@@ -2664,12 +3582,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,
@@ -2692,13 +3613,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;
@@ -2732,7 +3653,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);
@@ -2746,7 +3667,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);
     }
@@ -2759,6 +3680,7 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
   {
     set_namearray( &pcon->veto_list, lp_veto_files(SNUM(cnum)));
     set_namearray( &pcon->hide_list, lp_hide_files(SNUM(cnum)));
+    set_namearray( &pcon->veto_oplock_list, lp_veto_oplocks(SNUM(cnum)));
   }
 
   {
@@ -2775,20 +3697,99 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
   return(cnum);
 }
 
+/****************************************************************************
+  Attempt to break an oplock on a file (if oplocked).
+  Returns True if the file was closed as a result of
+  the oplock break, False otherwise.
+  Used as a last ditch attempt to free a space in the 
+  file table when we have run out.
+****************************************************************************/
+
+static BOOL attempt_close_oplocked_file(files_struct *fp)
+{
+
+  DEBUG(5,("attempt_close_oplocked_file: checking file %s.\n", fp->name));
+
+  if (fp->open && fp->granted_oplock && !fp->sent_oplock_break) {
+
+    /* Try and break the oplock. */
+    file_fd_struct *fsp = fp->fd_ptr;
+    if(oplock_break( fsp->dev, fsp->inode, &fp->open_time)) {
+      if(!fp->open) /* Did the oplock break close the file ? */
+        return True;
+    }
+  }
+
+  return False;
+}
 
 /****************************************************************************
   find first available file slot
 ****************************************************************************/
 int find_free_file(void )
 {
-  int i;
-  /* we start at 1 here for an obscure reason I can't now remember,
-     but I think is important :-) */
-  for (i=1;i<MAX_OPEN_FILES;i++)
-    if (!Files[i].open)
-      return(i);
-  DEBUG(1,("ERROR! Out of file structures - perhaps increase MAX_OPEN_FILES?\n"));
-  return(-1);
+       int i;
+       static int first_file;
+
+       /* we want to give out file handles differently on each new
+          connection because of a common bug in MS clients where they try to
+          reuse a file descriptor from an earlier smb connection. This code
+          increases the chance that the errant client will get an error rather
+          than causing corruption */
+       if (first_file == 0) {
+               first_file = (getpid() ^ (int)time(NULL)) % MAX_OPEN_FILES;
+               if (first_file == 0) first_file = 1;
+       }
+
+       if (first_file >= MAX_OPEN_FILES)
+               first_file = 1;
+
+       for (i=first_file;i<MAX_OPEN_FILES;i++)
+               if (!Files[i].open && !Files[i].reserved) {
+                       memset(&Files[i], 0, sizeof(Files[i]));
+                       first_file = i+1;
+                       Files[i].reserved = True;
+                       return(i);
+               }
+
+       /* returning a file handle of 0 is a bad idea - so we start at 1 */
+       for (i=1;i<first_file;i++)
+               if (!Files[i].open && !Files[i].reserved) {
+                       memset(&Files[i], 0, sizeof(Files[i]));
+                       first_file = i+1;
+                       Files[i].reserved = True;
+                       return(i);
+               }
+
+        /* 
+         * Before we give up, go through the open files 
+         * and see if there are any files opened with a
+         * batch oplock. If so break the oplock and then
+         * re-use that entry (if it becomes closed).
+         * This may help as NT/95 clients tend to keep
+         * files batch oplocked for quite a long time
+         * after they have finished with them.
+         */
+        for (i=first_file;i<MAX_OPEN_FILES;i++) {
+          if(attempt_close_oplocked_file( &Files[i])) {
+            memset(&Files[i], 0, sizeof(Files[i]));
+            first_file = i+1;
+            Files[i].reserved = True;
+            return(i);
+          }
+        }
+
+        for (i=1;i<MAX_OPEN_FILES;i++) {
+          if(attempt_close_oplocked_file( &Files[i])) {
+            memset(&Files[i], 0, sizeof(Files[i]));
+            first_file = i+1;
+            Files[i].reserved = True;
+            return(i);
+          }
+        }
+
+       DEBUG(1,("ERROR! Out of file structures - perhaps increase MAX_OPEN_FILES?\n"));
+       return(-1);
 }
 
 /****************************************************************************
@@ -2867,11 +3868,6 @@ 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;
@@ -2884,13 +3880,7 @@ int reply_lanman1(char *outbuf)
 
   Protocol = PROTOCOL_LANMAN1;
 
-  if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) {
-    DEBUG(3,("using password server validation\n"));
-  if (doencrypt) set_challenge(smb_buf(outbuf));    
-  }
-
   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);
@@ -2914,32 +3904,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); 
-  /* Create a token value and add it to the outgoing packet. */
-  if (doencrypt) 
-    generate_next_challenge(smb_buf(outbuf));
+  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"));
-    if (doencrypt) set_challenge(smb_buf(outbuf));    
-  }
-
   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);
@@ -2961,67 +3960,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;
-  /* 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);
-  }
+  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"));
-    if (doencrypt) set_challenge(smb_buf(outbuf));    
-  }
-
-  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! */
@@ -3205,7 +4195,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));
@@ -3229,7 +4219,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);
     }
 }
 
@@ -3266,7 +4256,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)));
@@ -3299,6 +4289,7 @@ void close_cnum(int cnum, uint16 vuid)
 
   free_namearray(Connections[cnum].veto_list);
   free_namearray(Connections[cnum].hide_list);
+  free_namearray(Connections[cnum].veto_oplock_list);
 
   string_set(&Connections[cnum].user,"");
   string_set(&Connections[cnum].dirpath,"");
@@ -3324,7 +4315,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,"","/");
 
@@ -3396,7 +4387,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,"","/");
 
@@ -3492,7 +4483,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);
@@ -3553,9 +4544,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);
@@ -3600,7 +4589,7 @@ force write permissions on print services.
 #define TIME_INIT (1<<2)
 #define CAN_IPC (1<<3)
 #define AS_GUEST (1<<5)
-
+#define QUEUE_IN_OPLOCK (1<<6)
 
 /* 
    define a list of possible SMB messages and their corresponding
@@ -3634,20 +4623,20 @@ struct smb_message_struct
    {SMBsetatr,"SMBsetatr",reply_setatr,AS_USER | NEED_WRITE},
    {SMBchkpth,"SMBchkpth",reply_chkpth,AS_USER},
    {SMBsearch,"SMBsearch",reply_search,AS_USER},
-   {SMBopen,"SMBopen",reply_open,AS_USER},
+   {SMBopen,"SMBopen",reply_open,AS_USER | QUEUE_IN_OPLOCK },
 
    /* note that SMBmknew and SMBcreate are deliberately overloaded */   
    {SMBcreate,"SMBcreate",reply_mknew,AS_USER},
    {SMBmknew,"SMBmknew",reply_mknew,AS_USER}, 
 
-   {SMBunlink,"SMBunlink",reply_unlink,AS_USER | NEED_WRITE},
+   {SMBunlink,"SMBunlink",reply_unlink,AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK},
    {SMBread,"SMBread",reply_read,AS_USER},
    {SMBwrite,"SMBwrite",reply_write,AS_USER},
    {SMBclose,"SMBclose",reply_close,AS_USER | CAN_IPC},
    {SMBmkdir,"SMBmkdir",reply_mkdir,AS_USER | NEED_WRITE},
    {SMBrmdir,"SMBrmdir",reply_rmdir,AS_USER | NEED_WRITE},
    {SMBdskattr,"SMBdskattr",reply_dskattr,AS_USER},
-   {SMBmv,"SMBmv",reply_mv,AS_USER | NEED_WRITE},
+   {SMBmv,"SMBmv",reply_mv,AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK},
 
    /* this is a Pathworks specific call, allowing the 
       changing of the root path */
@@ -3655,8 +4644,8 @@ struct smb_message_struct
 
    {SMBlseek,"SMBlseek",reply_lseek,AS_USER},
    {SMBflush,"SMBflush",reply_flush,AS_USER},
-   {SMBctemp,"SMBctemp",reply_ctemp,AS_USER},
-   {SMBsplopen,"SMBsplopen",reply_printopen,AS_USER},
+   {SMBctemp,"SMBctemp",reply_ctemp,AS_USER | QUEUE_IN_OPLOCK },
+   {SMBsplopen,"SMBsplopen",reply_printopen,AS_USER | QUEUE_IN_OPLOCK },
    {SMBsplclose,"SMBsplclose",reply_printclose,AS_USER},
    {SMBsplretq,"SMBsplretq",reply_printqueue,AS_USER|AS_GUEST},
    {SMBsplwr,"SMBsplwr",reply_printwrite,AS_USER},
@@ -3683,10 +4672,10 @@ struct smb_message_struct
    {SMBtrans,"SMBtrans",reply_trans,AS_USER | CAN_IPC},
    {SMBtranss,"SMBtranss",NULL,AS_USER | CAN_IPC},
    {SMBioctls,"SMBioctls",NULL,AS_USER},
-   {SMBcopy,"SMBcopy",reply_copy,AS_USER | NEED_WRITE},
-   {SMBmove,"SMBmove",NULL,AS_USER | NEED_WRITE},
+   {SMBcopy,"SMBcopy",reply_copy,AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK },
+   {SMBmove,"SMBmove",NULL,AS_USER | NEED_WRITE | QUEUE_IN_OPLOCK },
    
-   {SMBopenX,"SMBopenX",reply_open_and_X,AS_USER | CAN_IPC},
+   {SMBopenX,"SMBopenX",reply_open_and_X,AS_USER | CAN_IPC | QUEUE_IN_OPLOCK },
    {SMBreadX,"SMBreadX",reply_read_and_X,AS_USER},
    {SMBwriteX,"SMBwriteX",reply_write_and_X,AS_USER},
    {SMBlockingX,"SMBlockingX",reply_lockingX,AS_USER},
@@ -3698,7 +4687,7 @@ struct smb_message_struct
    /* LANMAN2.0 PROTOCOL FOLLOWS */
    {SMBfindnclose, "SMBfindnclose", reply_findnclose, AS_USER},
    {SMBfindclose, "SMBfindclose", reply_findclose,AS_USER},
-   {SMBtrans2, "SMBtrans2", reply_trans2, AS_USER},
+   {SMBtrans2, "SMBtrans2", reply_trans2, AS_USER | QUEUE_IN_OPLOCK },
    {SMBtranss2, "SMBtranss2", reply_transs2, AS_USER},
 
    /* messaging routines */
@@ -3780,18 +4769,35 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize
   else
     {
       DEBUG(3,("switch message %s (pid %d)\n",smb_messages[match].name,pid));
+
+      if(global_oplock_break && (smb_messages[match].flags & QUEUE_IN_OPLOCK))
+      {
+        /* 
+         * Queue this message as we are the process of an oplock break.
+         */
+
+        DEBUG(2,("%s: switch_message: queueing message due to being in oplock break state.\n",
+               timestring() ));
+
+        push_smb_message( inbuf, size);
+        return -1;
+      }          
+
       if (smb_messages[match].fn)
        {
          int cnum = SVAL(inbuf,smb_tid);
          int flags = smb_messages[match].flags;
-         uint16 session_tag = SVAL(inbuf,smb_uid);
+          /* In share mode security we must ignore the vuid. */
+         uint16 session_tag = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : SVAL(inbuf,smb_uid);
+          /* Ensure this value is replaced in the incoming packet. */
+          SSVAL(inbuf,smb_uid,session_tag);
 
          /* does this protocol need to be run as root? */
          if (!(flags & AS_USER))
            unbecome_user();
 
          /* does this protocol need to be run as the connected user? */
-         if ((flags & AS_USER) && !become_user(cnum,session_tag)) {
+         if ((flags & AS_USER) && !become_user(&Connections[cnum], cnum,session_tag)) {
            if (flags & AS_GUEST) 
              flags &= ~AS_USER;
            else
@@ -3964,6 +4970,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);
 
@@ -3994,14 +5001,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);
@@ -4023,35 +5027,30 @@ static void process(void)
   }
 #endif    
 
+  /* re-initialise the timezone */
+  TimeInit();
+
   while (True)
   {
-    int32 len;      
-    int msg_type;
-    int msg_flags;
-    int type;
     int deadtime = lp_deadtime()*60;
     int counter;
     int last_keepalive=0;
     int service_load_counter = 0;
-#ifdef USE_OPLOCKS
     BOOL got_smb = False;
-#endif /* USE_OPLOCKS */
 
     if (deadtime <= 0)
       deadtime = DEFAULT_SMBD_TIMEOUT;
 
+#if USE_READ_PREDICTION
     if (lp_readprediction())
       do_read_prediction();
+#endif
 
     errno = 0;      
 
     for (counter=SMBD_SELECT_LOOP; 
-#ifdef USE_OPLOCKS
           !receive_message_or_smb(Client,oplock_sock,
-                      InBuffer,SMBD_SELECT_LOOP*1000,&got_smb); 
-#else /* USE_OPLOCKS */
-          !receive_smb(Client,InBuffer,SMBD_SELECT_LOOP*1000); 
-#endif /* USE_OPLOCKS */
+                      InBuffer,BUFFER_SIZE,SMBD_SELECT_LOOP*1000,&got_smb); 
           counter += SMBD_SELECT_LOOP)
     {
       int i;
@@ -4101,17 +5100,16 @@ static void process(void)
 
       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;
+             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;
       }
 
       /* check for connection timeouts */
@@ -4134,57 +5132,10 @@ static void process(void)
       }
     }
 
-#ifdef USE_OPLOCKS
     if(got_smb)
-    {
-#endif /* USE_OPLOCKS */
-      msg_type = CVAL(InBuffer,0);
-      msg_flags = CVAL(InBuffer,1);
-      type = CVAL(InBuffer,smb_com);
-
-      len = smb_len(InBuffer);
-
-      DEBUG(6,("got message type 0x%x of len 0x%x\n",msg_type,len));
-
-      nread = len + 4;
-      
-      DEBUG(3,("%s Transaction %d of length %d\n",timestring(),trans_num,nread));
-
-#ifdef WITH_VTP
-      if(trans_num == 1 && VT_Check(InBuffer)) 
-      {
-        VT_Process();
-        return;
-      }
-#endif
-
-
-      if (msg_type == 0)
-        show_msg(InBuffer);
-
-      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);
-      }
-      trans_num++;
-#ifdef USE_OPLOCKS
-    } 
+      process_smb(InBuffer, OutBuffer);
     else
-    {
       process_local_message(oplock_sock, InBuffer, BUFFER_SIZE);
-    }
-#endif /* USE_OPLOCKS */
   }
 }
 
@@ -4228,6 +5179,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();
 }
 
@@ -4262,7 +5221,9 @@ static void usage(char *pname)
   int port = SMB_PORT;
   int opt;
   extern char *optarg;
-  char pidFile[100] = { 0 };
+  char pidFile[100];
+
+  *pidFile = '\0';
 
 #ifdef NEED_AUTH_PARAMETERS
   set_auth_parameters(argc,argv);
@@ -4278,11 +5239,13 @@ static void usage(char *pname)
 
   strcpy(debugf,SMBLOGFILE);  
 
+  strcpy(remote_machine, "smb");
+
   setup_logging(argv[0],False);
 
   charset_initialise();
 
-  /* make absolutely sure we run as root - to handle cases whre people
+  /* make absolutely sure we run as root - to handle cases where people
      are crazy enough to have it setuid */
 #ifdef USE_SETRES
   setresuid(0,0,0);
@@ -4372,7 +5335,12 @@ static void usage(char *pname)
   {
     struct rlimit rlp;
     getrlimit(RLIMIT_NOFILE, &rlp);
-    rlp.rlim_cur = (MAX_OPEN_FILES>rlp.rlim_max)? rlp.rlim_max:MAX_OPEN_FILES;
+    /*
+     * Set the fd limit to be MAX_OPEN_FILES + 10 to account for the
+     * extra fd we need to read directories, as well as the log files
+     * and standard handles etc.
+     */
+    rlp.rlim_cur = (MAX_OPEN_FILES+10>rlp.rlim_max)? rlp.rlim_max:MAX_OPEN_FILES+10;
     setrlimit(RLIMIT_NOFILE, &rlp);
     getrlimit(RLIMIT_NOFILE, &rlp);
     DEBUG(3,("Maximum number of open files per session is %d\n",rlp.rlim_cur));
@@ -4402,7 +5370,23 @@ static void usage(char *pname)
 #ifndef NO_SIGNAL_TEST
   signal(SIGHUP,SIGNAL_CAST sig_hup);
 #endif
-  
+
+  /* Setup the signals that allow the debug log level
+     to by dynamically changed. */
+  /* If we are using the malloc debug code we can't use
+     SIGUSR1 and SIGUSR2 to do debug level changes. */
+
+#ifndef MEM_MAN
+#if defined(SIGUSR1)
+  signal( SIGUSR1, SIGNAL_CAST sig_usr1 );
+#endif /* SIGUSR1 */
+   
+#if defined(SIGUSR2)
+  signal( SIGUSR2, SIGNAL_CAST sig_usr2 );
+#endif /* SIGUSR2 */
+#endif /* MEM_MAN */
+
   DEBUG(3,("%s loaded services\n",timestring()));
 
   if (!is_daemon && !is_a_socket(0))
@@ -4417,6 +5401,10 @@ static void usage(char *pname)
       become_daemon();
     }
 
+  if (!directory_exist(lp_lockdir(), NULL)) {
+         mkdir(lp_lockdir(), 0755);
+  }
+
   if (*pidFile)
     {
       int     fd;
@@ -4448,10 +5436,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);
@@ -4464,11 +5450,9 @@ static void usage(char *pname)
        DEBUG(2,("%s changed root to %s\n",timestring(),lp_rootdir()));
     }
 
-#ifdef USE_OPLOCKS
   /* Setup the oplock IPC socket. */
   if(!open_oplock_ipc())
     exit(1);
-#endif /* USE_OPLOCKS */
 
   process();
   close_sockets();