make the initial logfile names consistent. This should mean that smbd
[samba.git] / source / smbd / server.c
index 77c8fc319f0d1491bcc0c1a0072e2f0d216e9675..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
@@ -452,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))) 
@@ -1139,6 +1151,7 @@ static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct
   struct stat statbuf;
   file_fd_struct *fd_ptr;
   files_struct *fsp = &Files[fnum];
+  int accmode = (flags & (O_RDONLY | O_WRONLY | O_RDWR));
 
   fsp->open = False;
   fsp->fd_ptr = 0;
@@ -1148,12 +1161,32 @@ static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct
   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 */
@@ -1191,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--;
@@ -1313,7 +1344,7 @@ static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct
       Connections[cnum].num_files_open++;
       fsp->mode = sbuf->st_mode;
       GetTimeOfDay(&fsp->open_time);
-      fsp->uid = current_user.id;
+      fsp->vuid = current_user.vuid;
       fsp->size = 0;
       fsp->pos = -1;
       fsp->open = True;
@@ -1326,6 +1357,7 @@ static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct
       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;      
@@ -1434,6 +1466,8 @@ void close_file(int fnum, BOOL normal_close)
   uint32 inode = fs_p->fd_ptr->inode;
   int token;
 
+  Files[fnum].reserved = False;
+
 #if USE_READ_PREDICTION
   invalidate_read_prediction(fs_p->fd_ptr->fd);
 #endif
@@ -1476,6 +1510,8 @@ void close_file(int fnum, BOOL normal_close)
   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,
           Connections[cnum].num_files_open));
@@ -1538,7 +1574,7 @@ 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;
@@ -1585,21 +1621,50 @@ BOOL check_file_sharing(int cnum,char *fname)
         if(share_entry->op_type & BATCH_OPLOCK)
         {
 
-          DEBUG(5,("check_file_sharing: breaking oplock (%x) on file %s, \
+          /*
+           * 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, \
+            /* 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;
+              return False;
+            }
+            lock_share_entry(cnum, dev, inode, &token);
+            broke_oplock = True;
+            break;
           }
-          lock_share_entry(cnum, dev, inode, &token);
-          broke_oplock = True;
-          break;
         }
 
         /* someone else has a share lock on it, check to see 
@@ -2514,7 +2579,7 @@ max can be %d\n", num_interfaces, FD_SETSIZE));
           return True; 
         }
         close(Client); /* The parent doesn't need this socket */
-#endif /NO_FORK_DEBUG */
+#endif /NO_FORK_DEBUG */
       } /* end for num */
     } /* end while 1 */
   } /* end if is_daemon */
@@ -2580,6 +2645,8 @@ static void process_smb(char *inbuf, char *outbuf)
 
   if (msg_type == 0)
     show_msg(inbuf);
+  else if(msg_type == 0x85)
+    return; /* Keepalive packet. */
 
   nread = construct_reply(inbuf,outbuf,nread,max_send);
       
@@ -2763,8 +2830,8 @@ pid %d, port %d, dev = %x, inode = %x\n", remotepid, from_port, dev, inode));
 BOOL oplock_break(uint32 dev, uint32 inode, struct timeval *tval)
 {
   extern int Client;
-  static char *inbuf = NULL;
-  static char *outbuf = NULL;
+  char *inbuf = NULL;
+  char *outbuf = NULL;
   files_struct *fsp = NULL;
   int fnum;
   time_t start_time;
@@ -2773,22 +2840,6 @@ BOOL oplock_break(uint32 dev, uint32 inode, struct timeval *tval)
   DEBUG(3,("%s oplock_break: called for dev = %x, inode = %x. Current \
 global_oplocks_open = %d\n", timestring(), dev, inode, global_oplocks_open));
 
-  if(inbuf == NULL)
-  {
-    inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
-    if(inbuf == NULL) {
-      DEBUG(0,("oplock_break: malloc fail for input buffer.\n"));
-      return False;
-    } 
-    outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
-    if(outbuf == NULL) {
-      DEBUG(0,("oplock_break: malloc fail for output buffer.\n"));
-      free(inbuf);
-      inbuf = NULL;
-      return False;
-    }
-  } 
-
   /* We need to search the file open table for the
      entry containing this dev and inode, and ensure
      we have an oplock on it. */
@@ -2831,16 +2882,35 @@ allowing break to succeed.\n", timestring(), dev, inode, fnum));
   /* mark the oplock break as sent - we don't want to send twice! */
   if (fsp->sent_oplock_break)
   {
-    DEBUG(0,("%s ERROR: oplock_break already sent for file %s (fnum = %d, dev = %x, inode = %x)\n", timestring(), fsp->name, fnum, dev, inode));
-    return True;
-  }
+    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));
 
-  fsp->sent_oplock_break = True;
+    /* 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);
@@ -2858,6 +2928,9 @@ allowing break to succeed.\n", timestring(), dev, inode, fnum));
  
   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;
  
@@ -2892,6 +2965,16 @@ 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);
 
     /*
@@ -2909,6 +2992,10 @@ inode = %x).\n", timestring(), fsp->name, fnum, dev, inode));
     }
   }
 
+  /* 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;
@@ -2932,6 +3019,7 @@ inode = %x).\n", timestring(), fsp->name, fnum, dev, inode));
        from the sharemode. */
     /* Paranoia.... */
     fsp->granted_oplock = False;
+    fsp->sent_oplock_break = False;
     global_oplocks_open--;
   }
 
@@ -2960,6 +3048,8 @@ BOOL request_oplock_break(share_mode_entry *share_entry,
   char op_break_msg[OPLOCK_BREAK_MSG_LEN];
   struct sockaddr_in addr_out;
   int pid = getpid();
+  time_t start_time;
+  int time_left;
 
   if(pid == share_entry->pid)
   {
@@ -3013,7 +3103,10 @@ to pid %d on port %d for dev = %x, inode = %x. Error was %s\n",
    * While we get messages that aren't ours, loop.
    */
 
-  while(1)
+  start_time = time(NULL);
+  time_left = OPLOCK_BREAK_TIMEOUT+OPLOCK_BREAK_TIMEOUT_FUDGEFACTOR;
+
+  while(time_left >= 0)
   {
     char op_break_reply[UDP_CMD_HEADER_LEN+OPLOCK_BREAK_MSG_LEN];
     int32 reply_msg_len;
@@ -3021,7 +3114,7 @@ to pid %d on port %d for dev = %x, inode = %x. Error was %s\n",
     char *reply_msg_start;
 
     if(receive_local_message(oplock_sock, op_break_reply, sizeof(op_break_reply),
-               (OPLOCK_BREAK_TIMEOUT+OPLOCK_BREAK_TIMEOUT_FUDGEFACTOR) * 1000) == False)
+               time_left ? time_left * 1000 : 1) == False)
     {
       if(smb_read_error == READ_TIMEOUT)
       {
@@ -3044,23 +3137,6 @@ pid %d on port %d for dev = %x, inode = %x. Error was (%s).\n", timestring, shar
       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);
 
@@ -3074,21 +3150,37 @@ pid %d on port %d for dev = %x, inode = %x. Error was (%s).\n", timestring, shar
       continue;
     }
 
-    if(((SVAL(reply_msg_start,UDP_MESSAGE_CMD_OFFSET) & CMD_REPLY) == 0) ||
-       (reply_from_port != share_entry->op_port) ||
+    /*
+     * Test to see if this is the reply we are awaiting.
+     */
+
+    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))
+               OPLOCK_BREAK_MSG_LEN - OPLOCK_BREAK_PID_OFFSET) == 0))
     {
-      DEBUG(3,("%s request_oplock_break: received other message whilst awaiting \
-oplock break response from pid %d on port %d for dev = %x, inode = %x.\n",
-             timestring(), share_entry->pid, share_entry->op_port, dev, inode));
-      if(push_local_message(op_break_reply, sizeof(op_break_reply)) == False)
-        return False;
-      continue;
+      /*
+       * 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.
+       */
 
-    break;
+      process_local_message(oplock_sock, op_break_reply, sizeof(op_break_reply));
+    }
+
+    time_left -= (time(NULL) - start_time);
   }
 
   DEBUG(3,("%s request_oplock_break: broke oplock.\n", timestring()));
@@ -3116,6 +3208,13 @@ BOOL receive_next_smb(int smbfd, int oplockfd, char *inbuf, int bufsize, int tim
       process_local_message(oplock_sock, inbuf, bufsize);
       continue;
     }
+
+    if(ret && (CVAL(inbuf,0) == 0x85))
+    {
+      /* Keepalive packet. */
+      got_smb = False;
+    }
+
   }
   while(ret && !got_smb);
 
@@ -3598,23 +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) {
-                 /* paranoia */
-                 memset(&Files[i], 0, sizeof(Files[i]));
-                 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);
 }
 
 /****************************************************************************
@@ -4414,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
@@ -4448,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 */
@@ -4469,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},
@@ -4497,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},
@@ -4512,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 */
@@ -4594,11 +4769,28 @@ 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))
@@ -5029,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);
@@ -5045,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);
@@ -5139,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));
@@ -5169,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))