local.h: Fix spelling mistake :-).
[kai/samba.git] / source3 / smbd / server.c
index 0361c5aa4679df86de41aa0f222121781e933d29..d387b7375bb7d200744bb8a0e4afaa6cd1ef0447 100644 (file)
@@ -84,6 +84,14 @@ int chain_fnum = -1;
 /* number of open connections */
 static int num_connections_open = 0;
 
+/* Oplock ipc UDP socket. */
+int oplock_sock = -1;
+uint16 oplock_port = 0;
+/* Current number of oplocks we have outstanding. */
+int32 global_oplocks_open = 0;
+
+BOOL global_oplock_break = False;
+
 extern fstring remote_machine;
 
 pstring OriginalDir;
@@ -179,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) ||
@@ -194,7 +202,7 @@ int dos_mode(int cnum,char *path,struct stat *sbuf)
       result |= aRONLY;
   }
 
-  if ((sbuf->st_mode & S_IXUSR) != 0)
+  if (MAP_ARCHIVE(cnum) && ((sbuf->st_mode & S_IXUSR) != 0))
     result |= aARCH;
 
   if (MAP_SYSTEM(cnum) && ((sbuf->st_mode & S_IXGRP) != 0))
@@ -206,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 . */
@@ -224,20 +234,22 @@ int dos_mode(int cnum,char *path,struct stat *sbuf)
        result |= aHIDDEN;
     }
 
-  if (is_hidden_path(SNUM(cnum), path))
+  /* Optimization : Only call is_hidden_path if it's not already
+     hidden. */
+  if (!(result & aHIDDEN) && IS_HIDDEN_PATH(cnum,path))
   {
     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);
 }
@@ -356,7 +368,7 @@ scan a directory to find a filename, matching without case sensitivity
 
 If the name looks like a mangled name then try via the mangling functions
 ****************************************************************************/
-static BOOL scan_directory(char *path, char *name,int snum,BOOL docache)
+static BOOL scan_directory(char *path, char *name,int cnum,BOOL docache)
 {
   void *cur_dir;
   char *dname;
@@ -369,7 +381,7 @@ static BOOL scan_directory(char *path, char *name,int snum,BOOL docache)
   if (*path == 0)
     path = ".";
 
-  if (docache && (dname = DirCacheCheck(path,name,snum))) {
+  if (docache && (dname = DirCacheCheck(path,name,SNUM(cnum)))) {
     strcpy(name, dname);       
     return(True);
   }      
@@ -378,7 +390,7 @@ static BOOL scan_directory(char *path, char *name,int snum,BOOL docache)
     check_mangled_stack(name);
 
   /* open the directory */
-  if (!(cur_dir = OpenDir(snum, path, True))) 
+  if (!(cur_dir = OpenDir(cnum, path, True))) 
     {
       DEBUG(3,("scan dir didn't open dir [%s]\n",path));
       return(False);
@@ -391,14 +403,14 @@ static BOOL scan_directory(char *path, char *name,int snum,BOOL docache)
          (strequal(dname,".") || strequal(dname,"..")))
        continue;
 
-      strcpy(name2,dname);
-      if (!name_map_mangle(name2,False,snum)) continue;
+      pstrcpy(name2,dname);
+      if (!name_map_mangle(name2,False,SNUM(cnum))) continue;
 
       if ((mangled && mangled_equal(name,name2))
-         || fname_equal(name, name2))
+         || fname_equal(name, name2)) /* name2 here was changed to dname - since 1.9.16p2 - not sure of reason (jra) */
        {
          /* we've found the file, change it's name and return */
-         if (docache) DirCacheAdd(path,name,dname,snum);
+         if (docache) DirCacheAdd(path,name,dname,SNUM(cnum));
          strcpy(name, dname);
          CloseDir(cur_dir);
          return(True);
@@ -424,14 +436,22 @@ If the saved_last_component != 0, then the unmodified last component
 of the pathname is returned there. This is used in an exceptional
 case in reply_mv (so far). If saved_last_component == 0 then nothing
 is returned there.
+
+The bad_path arg is set to True if the filename walk failed. This is
+used to pick the correct error code to return between ENOENT and ENOTDIR
+as Windows applications depend on ERRbadpath being returned if a component
+of a pathname does not exist.
 ****************************************************************************/
-BOOL unix_convert(char *name,int cnum,pstring saved_last_component)
+BOOL unix_convert(char *name,int cnum,pstring saved_last_component, BOOL *bad_path)
 {
   struct stat st;
   char *start, *end;
   pstring dirpath;
+  int saved_errno;
 
   *dirpath = 0;
+  *bad_path = False;
+
   if(saved_last_component)
     *saved_last_component = 0;
 
@@ -478,12 +498,14 @@ BOOL unix_convert(char *name,int cnum,pstring saved_last_component)
   if (sys_stat(name,&st) == 0)
     return(True);
 
+  saved_errno = errno;
+
   DEBUG(5,("unix_convert(%s,%d)\n",name,cnum));
 
   /* a special case - if we don't have any mangling chars and are case
      sensitive then searching won't help */
   if (case_sensitive && !is_mangled(name) && 
-      !lp_strip_dot() && !use_mangled_map)
+      !lp_strip_dot() && !use_mangled_map && (saved_errno != ENOENT))
     return(False);
 
   /* now we need to recursively match the name against the real 
@@ -504,7 +526,7 @@ BOOL unix_convert(char *name,int cnum,pstring saved_last_component)
       if (end)         *end = 0;
 
       if(saved_last_component != 0)
-       strcpy(saved_last_component, end ? end + 1 : start);
+        strcpy(saved_last_component, end ? end + 1 : start);
 
       /* check if the name exists up to this point */
       if (sys_stat(name, &st) == 0) 
@@ -527,17 +549,24 @@ BOOL unix_convert(char *name,int cnum,pstring saved_last_component)
 
          /* remember the rest of the pathname so it can be restored
             later */
-         if (end) strcpy(rest,end+1);
+         if (end) pstrcpy(rest,end+1);
 
          /* try to find this part of the path in the directory */
          if (strchr(start,'?') || strchr(start,'*') ||
-             !scan_directory(dirpath, start, SNUM(cnum), end?True:False))
+             !scan_directory(dirpath, start, cnum, end?True:False))
            {
              if (end) 
                {
                  /* an intermediate part of the name can't be found */
                  DEBUG(5,("Intermediate not found %s\n",start));
                  *end = '/';
+                  /* We need to return the fact that the intermediate
+                     name resolution failed. This is used to return an
+                     error of ERRbadpath rather than ERRbadfile. Some
+                     Windows applications depend on the difference between
+                     these two errors.
+                   */
+                  *bad_path = True;
                  return(False);
                }
              
@@ -684,7 +713,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;
@@ -774,7 +811,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;
@@ -808,13 +853,31 @@ BOOL check_name(char *name,int cnum)
 
   errno = 0;
 
-  if( is_vetoed_name(SNUM(cnum), name)) 
+  if( IS_VETO_PATH(cnum, name)) 
     {
       DEBUG(5,("file path name %s vetoed\n",name));
       return(0);
     }
 
   ret = reduce_name(name,Connections[cnum].connectpath,lp_widelinks(SNUM(cnum)));
+
+  /* Check if we are allowing users to follow symlinks */
+  /* Patch from David Clerc <David.Clerc@cui.unige.ch>
+     University of Geneva */
+
+#ifdef S_ISLNK
+  if (!lp_symlinks(SNUM(cnum)))
+    {
+      struct stat statbuf;
+      if ( (sys_lstat(name,&statbuf) != -1) &&
+          (S_ISLNK(statbuf.st_mode)) )
+        {
+          DEBUG(3,("check_name: denied: file path name %s is a symlink\n",name));
+          ret=0; 
+        }
+    }
+#endif
+
   if (!ret)
     DEBUG(5,("check_name on %s failed\n",name));
 
@@ -841,8 +904,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);
 
@@ -894,7 +956,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;
@@ -921,7 +983,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;
@@ -954,8 +1016,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);
 
@@ -975,7 +1036,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],
@@ -1011,12 +1072,14 @@ static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct
   pstring fname;
   struct stat statbuf;
   file_fd_struct *fd_ptr;
+  files_struct *fsp = &Files[fnum];
 
-  Files[fnum].open = False;
-  Files[fnum].fd_ptr = 0;
+  fsp->open = False;
+  fsp->fd_ptr = 0;
+  fsp->granted_oplock = False;
   errno = EPERM;
 
-  strcpy(fname,fname1);
+  pstrcpy(fname,fname1);
 
   /* check permissions */
   if ((flags != O_RDONLY) && !CAN_WRITE(cnum) && !Connections[cnum].printer)
@@ -1145,13 +1208,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;
@@ -1187,25 +1250,26 @@ static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct
       fd_ptr->dev = (uint32)sbuf->st_dev;
       fd_ptr->inode = (uint32)sbuf->st_ino;
 
-      Files[fnum].fd_ptr = fd_ptr;
+      fsp->fd_ptr = fd_ptr;
       Connections[cnum].num_files_open++;
-      Files[fnum].mode = sbuf->st_mode;
-      GetTimeOfDay(&Files[fnum].open_time);
-      Files[fnum].uid = current_user.id;
-      Files[fnum].size = 0;
-      Files[fnum].pos = -1;
-      Files[fnum].open = True;
-      Files[fnum].mmap_ptr = NULL;
-      Files[fnum].mmap_size = 0;
-      Files[fnum].can_lock = True;
-      Files[fnum].can_read = ((flags & O_WRONLY)==0);
-      Files[fnum].can_write = ((flags & (O_WRONLY|O_RDWR))!=0);
-      Files[fnum].share_mode = 0;
-      Files[fnum].print_file = Connections[cnum].printer;
-      Files[fnum].modified = False;
-      Files[fnum].cnum = cnum;
-      string_set(&Files[fnum].name,dos_to_unix(fname,False));
-      Files[fnum].wbmpx_ptr = NULL;      
+      fsp->mode = sbuf->st_mode;
+      GetTimeOfDay(&fsp->open_time);
+      fsp->uid = current_user.id;
+      fsp->size = 0;
+      fsp->pos = -1;
+      fsp->open = True;
+      fsp->mmap_ptr = NULL;
+      fsp->mmap_size = 0;
+      fsp->can_lock = True;
+      fsp->can_read = ((flags & O_WRONLY)==0);
+      fsp->can_write = ((flags & (O_WRONLY|O_RDWR))!=0);
+      fsp->share_mode = 0;
+      fsp->print_file = Connections[cnum].printer;
+      fsp->modified = False;
+      fsp->granted_oplock = False;
+      fsp->cnum = cnum;
+      string_set(&fsp->name,dos_to_unix(fname,False));
+      fsp->wbmpx_ptr = NULL;      
 
       /*
        * If the printer is marked as postscript output a leading
@@ -1214,8 +1278,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);
@@ -1223,23 +1287,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
@@ -1280,10 +1344,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);
 
@@ -1310,17 +1374,17 @@ void close_file(int fnum)
   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)))
@@ -1357,7 +1421,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);
@@ -1411,23 +1476,74 @@ BOOL check_file_sharing(int cnum,char *fname)
   struct stat sbuf;
   share_lock_token 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;
+
+  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.
+   */
 
-  for( i = 0; i < num_share_modes; i++)
+  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++)
+      {
+        min_share_mode_entry *share_entry = &old_shares[i];
+
+        /* 
+         * Break oplocks before checking share modes. See comment in
+         * open_file_shared for details. 
+         * Check if someone has an oplock on this file. If so we must 
+         * break it before continuing. 
+         */
+        if(share_entry->op_type & BATCH_OPLOCK)
+        {
+
+          DEBUG(5,("check_file_sharing: breaking oplock (%x) on file %s, \
+dev = %x, inode = %x\n", share_entry->op_type, fname, dev, inode));
 
-    if(old_shares[i].pid != pid)
-      goto free_and_exit;
+          /* Oplock break.... */
+          unlock_share_entry(cnum, dev, inode, token);
+          if(request_oplock_break(share_entry, dev, inode) == False)
+          {
+            free((char *)old_shares);
+            DEBUG(0,("check_file_sharing: FAILED when breaking oplock (%x) on file %s, \
+dev = %x, inode = %x\n", old_shares[i].op_type, fname, dev, inode));
+            return False;
+          }
+          lock_share_entry(cnum, dev, inode, &token);
+          broke_oplock = True;
+          break;
+        }
+
+        /* someone else has a share lock on it, check to see 
+           if we can too */
+        if ((share_entry->share_mode != DENY_DOS) || (share_entry->pid != pid))
+          goto free_and_exit;
+
+      } /* end for */
+
+      if(broke_oplock)
+      {
+        free((char *)old_shares);
+        num_share_modes = get_share_modes(cnum, token, dev, inode, &old_shares);
+      }
+    } while(broke_oplock);
   }
 
   /* XXXX exactly what share mode combinations should be allowed for
@@ -1438,7 +1554,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);
@@ -1471,12 +1587,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( min_share_mode_entry *share, int deny_mode, char *fname,
+                      BOOL fcbopen, int *flags)
+{
+  int old_open_mode = share->share_mode &0xF;
+  int old_deny_mode = (share->share_mode >>4)&7;
+
+  if (old_deny_mode > 4 || old_open_mode > 2)
+  {
+    DEBUG(0,("Invalid share mode found (%d,%d,%d) on file %s\n",
+               deny_mode,old_deny_mode,old_open_mode,fname));
+    return False;
+  }
+
+  {
+    int access_allowed = access_table(deny_mode,old_deny_mode,old_open_mode,
+                                share->pid,fname);
+
+    if ((access_allowed == AFAIL) ||
+        (!fcbopen && (access_allowed == AREAD && *flags == O_RDWR)) ||
+        (access_allowed == AREAD && *flags == O_WRONLY) ||
+        (access_allowed == AWRITE && *flags == O_RDONLY))
+    {
+      DEBUG(2,("Share violation on file (%d,%d,%d,%d,%s) = %d\n",
+                deny_mode,old_deny_mode,old_open_mode,
+                share->pid,fname, access_allowed));
+      return False;
+    }
+
+    if (access_allowed == AREAD)
+      *flags = O_RDONLY;
+
+    if (access_allowed == AWRITE)
+      *flags = O_WRONLY;
+
+  }
+  return True;
+}
 
 /****************************************************************************
 open a file with a share mode
 ****************************************************************************/
 void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
-                     int mode,int *Access,int *action)
+                     int mode,int oplock_request, int *Access,int *action)
 {
   files_struct *fs_p = &Files[fnum];
   int flags=0;
@@ -1489,6 +1645,7 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
   share_lock_token token;
   uint32 dev = 0;
   uint32 inode = 0;
+  int num_share_modes = 0;
 
   fs_p->open = False;
   fs_p->fd_ptr = 0;
@@ -1497,7 +1654,13 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
   if (strstr(fname,".+,;=[].")) 
   {
     unix_ERR_class = ERRDOS;
+    /* OS/2 Workplace shell fix may be main code stream in a later release. */ 
+#ifdef OS2_WPS_FIX
+    unix_ERR_code = ERRcannotopen;
+#else /* OS2_WPS_FIX */
     unix_ERR_code = ERROR_EAS_NOT_SUPPORTED;
+#endif /* OS2_WPS_FIX */
+
     return;
   }
 
@@ -1554,69 +1717,86 @@ 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;
 
-
     if (file_existed)
     {
       dev = (uint32)sbuf.st_dev;
       inode = (uint32)sbuf.st_ino;
       lock_share_entry(cnum, dev, inode, &token);
       share_locked = True;
-      num_shares = get_share_modes(cnum, token, dev, inode, &old_shares);
+      num_share_modes = get_share_modes(cnum, token, dev, inode, &old_shares);
     }
 
-    for(i = 0; i < num_shares; i++)
+    /*
+     * Check if the share modes will give us access.
+     */
+
+    if(share_locked && (num_share_modes != 0))
     {
-      /* someone else has a share lock on it, check to see 
-        if we can too */
-      int old_open_mode = old_shares[i].share_mode &0xF;
-      int old_deny_mode = (old_shares[i].share_mode >>4)&7;
+      BOOL broke_oplock;
 
-      if (deny_mode > 4 || old_deny_mode > 4 || old_open_mode > 2) 
+      do
       {
-       DEBUG(2,("Invalid share mode (%d,%d,%d) on file %s\n",
-                deny_mode,old_deny_mode,old_open_mode,fname));
-        free((char *)old_shares);
-        if(share_locked)
-          unlock_share_entry(cnum, dev, inode, token);
-       errno = EACCES;
-       unix_ERR_class = ERRDOS;
-       unix_ERR_code = ERRbadshare;
-       return;
-      }
 
-      {
-       int access_allowed = access_table(deny_mode,old_deny_mode,old_open_mode,
-                                         old_shares[i].pid,fname);
+        broke_oplock = False;
+        for(i = 0; i < num_share_modes; i++)
+        {
+          min_share_mode_entry *share_entry = &old_shares[i];
+
+          /* 
+           * By observation of NetBench, oplocks are broken *before* share
+           * modes are checked. This allows a file to be closed by the client
+           * if the share mode would deny access and the client has an oplock. 
+           * Check if someone has an oplock on this file. If so we must break 
+           * it before continuing. 
+           */
+          if(share_entry->op_type & (EXCLUSIVE_OPLOCK|BATCH_OPLOCK))
+          {
+
+            DEBUG(5,("open_file_shared: breaking oplock (%x) on file %s, \
+dev = %x, inode = %x\n", share_entry->op_type, fname, dev, inode));
+
+            /* Oplock break.... */
+            unlock_share_entry(cnum, dev, inode, token);
+            if(request_oplock_break(share_entry, dev, inode) == False)
+            {
+              free((char *)old_shares);
+              DEBUG(0,("open_file_shared: FAILED when breaking oplock (%x) on file %s, \
+dev = %x, inode = %x\n", old_shares[i].op_type, fname, dev, inode));
+              errno = EACCES;
+              unix_ERR_class = ERRDOS;
+              unix_ERR_code = ERRbadshare;
+              return;
+            }
+            lock_share_entry(cnum, dev, inode, &token);
+            broke_oplock = True;
+            break;
+          }
+
+          /* someone else has a share lock on it, check to see 
+             if we can too */
+          if(check_share_mode(share_entry, deny_mode, fname, fcbopen, &flags) == False)
+          {
+            free((char *)old_shares);
+            unlock_share_entry(cnum, dev, inode, token);
+            errno = EACCES;
+            unix_ERR_class = ERRDOS;
+            unix_ERR_code = ERRbadshare;
+            return;
+          }
 
-       if ((access_allowed == AFAIL) ||
-           (!fcbopen && (access_allowed == AREAD && flags == O_RDWR)) ||
-           (access_allowed == AREAD && flags == O_WRONLY) ||
-           (access_allowed == AWRITE && flags == O_RDONLY)) 
+        } /* 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);
   }
@@ -1673,7 +1853,30 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
        file (which expects the share_mode_entry to be there).
      */
     if (lp_share_modes(SNUM(cnum)))
-      set_share_mode(token, fnum);
+    {
+      uint16 port = 0;
+      /* JRA. Currently this only services Exlcusive and batch
+         oplocks (no other opens on this file). This needs to
+         be extended to level II oplocks (multiple reader
+         oplocks). */
+
+      if(oplock_request && (num_share_modes == 0) && lp_oplocks(SNUM(cnum)))
+      {
+        fs_p->granted_oplock = True;
+        global_oplocks_open++;
+        port = oplock_port;
+
+        DEBUG(5,("open_file_shared: granted oplock (%x) on file %s, \
+dev = %x, inode = %x\n", oplock_request, fname, dev, inode));
+
+      }
+      else
+      {
+        port = 0;
+        oplock_request = 0;
+      }
+      set_share_mode(token, fnum, port, oplock_request);
+    }
 
     if ((flags2&O_TRUNC) && file_existed)
       truncate_unless_locked(fnum,cnum,token,&share_locked);
@@ -1686,20 +1889,21 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
 /****************************************************************************
 seek a file. Try to avoid the seek if possible
 ****************************************************************************/
-int seek_file(int fnum,int pos)
+int seek_file(int fnum,uint32 pos)
 {
-  int offset = 0;
+  uint32 offset = 0;
   if (Files[fnum].print_file && POSTSCRIPT(Files[fnum].cnum))
     offset = 3;
 
-  Files[fnum].pos = lseek(Files[fnum].fd_ptr->fd,pos+offset,SEEK_SET) - offset;
+  Files[fnum].pos = (int)(lseek(Files[fnum].fd_ptr->fd,pos+offset,SEEK_SET) 
+                                  - offset);
   return(Files[fnum].pos);
 }
 
 /****************************************************************************
 read from a file
 ****************************************************************************/
-int read_file(int fnum,char *data,int pos,int n)
+int read_file(int fnum,char *data,uint32 pos,int n)
 {
   int ret=0,readret;
 
@@ -1715,7 +1919,7 @@ int read_file(int fnum,char *data,int pos,int n)
 #if USE_MMAP
   if (Files[fnum].mmap_ptr)
     {
-      int num = MIN(n,Files[fnum].mmap_size-pos);
+      int num = MIN(n,(int)(Files[fnum].mmap_size-pos));
       if (num > 0)
        {
          memcpy(data,Files[fnum].mmap_ptr+pos,num);
@@ -1921,6 +2125,7 @@ struct
   {EPERM,ERRDOS,ERRnoaccess},
   {EACCES,ERRDOS,ERRnoaccess},
   {ENOENT,ERRDOS,ERRbadfile},
+  {ENOTDIR,ERRDOS,ERRbadpath},
   {EIO,ERRHRD,ERRgeneral},
   {EBADF,ERRSRV,ERRsrverror},
   {EINVAL,ERRSRV,ERRsrverror},
@@ -1941,7 +2146,6 @@ struct
   {0,0,0}
 };
 
-
 /****************************************************************************
   create an error packet from errno
 ****************************************************************************/
@@ -1961,15 +2165,15 @@ int unix_error_packet(char *inbuf,char *outbuf,int def_class,uint32 def_code,int
   else
     {
       while (unix_smb_errmap[i].smbclass != 0)
-       {
-         if (unix_smb_errmap[i].unixerror == errno)
+      {
+           if (unix_smb_errmap[i].unixerror == errno)
            {
              eclass = unix_smb_errmap[i].smbclass;
              ecode = unix_smb_errmap[i].smbcode;
              break;
            }
          i++;
-       }
+      }
     }
 
   return(error_packet(inbuf,outbuf,eclass,ecode,line));
@@ -2100,7 +2304,7 @@ static BOOL open_sockets(BOOL is_daemon,int port)
       /* ready to listen */
       if (listen(s, 5) == -1) 
        {
-         DEBUG(0,("listen: %s",strerror(errno)));
+         DEBUG(0,("listen: %s\n",strerror(errno)));
          close(s);
          return False;
        }
@@ -2120,7 +2324,7 @@ static BOOL open_sockets(BOOL is_daemon,int port)
 
          if (Client == -1)
            {
-             DEBUG(0,("accept: %s",strerror(errno)));
+             DEBUG(0,("accept: %s\n",strerror(errno)));
              continue;
            }
 
@@ -2178,6 +2382,542 @@ static BOOL open_sockets(BOOL is_daemon,int port)
   return True;
 }
 
+/****************************************************************************
+  process an smb from the client - split out from the process() code so
+  it can be used by the oplock break code.
+****************************************************************************/
+
+static void process_smb(char *inbuf, char *outbuf)
+{
+  extern int Client;
+  static int trans_num;
+  int msg_type = CVAL(inbuf,0);
+  int32 len = smb_len(inbuf);
+  int nread = len + 4;
+
+  if (trans_num == 0) {
+         /* on the first packet, check the global hosts allow/ hosts
+            deny parameters before doing any parsing of the packet
+            passed to us by the client.  This prevents attacks on our
+            parsing code from hosts not in the hosts allow list */
+         if (!check_access(-1)) {
+                 /* send a negative session response "not listining on calling
+                  name" */
+                 static unsigned char buf[5] = {0x83, 0, 0, 1, 0x81};
+                 DEBUG(1,("%s Connection denied from %s\n",
+                          timestring(),client_addr()));
+                 send_smb(Client,(char *)buf);
+                 exit_server("connection denied");
+         }
+  }
+
+  DEBUG(6,("got message type 0x%x of len 0x%x\n",msg_type,len));
+  DEBUG(3,("%s Transaction %d of length %d\n",timestring(),trans_num,nread));
+
+#ifdef WITH_VTP
+  if(trans_num == 1 && VT_Check(inbuf)) 
+  {
+    VT_Process();
+    return;
+  }
+#endif
+
+  if (msg_type == 0)
+    show_msg(inbuf);
+
+  nread = construct_reply(inbuf,outbuf,nread,max_send);
+      
+  if(nread > 0) 
+  {
+    if (CVAL(outbuf,0) == 0)
+      show_msg(outbuf);
+       
+    if (nread != smb_len(outbuf) + 4) 
+    {
+      DEBUG(0,("ERROR: Invalid message response size! %d %d\n",
+                 nread, smb_len(outbuf)));
+    }
+    else
+      send_smb(Client,outbuf);
+  }
+  trans_num++;
+}
+
+/****************************************************************************
+  open the oplock IPC socket communication
+****************************************************************************/
+static BOOL open_oplock_ipc()
+{
+  struct sockaddr_in sock_name;
+  int len = sizeof(sock_name);
+
+  DEBUG(3,("open_oplock_ipc: opening loopback UDP socket.\n"));
+
+  /* Open a lookback UDP socket on a random port. */
+  oplock_sock = open_socket_in(SOCK_DGRAM, 0, 0, htonl(INADDR_LOOPBACK));
+  if (oplock_sock == -1)
+  {
+    DEBUG(0,("open_oplock_ipc: Failed to get local UDP socket for \
+address %x. Error was %s\n", htonl(INADDR_LOOPBACK), strerror(errno)));
+    oplock_port = 0;
+    return(False);
+  }
+
+  /* Find out the transient UDP port we have been allocated. */
+  if(getsockname(oplock_sock, (struct sockaddr *)&sock_name, &len)<0)
+  {
+    DEBUG(0,("open_oplock_ipc: Failed to get local UDP port. Error was %s\n",
+            strerror(errno)));
+    close(oplock_sock);
+    oplock_sock = -1;
+    oplock_port = 0;
+    return False;
+  }
+  oplock_port = ntohs(sock_name.sin_port);
+
+  DEBUG(3,("open_oplock ipc: pid = %d, oplock_port = %u\n", 
+            getpid(), oplock_port));
+
+  return True;
+}
+
+/****************************************************************************
+  process an oplock break message.
+****************************************************************************/
+static BOOL process_local_message(int sock, char *buffer, int buf_size)
+{
+  int32 msg_len;
+  int16 from_port;
+  char *msg_start;
+
+  msg_len = IVAL(buffer,UDP_CMD_LEN_OFFSET);
+  from_port = SVAL(buffer,UDP_CMD_PORT_OFFSET);
+
+  msg_start = &buffer[UDP_CMD_HEADER_LEN];
+
+  DEBUG(5,("process_local_message: Got a message of length %d from port (%d)\n", 
+            msg_len, from_port));
+
+  /* Switch on message command - currently OPLOCK_BREAK_CMD is the
+     only valid request. */
+
+  switch(SVAL(msg_start,UDP_MESSAGE_CMD_OFFSET))
+  {
+    case OPLOCK_BREAK_CMD:
+      /* Ensure that the msg length is correct. */
+      if(msg_len != OPLOCK_BREAK_MSG_LEN)
+      {
+        DEBUG(0,("process_local_message: incorrect length for OPLOCK_BREAK_CMD (was %d, \
+should be %d).\n", msg_len, OPLOCK_BREAK_MSG_LEN));
+        return False;
+      }
+      {
+        uint32 remotepid = IVAL(msg_start,OPLOCK_BREAK_PID_OFFSET);
+        uint32 dev = IVAL(msg_start,OPLOCK_BREAK_DEV_OFFSET);
+        uint32 inode = IVAL(msg_start, OPLOCK_BREAK_INODE_OFFSET);
+        struct timeval tval;
+        struct sockaddr_in toaddr;
+
+        tval.tv_sec = IVAL(msg_start, OPLOCK_BREAK_SEC_OFFSET);
+        tval.tv_usec = IVAL(msg_start, OPLOCK_BREAK_USEC_OFFSET);
+
+        DEBUG(5,("process_local_message: oplock break request from \
+pid %d, port %d, dev = %x, inode = %x\n", remotepid, from_port, dev, inode));
+
+        /*
+         * If we have no record of any currently open oplocks,
+         * it's not an error, as a close command may have
+         * just been issued on the file that was oplocked.
+         * Just return success in this case.
+         */
+
+        if(global_oplocks_open != 0)
+        {
+          if(oplock_break(dev, inode, &tval) == False)
+          {
+            DEBUG(0,("process_local_message: oplock break failed - \
+not returning udp message.\n"));
+            return False;
+          }
+        }
+        else
+        {
+          DEBUG(3,("process_local_message: oplock break requested with no outstanding \
+oplocks. Returning success.\n"));
+        }
+
+        /* Send the message back after OR'ing in the 'REPLY' bit. */
+        SSVAL(msg_start,UDP_MESSAGE_CMD_OFFSET,OPLOCK_BREAK_CMD | CMD_REPLY);
+  
+        bzero((char *)&toaddr,sizeof(toaddr));
+        toaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+        toaddr.sin_port = htons(from_port);
+        toaddr.sin_family = AF_INET;
+
+        if(sendto( sock, msg_start, OPLOCK_BREAK_MSG_LEN, 0,
+                (struct sockaddr *)&toaddr, sizeof(toaddr)) < 0) 
+        {
+          DEBUG(0,("process_local_message: sendto process %d failed. Errno was %s\n",
+                    remotepid, strerror(errno)));
+          return False;
+        }
+
+        DEBUG(5,("process_local_message: oplock break reply sent to \
+pid %d, port %d, for file dev = %x, inode = %x\n", remotepid, 
+                from_port, dev, inode));
+
+      }
+      break;
+    /* 
+     * Keep this as a debug case - eventually we can remove it.
+     */
+    case 0x8001:
+      DEBUG(0,("process_local_message: Received unsolicited break \
+reply - dumping info.\n"));
+
+      if(msg_len != OPLOCK_BREAK_MSG_LEN)
+      {
+        DEBUG(0,("process_local_message: ubr: incorrect length for reply \
+(was %d, should be %d).\n", msg_len, OPLOCK_BREAK_MSG_LEN));
+        return False;
+      }
+
+      {
+        uint32 remotepid = IVAL(msg_start,OPLOCK_BREAK_PID_OFFSET);
+        uint32 dev = IVAL(msg_start,OPLOCK_BREAK_DEV_OFFSET);
+        uint32 inode = IVAL(msg_start, OPLOCK_BREAK_INODE_OFFSET);
+
+        DEBUG(0,("process_local_message: unsolicited oplock break reply from \
+pid %d, port %d, dev = %x, inode = %x\n", remotepid, from_port, dev, inode));
+
+       }
+       return False;
+
+    default:
+      DEBUG(0,("process_local_message: unknown UDP message command code (%x) - ignoring.\n",
+                (unsigned int)SVAL(msg_start,0)));
+      return False;
+  }
+  return True;
+}
+
+/****************************************************************************
+ Process an oplock break directly.
+****************************************************************************/
+BOOL oplock_break(uint32 dev, uint32 inode, struct timeval *tval)
+{
+  extern int Client;
+  static char *inbuf = NULL;
+  static char *outbuf = NULL;
+  files_struct *fsp = NULL;
+  int fnum;
+  time_t start_time;
+  BOOL shutdown_server = False;
+
+  DEBUG(5,("oplock_break: called for dev = %x, inode = %x. Current \
+global_oplocks_open = %d\n", dev, inode, global_oplocks_open));
+
+  if(inbuf == NULL)
+  {
+    inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+    if(inbuf == NULL) {
+      DEBUG(0,("oplock_break: malloc fail for input buffer.\n"));
+      return False;
+    } 
+    outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+    if(outbuf == NULL) {
+      DEBUG(0,("oplock_break: malloc fail for output buffer.\n"));
+      free(inbuf);
+      inbuf = NULL;
+      return False;
+    }
+  } 
+
+  /* We need to search the file open table for the
+     entry containing this dev and inode, and ensure
+     we have an oplock on it. */
+  for( fnum = 0; fnum < MAX_OPEN_FILES; fnum++)
+  {
+    if(OPEN_FNUM(fnum))
+    {
+      fsp = &Files[fnum];
+      if((fsp->fd_ptr->dev == dev) && (fsp->fd_ptr->inode == inode) &&
+         (fsp->open_time.tv_sec == tval->tv_sec) && 
+         (fsp->open_time.tv_usec == tval->tv_usec))
+        break;
+    }
+  }
+
+  if(fsp == NULL)
+  {
+    /* The file could have been closed in the meantime - return success. */
+    DEBUG(3,("oplock_break: cannot find open file with dev = %x, inode = %x (fnum = %d) \
+allowing break to succeed.\n", dev, inode, fnum));
+    return True;
+  }
+
+  /* Ensure we have an oplock on the file */
+
+  /* There is a potential race condition in that an oplock could
+     have been broken due to another udp request, and yet there are
+     still oplock break messages being sent in the udp message
+     queue for this file. So return true if we don't have an oplock,
+     as we may have just freed it.
+   */
+
+  if(!fsp->granted_oplock)
+  {
+    DEBUG(3,("oplock_break: file %s (fnum = %d, dev = %x, inode = %x) has no oplock. \
+Allowing break to succeed regardless.\n", fsp->name, fnum, dev, inode));
+    return True;
+  }
+
+  /* Now comes the horrid part. We must send an oplock break to the client,
+     and then process incoming messages until we get a close or oplock release.
+   */
+
+  /* Prepare the SMBlockingX message. */
+  bzero(outbuf,smb_size);
+  set_message(outbuf,8,0,True);
+
+  SCVAL(outbuf,smb_com,SMBlockingX);
+  SSVAL(outbuf,smb_tid,fsp->cnum);
+  SSVAL(outbuf,smb_pid,0xFFFF);
+  SSVAL(outbuf,smb_uid,0);
+  SSVAL(outbuf,smb_mid,0xFFFF);
+  SCVAL(outbuf,smb_vwv0,0xFF);
+  SSVAL(outbuf,smb_vwv2,fnum);
+  SCVAL(outbuf,smb_vwv3,LOCKING_ANDX_OPLOCK_RELEASE);
+  /* Change this when we have level II oplocks. */
+  SCVAL(outbuf,smb_vwv3+1,OPLOCKLEVEL_NONE);
+  send_smb(Client, outbuf);
+
+  global_oplock_break = True;
+  /* Process incoming messages. */
+
+  /* JRA - If we don't get a break from the client in OPLOCK_BREAK_TIMEOUT
+     seconds we should just die.... */
+
+  start_time = time(NULL);
+
+  while(OPEN_FNUM(fnum) && fsp->granted_oplock)
+  {
+    if(receive_smb(Client,inbuf,OPLOCK_BREAK_TIMEOUT * 1000) == False)
+    {
+      /*
+       * Die if we got an error.
+       */
+
+      if (smb_read_error == READ_EOF)
+        DEBUG(0,("oplock_break: end of file from client\n"));
+      if (smb_read_error == READ_ERROR)
+        DEBUG(0,("oplock_break: receive_smb error (%s)\n",
+                  strerror(errno)));
+
+      if (smb_read_error == READ_TIMEOUT)
+        DEBUG(0,("oplock_break: receive_smb timed out after %d seconds.\n",
+                  OPLOCK_BREAK_TIMEOUT));
+
+      DEBUG(0,("oplock_break failed for file %s (fnum = %d, dev = %x, \
+inode = %x).\n", fsp->name, fnum, dev, inode));
+      shutdown_server = True;
+      break;
+    }
+    process_smb(inbuf, outbuf);
+
+    /* We only need this in case a readraw crossed on the wire. */
+    if(global_oplock_break)
+      global_oplock_break = False;
+
+    /*
+     * Die if we go over the time limit.
+     */
+
+    if((time(NULL) - start_time) > OPLOCK_BREAK_TIMEOUT)
+    {
+      DEBUG(0,("oplock_break: no break received from client within \
+%d seconds.\n", OPLOCK_BREAK_TIMEOUT));
+      DEBUG(0,("oplock_break failed for file %s (fnum = %d, dev = %x, \
+inode = %x).\n", fsp->name, fnum, dev, inode));
+      shutdown_server = True;
+      break;
+    }
+  }
+
+  /*
+   * If the client did not respond we must die.
+   */
+
+  if(shutdown_server)
+  {
+    DEBUG(0,("oplock_break: client failure in break - shutting down this smbd.\n"));
+    close_sockets();
+    close(oplock_sock);
+    exit_server("oplock break failure");
+  }
+
+  if(OPEN_FNUM(fnum))
+  {
+    /* The lockingX reply will have removed the oplock flag 
+       from the sharemode. */
+    /* Paranoia.... */
+    fsp->granted_oplock = False;
+  }
+
+  global_oplocks_open--;
+
+  /* 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(5,("oplock_break: returning success for fnum = %d, dev = %x, inode = %x. Current \
+global_oplocks_open = %d\n", fnum, dev, inode, global_oplocks_open));
+
+  return True;
+}
+
+/****************************************************************************
+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.
+****************************************************************************/
+
+BOOL request_oplock_break(min_share_mode_entry *share_entry, 
+                          uint32 dev, uint32 inode)
+{
+  char op_break_msg[OPLOCK_BREAK_MSG_LEN];
+  struct sockaddr_in addr_out;
+  int pid = getpid();
+
+  if(pid == share_entry->pid)
+  {
+    /* We are breaking our own oplock, make sure it's us. */
+    if(share_entry->op_port != oplock_port)
+    {
+      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;
+    }
+
+    DEBUG(5,("request_oplock_break: breaking our own oplock\n"));
+
+    /* Call oplock break direct. */
+    return oplock_break(dev, inode, &share_entry->time);
+  }
+
+  /* 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,("request_oplock_break: sending a oplock break message to pid %d on port %d \
+for dev = %x, inode = %x\n", share_entry->pid, share_entry->op_port, dev, inode));
+
+  if(sendto(oplock_sock,op_break_msg,OPLOCK_BREAK_MSG_LEN,0,
+         (struct sockaddr *)&addr_out,sizeof(addr_out)) < 0)
+  {
+    DEBUG(0,("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",
+         share_entry->pid, share_entry->op_port, dev, inode,
+         strerror(errno)));
+    return False;
+  }
+
+  /*
+   * 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 seconds.
+   * While we get messages that aren't ours, loop.
+   */
+
+  while(1)
+  {
+    char op_break_reply[UDP_CMD_HEADER_LEN+OPLOCK_BREAK_MSG_LEN];
+    int32 reply_msg_len;
+    int16 reply_from_port;
+    char *reply_msg_start;
+
+    if(receive_local_message(oplock_sock, op_break_reply, sizeof(op_break_reply),
+                             OPLOCK_BREAK_TIMEOUT * 1000) == False)
+    {
+      if(smb_read_error == READ_TIMEOUT)
+        DEBUG(0,("request_oplock_break: no response received to oplock break request to \
+pid %d on port %d for dev = %x, inode = %x\n", share_entry->pid, 
+                           share_entry->op_port, dev, inode));
+      else
+        DEBUG(0,("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", share_entry->pid, 
+                         share_entry->op_port, dev, inode, strerror(errno)));
+      return False;
+    }
+
+    /* 
+     * If the response we got was not an answer to our message, but
+     * was a completely different request, push it onto the pending
+     * udp message stack so that we can deal with it in the main loop.
+     * It may be another oplock break request to us.
+     */
+
+    /*
+     * Local note from JRA. There exists the possibility of a denial
+     * of service attack here by allowing non-root processes running
+     * on a local machine sending many of these pending messages to
+     * a smbd port. Currently I'm not sure how to restrict the messages
+     * I will queue (although I could add a limit to the queue) to
+     * those received by root processes only. There should be a 
+     * way to make this bulletproof....
+     */
+
+    reply_msg_len = IVAL(op_break_reply,UDP_CMD_LEN_OFFSET);
+    reply_from_port = SVAL(op_break_reply,UDP_CMD_PORT_OFFSET);
+
+    reply_msg_start = &op_break_reply[UDP_CMD_HEADER_LEN];
+
+    if(reply_msg_len != OPLOCK_BREAK_MSG_LEN)
+    {
+      /* Ignore it. */
+      DEBUG(0,("request_oplock_break: invalid message length received. Ignoring\n"));
+      continue;
+    }
+
+    if(((SVAL(reply_msg_start,UDP_MESSAGE_CMD_OFFSET) & CMD_REPLY) == 0) ||
+       (reply_from_port != share_entry->op_port) ||
+       (memcmp(&reply_msg_start[OPLOCK_BREAK_PID_OFFSET], 
+               &op_break_msg[OPLOCK_BREAK_PID_OFFSET],
+               OPLOCK_BREAK_MSG_LEN - OPLOCK_BREAK_PID_OFFSET) != 0))
+    {
+      DEBUG(3,("request_oplock_break: received other message whilst awaiting \
+oplock break response from pid %d on port %d for dev = %x, inode = %x.\n",
+             share_entry->pid, share_entry->op_port, dev, inode));
+      if(push_local_message(op_break_reply, sizeof(op_break_reply)) == False)
+        return False;
+      continue;
+    }
+
+    break;
+  }
+
+  DEBUG(3,("request_oplock_break: broke oplock.\n"));
+
+  return True;
+}
 
 /****************************************************************************
 check if a snum is in use
@@ -2201,10 +2941,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;
        }
     }
@@ -2447,8 +3187,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));
@@ -2467,6 +3216,8 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
   pcon->printer = (strncmp(dev,"LPT",3) == 0);
   pcon->ipc = (strncmp(dev,"IPC",3) == 0);
   pcon->dirptr = NULL;
+  pcon->veto_list = NULL;
+  pcon->hide_list = NULL;
   string_set(&pcon->dirpath,"");
   string_set(&pcon->user,user);
 
@@ -2495,13 +3246,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));    
        }
@@ -2511,7 +3262,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));
@@ -2547,7 +3298,7 @@ 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);
@@ -2587,7 +3338,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);
@@ -2601,7 +3352,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);
     }
@@ -2609,6 +3360,13 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
   /* we've finished with the sensitive stuff */
   unbecome_user();
 
+  /* Add veto/hide lists */
+  if (!IS_IPC(cnum) && !IS_PRINT(cnum))
+  {
+    set_namearray( &pcon->veto_list, lp_veto_files(SNUM(cnum)));
+    set_namearray( &pcon->hide_list, lp_hide_files(SNUM(cnum)));
+  }
+
   {
     DEBUG(IS_IPC(cnum)?3:1,("%s %s (%s) connect to service %s as user %s (uid=%d,gid=%d) (pid %d)\n",
                            timestring(),
@@ -2726,19 +3484,15 @@ int reply_lanman1(char *outbuf)
 
   set_message(outbuf,13,doencrypt?8:0,True);
   SSVAL(outbuf,smb_vwv1,secword); 
-#ifdef SMB_PASSWD
   /* Create a token value and add it to the outgoing packet. */
   if (doencrypt) 
     generate_next_challenge(smb_buf(outbuf));
-#endif
 
   Protocol = PROTOCOL_LANMAN1;
 
   if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) {
     DEBUG(3,("using password server validation\n"));
-#ifdef SMB_PASSWD
   if (doencrypt) set_challenge(smb_buf(outbuf));    
-#endif
   }
 
   CVAL(outbuf,smb_flg) = 0x81; /* Reply, SMBlockread, SMBwritelock supported */
@@ -2777,11 +3531,9 @@ int reply_lanman2(char *outbuf)
 
   set_message(outbuf,13,doencrypt?8:0,True);
   SSVAL(outbuf,smb_vwv1,secword); 
-#ifdef SMB_PASSWD
   /* Create a token value and add it to the outgoing packet. */
   if (doencrypt) 
     generate_next_challenge(smb_buf(outbuf));
-#endif
 
   SIVAL(outbuf,smb_vwv6,getpid());
 
@@ -2789,9 +3541,7 @@ int reply_lanman2(char *outbuf)
 
   if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) {
     DEBUG(3,("using password server validation\n"));
-#ifdef SMB_PASSWD
     if (doencrypt) set_challenge(smb_buf(outbuf));    
-#endif
   }
 
   CVAL(outbuf,smb_flg) = 0x81; /* Reply, SMBlockread, SMBwritelock supported */
@@ -2861,7 +3611,6 @@ int reply_nt1(char *outbuf)
 #endif
 
   CVAL(outbuf,smb_vwv1) = secword;
-#ifdef SMB_PASSWD
   /* Create a token value and add it to the outgoing packet. */
   if (doencrypt)
   {
@@ -2870,15 +3619,12 @@ int reply_nt1(char *outbuf)
     /* Tell the nt machine how long the challenge is. */
     SSVALS(outbuf,smb_vwv16+1,challenge_len);
   }
-#endif
 
   Protocol = PROTOCOL_NT1;
 
   if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) {
     DEBUG(3,("using password server validation\n"));
-#ifdef SMB_PASSWD
     if (doencrypt) set_challenge(smb_buf(outbuf));    
-#endif
   }
 
   SSVAL(outbuf,smb_mid,mid); /* Restore possibly corrupted mid */
@@ -2979,7 +3725,6 @@ struct {
 ****************************************************************************/
 static int reply_negprot(char *inbuf,char *outbuf)
 {
-  extern fstring remote_arch;
   int outsize = set_message(outbuf,1,0,True);
   int Index=0;
   int choice= -1;
@@ -3019,22 +3764,22 @@ static int reply_negprot(char *inbuf,char *outbuf)
     
   switch ( arch ) {
   case ARCH_SAMBA:
-    strcpy(remote_arch,"Samba");
+    set_remote_arch(RA_SAMBA);
     break;
   case ARCH_WFWG:
-    strcpy(remote_arch,"WfWg");
+    set_remote_arch(RA_WFWG);
     break;
   case ARCH_WIN95:
-    strcpy(remote_arch,"Win95");
+    set_remote_arch(RA_WIN95);
     break;
   case ARCH_WINNT:
-    strcpy(remote_arch,"WinNT");
+    set_remote_arch(RA_WINNT);
     break;
   case ARCH_OS2:
-    strcpy(remote_arch,"OS2");
+    set_remote_arch(RA_OS2);
     break;
   default:
-    strcpy(remote_arch,"UNKNOWN");
+    set_remote_arch(RA_UNKNOWN);
     break;
   }
  
@@ -3066,7 +3811,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));
@@ -3158,6 +3903,9 @@ void close_cnum(int cnum, uint16 vuid)
       Connections[cnum].ngroups = 0;
     }
 
+  free_namearray(Connections[cnum].veto_list);
+  free_namearray(Connections[cnum].hide_list);
+
   string_set(&Connections[cnum].user,"");
   string_set(&Connections[cnum].dirpath,"");
   string_set(&Connections[cnum].connectpath,"");
@@ -3182,7 +3930,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,"","/");
 
@@ -3254,7 +4002,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,"","/");
 
@@ -3350,7 +4098,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);
@@ -3393,7 +4141,7 @@ void exit_server(char *reason)
   DEBUG(2,("Closing connections\n"));
   for (i=0;i<MAX_CONNECTIONS;i++)
     if (Connections[i].open)
-      close_cnum(i,-1);
+      close_cnum(i,(uint16)-1);
 #ifdef DFS_AUTH
   if (dcelogin_atmost_once)
     dfs_unlogin();
@@ -3422,22 +4170,28 @@ void exit_server(char *reason)
 /****************************************************************************
 do some standard substitutions in a string
 ****************************************************************************/
-void standard_sub(int cnum,char *s)
+void standard_sub(int cnum,char *str)
 {
-  if (!strchr(s,'%')) return;
-
-  if (VALID_CNUM(cnum))
-    {
-      string_sub(s,"%S",lp_servicename(Connections[cnum].service));
-      string_sub(s,"%P",Connections[cnum].connectpath);
-      string_sub(s,"%u",Connections[cnum].user);
-      if (strstr(s,"%H")) {
-       char *home = get_home_dir(Connections[cnum].user);
-       if (home) string_sub(s,"%H",home);
+  if (VALID_CNUM(cnum)) {
+    char *p, *s, *home;
+
+    for ( s=str ; (p=strchr(s, '%')) != NULL ; s=p ) {
+      switch (*(p+1)) {
+        case 'H' : if ((home = get_home_dir(Connections[cnum].user))!=NULL)
+                     string_sub(p,"%H",home);
+                   else
+                     p += 2;
+                   break;
+        case 'P' : string_sub(p,"%P",Connections[cnum].connectpath); break;
+        case 'S' : string_sub(p,"%S",lp_servicename(Connections[cnum].service)); break;
+        case 'g' : string_sub(p,"%g",gidtoname(Connections[cnum].gid)); break;
+        case 'u' : string_sub(p,"%u",Connections[cnum].user); break;
+        case '\0' : p++; break; /* don't run off the end of the string */
+        default  : p+=2; break;
       }
-      string_sub(s,"%g",gidtoname(Connections[cnum].gid));
     }
-  standard_sub_basic(s);
+  }
+  standard_sub_basic(str);
 }
 
 /*
@@ -3846,14 +4600,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);
@@ -3876,140 +4627,111 @@ static void process(void)
 #endif    
 
   while (True)
-    {
-      int32 len;      
-      int msg_type;
-      int msg_flags;
-      int type;
-      int deadtime = lp_deadtime()*60;
-      int counter;
-      int last_keepalive=0;
-
-      if (deadtime <= 0)
-       deadtime = DEFAULT_SMBD_TIMEOUT;
-
-      if (lp_readprediction())
-       do_read_prediction();
-
-      errno = 0;      
-
-      for (counter=SMBD_SELECT_LOOP; 
-          !receive_smb(Client,InBuffer,SMBD_SELECT_LOOP*1000); 
-          counter += SMBD_SELECT_LOOP)
-       {
-         int i;
-         time_t t;
-         BOOL allidle = True;
-         extern int keepalive;
-
-         if (smb_read_error == READ_EOF) {
-           DEBUG(3,("end of file from client\n"));
-           return;
-         }
-
-         if (smb_read_error == READ_ERROR) {
-           DEBUG(3,("receive_smb error (%s) exiting\n",
-                    strerror(errno)));
-           return;
-         }
-
-         t = time(NULL);
+  {
+    int deadtime = lp_deadtime()*60;
+    int counter;
+    int last_keepalive=0;
+    int service_load_counter = 0;
+    BOOL got_smb = False;
 
-         /* become root again if waiting */
-         unbecome_user();
+    if (deadtime <= 0)
+      deadtime = DEFAULT_SMBD_TIMEOUT;
 
-         /* check for smb.conf reload */
-         if (!(counter%SMBD_RELOAD_CHECK))
-           reload_services(True);
+    if (lp_readprediction())
+      do_read_prediction();
 
-#if 0 /* JRA */
-         /* check the share modes every 10 secs */
-         if (!(counter%SHARE_MODES_CHECK))
-           check_share_modes();
+    errno = 0;      
 
-         /* clean the share modes every 5 minutes */
-         if (!(counter%SHARE_MODES_CLEAN))
-           clean_share_modes();
-#endif /* JRA */
+    for (counter=SMBD_SELECT_LOOP; 
+          !receive_message_or_smb(Client,oplock_sock,
+                      InBuffer,BUFFER_SIZE,SMBD_SELECT_LOOP*1000,&got_smb); 
+          counter += SMBD_SELECT_LOOP)
+    {
+      int i;
+      time_t t;
+      BOOL allidle = True;
+      extern int keepalive;
 
-         /* automatic timeout if all connections are closed */      
-         if (num_connections_open==0 && counter >= IDLE_CLOSED_TIMEOUT) {
-           DEBUG(2,("%s Closing idle connection\n",timestring()));
-           return;
-         }
+      if (counter > 365 * 3600) /* big number of seconds. */
+      {
+        counter = 0;
+        service_load_counter = 0;
+      }
 
-         if (keepalive && (counter-last_keepalive)>keepalive) {
-           extern int password_client;
-           if (!send_keepalive(Client)) {
-             DEBUG(2,("%s Keepalive failed - exiting\n",timestring()));
-             return;
-           }       
-           /* also send a keepalive to the password server if its still
-              connected */
-           if (password_client != -1)
-             send_keepalive(password_client);
-           last_keepalive = counter;
-         }
+      if (smb_read_error == READ_EOF) 
+      {
+        DEBUG(3,("end of file from client\n"));
+        return;
+      }
 
-         /* check for connection timeouts */
-         for (i=0;i<MAX_CONNECTIONS;i++)
-           if (Connections[i].open)
-             {
-               /* close dirptrs on connections that are idle */
-               if ((t-Connections[i].lastused)>DPTR_IDLE_TIMEOUT)
-                 dptr_idlecnum(i);
-
-               if (Connections[i].num_files_open > 0 ||
-                   (t-Connections[i].lastused)<deadtime)
-                 allidle = False;
-             }
-
-         if (allidle && num_connections_open>0) {
-           DEBUG(2,("%s Closing idle connection 2\n",timestring()));
-           return;
-         }
-       }
+      if (smb_read_error == READ_ERROR) 
+      {
+        DEBUG(3,("receive_smb error (%s) exiting\n",
+                  strerror(errno)));
+        return;
+      }
 
-      msg_type = CVAL(InBuffer,0);
-      msg_flags = CVAL(InBuffer,1);
-      type = CVAL(InBuffer,smb_com);
+      t = time(NULL);
 
-      len = smb_len(InBuffer);
+      /* become root again if waiting */
+      unbecome_user();
 
-      DEBUG(6,("got message type 0x%x of len 0x%x\n",msg_type,len));
+      /* check for smb.conf reload */
+      if (counter >= service_load_counter + SMBD_RELOAD_CHECK)
+      {
+        service_load_counter = counter;
 
-      nread = len + 4;
-      
-      DEBUG(3,("%s Transaction %d of length %d\n",timestring(),trans_num,nread));
+        /* reload services, if files have changed. */
+        reload_services(True);
+      }
 
-#ifdef WITH_VTP
-      if(trans_num == 1 && VT_Check(InBuffer)) {
-        VT_Process();
+      /* automatic timeout if all connections are closed */      
+      if (num_connections_open==0 && counter >= IDLE_CLOSED_TIMEOUT) 
+      {
+        DEBUG(2,("%s Closing idle connection\n",timestring()));
         return;
       }
-#endif
 
+      if (keepalive && (counter-last_keepalive)>keepalive) 
+      {
+        extern int password_client;
+        if (!send_keepalive(Client))
+        { 
+          DEBUG(2,("%s Keepalive failed - exiting\n",timestring()));
+          return;
+        }          
+        /* also send a keepalive to the password server if its still
+           connected */
+        if (password_client != -1)
+          send_keepalive(password_client);
+        last_keepalive = counter;
+      }
 
-      if (msg_type == 0)
-       show_msg(InBuffer);
+      /* check for connection timeouts */
+      for (i=0;i<MAX_CONNECTIONS;i++)
+        if (Connections[i].open)
+        {
+          /* close dirptrs on connections that are idle */
+          if ((t-Connections[i].lastused)>DPTR_IDLE_TIMEOUT)
+            dptr_idlecnum(i);
 
-      nread = construct_reply(InBuffer,OutBuffer,nread,max_send);
-      
-      if(nread > 0) {
-        if (CVAL(OutBuffer,0) == 0)
-         show_msg(OutBuffer);
-       
-        if (nread != smb_len(OutBuffer) + 4) 
-         {
-           DEBUG(0,("ERROR: Invalid message response size! %d %d\n",
-                    nread,
-                    smb_len(OutBuffer)));
-         }
-       else
-         send_smb(Client,OutBuffer);
+          if (Connections[i].num_files_open > 0 ||
+                     (t-Connections[i].lastused)<deadtime)
+            allidle = False;
+        }
+
+      if (allidle && num_connections_open>0) 
+      {
+        DEBUG(2,("%s Closing idle connection 2\n",timestring()));
+        return;
       }
-      trans_num++;
     }
+
+    if(got_smb)
+      process_smb(InBuffer, OutBuffer);
+    else
+      process_local_message(oplock_sock, InBuffer, BUFFER_SIZE);
+  }
 }
 
 
@@ -4104,7 +4826,7 @@ static void usage(char *pname)
 
   setup_logging(argv[0],False);
 
-  charset_initialise(-1);
+  charset_initialise();
 
   /* make absolutely sure we run as root - to handle cases whre people
      are crazy enough to have it setuid */
@@ -4189,7 +4911,7 @@ static void usage(char *pname)
   reopen_logs();
 
   DEBUG(2,("%s smbd version %s started\n",timestring(),VERSION));
-  DEBUG(2,("Copyright Andrew Tridgell 1992-1995\n"));
+  DEBUG(2,("Copyright Andrew Tridgell 1992-1997\n"));
 
 #ifndef NO_GETRLIMIT
 #ifdef RLIMIT_NOFILE
@@ -4219,7 +4941,7 @@ static void usage(char *pname)
   if (!reload_services(False))
     return(-1);        
 
-  charset_initialise(lp_client_code_page());
+  codepage_initialise(lp_client_code_page());
 
   strcpy(myworkgroup, lp_workgroup());
 
@@ -4247,7 +4969,10 @@ static void usage(char *pname)
       char    buf[20];
 
       if ((fd = open(pidFile,
-         O_NONBLOCK | O_CREAT | O_WRONLY | O_TRUNC, 0644)) < 0)
+#ifdef O_NONBLOCK
+         O_NONBLOCK | 
+#endif
+         O_CREAT | O_WRONLY | O_TRUNC, 0644)) < 0)
         {
            DEBUG(0,("ERROR: can't open %s: %s\n", pidFile, strerror(errno)));
            exit(1);
@@ -4285,6 +5010,10 @@ static void usage(char *pname)
        DEBUG(2,("%s changed root to %s\n",timestring(),lp_rootdir()));
     }
 
+  /* Setup the oplock IPC socket. */
+  if(!open_oplock_ipc())
+    exit(1);
+
   process();
   close_sockets();