dir.c: more pstrcpys.
authorJeremy Allison <jra@samba.org>
Tue, 30 Sep 1997 02:38:19 +0000 (02:38 +0000)
committerJeremy Allison <jra@samba.org>
Tue, 30 Sep 1997 02:38:19 +0000 (02:38 +0000)
local.h: Add OPLOCK_BREAK_TIMEOUT.
password.c: Fix for paranoia password server security bug.
proto.h: Updated.
reply.c: Oplock changes.
server.c: Massive oplock changes - nearly there....
smb.h: oplock definitions.
util.c: Add local message processing queues for oplocks.
Jeremy (jallison@whistle.com)
(This used to be commit 92f1553db2cdf6f32881eb984a87050cf3e4760b)

source3/include/local.h
source3/include/proto.h
source3/include/smb.h
source3/lib/util.c
source3/smbd/dir.c
source3/smbd/password.c
source3/smbd/reply.c
source3/smbd/server.c

index 9548bf74b6bd81b05e6707b4ffcb496090aab6d6..e7eff2a300d5e5221afcb1f3748fea2bd20ac513 100644 (file)
 /* the directory to sit in when idle */
 /* #define IDLE_DIR "/" */
 
+/* Timout (in seconds) to wait for an oplock breal
+   message to return. */
+
+#define OPLOCK_BREAK_TIMEOUT 120
+
 #endif
index 8903437d004ccb0d296cf82f601089c94e8e84cd..7a1ccc626f727ceb603e09fa0b6822d2969f0c59 100644 (file)
@@ -719,6 +719,9 @@ int find_service(char *service);
 int cached_error_packet(char *inbuf,char *outbuf,int fnum,int line);
 int unix_error_packet(char *inbuf,char *outbuf,int def_class,uint32 def_code,int line);
 int error_packet(char *inbuf,char *outbuf,int error_class,uint32 error_code,int line);
+BOOL oplock_break(uint32 dev, uint32 inode);
+BOOL request_oplock_break(min_share_mode_entry *share_entry, 
+                          uint32 dev, uint32 inode);
 BOOL snum_used(int snum);
 BOOL reload_services(BOOL test);
 int setup_groups(char *user, int uid, int gid, int *p_ngroups, 
@@ -925,7 +928,9 @@ int read_data(int fd,char *buffer,int N);
 int write_data(int fd,char *buffer,int N);
 int transfer_file(int infd,int outfd,int n,char *header,int headlen,int align);
 int read_smb_length(int fd,char *inbuf,int timeout);
-BOOL receive_smb(int fd,char *buffer,int timeout);
+BOOL receive_smb(int fd,char *buffer, int timeout);
+BOOL receive_local_message(int fd, char *buffer, int buffer_len, int timeout);
+BOOL push_local_message(char *buf, int msg_len);
 BOOL receive_message_or_smb(int smbfd, int oplock_fd, 
                            char *buffer, int buffer_len, 
                            int timeout, BOOL *got_smb);
index 07614194f757763672357a8fe8e442ed006487da..c8de001fda9195490d5cb51640abe5653f22ae62 100644 (file)
@@ -1014,6 +1014,17 @@ extern int unix_ERR_code;
 #define EXTENDED_OPLOCK_REQUEST(inbuf) (((SVAL(inbuf,smb_vwv2)|(1<<1))>>1) | \
                                         ((SVAL(inbuf,smb_vwv2)|(1<<2))>>1))
 
+/* Lock types. */
+#define LOCKING_ANDX_SHARED_LOCK 0x1
+#define LOCKING_ANDX_OPLOCK_RELEASE 0x2
+#define LOCKING_ANDX_CHANGE_LOCKTYPE 0x4
+#define LOCKING_ANDX_CANCEL_LOCK 0x8
+#define LOCKING_ANDX_LARGE_FILES 0x10
+
+/* Oplock levels */
+#define OPLOCKLEVEL_NONE 0
+#define OPLOCKLEVEL_II 1
+
 /*
  * Bits we test with.
  */
@@ -1023,4 +1034,34 @@ extern int unix_ERR_code;
 #define CORE_OPLOCK_GRANTED (1<<5)
 #define EXTENDED_OPLOCK_GRANTED (1<<15)
 
+/*
+ * Loopback command offsets.
+ */
+
+#define UDP_CMD_LEN_OFFSET 0
+#define UDP_CMD_PORT_OFFSET 4
+#define UDP_CMD_HEADER_LEN 6
+
+#define UDP_MESSAGE_CMD_OFFSET 0
+
+/*
+ * Oplock break command code to send over the udp socket.
+ * 
+ * Form of this is :
+ *
+ *  0     2       6        10
+ *  +----+--------+--------+--------+
+ *  | cmd| pid    | dev    | inode  |
+ *  +----+--------+--------+--------+
+ */
+
+#define OPLOCK_BREAK_CMD 0x1
+#define OPLOCK_BREAK_PID_OFFSET 2
+#define OPLOCK_BREAK_DEV_OFFSET 6
+#define OPLOCK_BREAK_INODE_OFFSET 10
+#define OPLOCK_BREAK_MSG_LEN 14
+
+
+#define CMD_REPLY 0x8000
+
 /* _SMB_H */
index 05dd6198135ac4463b86ff3db504393c506a1bd6..056e7e18dbe9a7dde3db1796ee7825b1fa6b8746 100644 (file)
@@ -2270,10 +2270,11 @@ int read_smb_length(int fd,char *inbuf,int timeout)
 
 
 /****************************************************************************
-  read an smb from a fd.
+  read an smb from a fd. Note that the buffer *MUST* be of size
+  BUFFER_SIZE+SAFETY_MARGIN.
 The timeout is in milli seconds
 ****************************************************************************/
-BOOL receive_smb(int fd,char *buffer,int timeout)
+BOOL receive_smb(int fd,char *buffer, int timeout)
 {
   int len,ret;
 
@@ -2301,9 +2302,134 @@ BOOL receive_smb(int fd,char *buffer,int timeout)
 }
 
 #ifdef USE_OPLOCKS
+/****************************************************************************
+  read a message from a udp fd.
+The timeout is in milli seconds
+****************************************************************************/
+BOOL receive_local_message(int fd, char *buffer, int buffer_len, int timeout)
+{
+  struct sockaddr_in from;
+  int fromlen = sizeof(from);
+  int32 msg_len = 0;
+
+  if(timeout != 0)
+  {
+    struct timeval to;
+    fd_set fds;
+    int selrtn;
+
+    FD_ZERO(&fds);
+    FD_SET(fd,&fds);
+
+    to.tv_sec = timeout / 1000;
+    to.tv_usec = (timeout % 1000) * 1000;
+
+    selrtn = sys_select(&fds,&to);
+
+    /* Check if error */
+    if(selrtn == -1) 
+    {
+      /* something is wrong. Maybe the socket is dead? */
+      smb_read_error = READ_ERROR;
+      return False;
+    } 
+    
+    /* Did we timeout ? */
+    if (selrtn == 0) 
+    {
+      smb_read_error = READ_TIMEOUT;
+      return False;
+    }
+  }
+
+  /*
+   * Read a loopback udp message.
+   */
+  msg_len = recvfrom(fd, &buffer[UDP_CMD_HEADER_LEN], 
+                     buffer_len - UDP_CMD_HEADER_LEN, 0,
+                     (struct sockaddr *)&from, &fromlen);
+
+  if(msg_len < 0)
+  {
+    DEBUG(0,("receive_local_message. Error in recvfrom. (%s).\n",strerror(errno)));
+    return False;
+  }
+
+  /* Validate message length. */
+  if(msg_len > (buffer_len - UDP_CMD_HEADER_LEN))
+  {
+    DEBUG(0,("receive_local_message: invalid msg_len (%d) max can be %d\n",
+              msg_len, 
+              buffer_len  - UDP_CMD_HEADER_LEN));
+    return False;
+  }
+
+  /* Validate message from address (must be localhost). */
+  if(from.sin_addr.s_addr != htonl(INADDR_LOOPBACK))
+  {
+    DEBUG(0,("receive_local_message: invalid 'from' address \
+(was %x should be 127.0.0.1\n", from.sin_addr.s_addr));
+   return False;
+  }
+
+  /* Setup the message header */
+  SIVAL(buffer,UDP_CMD_LEN_OFFSET,msg_len);
+  SSVAL(buffer,UDP_CMD_PORT_OFFSET,ntohs(from.sin_port));
+
+  return True;
+}
+
+/****************************************************************************
+ structure to hold a linked list of local udp messages.
+ for processing.
+****************************************************************************/
+
+typedef struct _udp_message_list {
+   struct _udp_message_list *msg_next;
+   char *msg_buf;
+   int msg_len;
+} udp_message_list;
+
+static udp_message_list *udp_msg_head = NULL;
+
+/****************************************************************************
+ Function to push a linked list of local udp messages ready
+ for processing.
+****************************************************************************/
+BOOL push_local_message(char *buf, int msg_len)
+{
+  udp_message_list *msg = (udp_message_list *)malloc(sizeof(udp_message_list));
+
+  if(msg == NULL)
+  {
+    DEBUG(0,("push_local_message: malloc fail (1)\n"));
+    return False;
+  }
+
+  msg->msg_buf = (char *)malloc(msg_len);
+  if(msg->msg_buf == NULL)
+  {
+    DEBUG(0,("push_local_message: malloc fail (2)\n"));
+    free((char *)msg);
+    return False;
+  }
+
+  memcpy(msg->msg_buf, buf, msg_len);
+  msg->msg_len = msg_len;
+
+  msg->msg_next = udp_msg_head;
+  udp_msg_head = msg;
+
+  return True;
+}
+
 /****************************************************************************
   Do a select on an two fd's - with timeout. 
 
+  If a local udp message has been pushed onto the
+  queue (this can only happen during oplock break
+  processing) return this first.
+
   If the first smbfd is ready then read an smb from it.
   if the second (loopback UDP) fd is ready then read a message
   from it and setup the buffer header to identify the length
@@ -2322,7 +2448,24 @@ BOOL receive_message_or_smb(int smbfd, int oplock_fd,
   struct timeval to;
 
   *got_smb = False;
+
+  /*
+   * Check to see if we already have a message on the udp queue.
+   * If so - copy and return it.
+   */
+
+  if(udp_msg_head)
+  {
+    udp_message_list *msg = udp_msg_head;
+    memcpy(buffer, msg->msg_buf, MIN(buffer_len, msg->msg_len));
+    udp_msg_head = msg->msg_next;
+
+    /* Free the message we just copied. */
+    free((char *)msg->msg_buf);
+    free((char *)msg);
+    return True;
+  }
+
   FD_ZERO(&fds);
   FD_SET(smbfd,&fds);
   FD_SET(oplock_fd,&fds);
@@ -2352,34 +2495,8 @@ BOOL receive_message_or_smb(int smbfd, int oplock_fd,
   }
   else
   {
-    /*
-     * Read a udp message.
-     */
-    struct sockaddr_in from;
-    int fromlen = sizeof(from);
-    int32 msg_len = 0;
-    uint16 port = 0;
-
-    msg_len = recvfrom(oplock_fd, &buffer[6+sizeof(struct in_addr)],
-              buffer_len - (6 + sizeof(struct in_addr)), 0,
-              (struct sockaddr *)&from, &fromlen);
-
-    if(msg_len < 0)
-    {
-      DEBUG(0,("Invalid loopback packet ! (%s).\n",strerror(errno)));
-      return False;
-    }
-
-    port = ntohs(from.sin_port);
-
-    /* Setup the message header */
-    SIVAL(buffer,0,msg_len);
-    SSVAL(buffer,4,port);
-    memcpy(&buffer[6],(char *)&from.sin_addr,sizeof(struct in_addr));
-
+    return receive_local_message(oplock_fd, buffer, buffer_len, 0);
   }
-
-  return True;
 }
 #endif /* USE_OPLOCKS */
 
@@ -3713,10 +3830,10 @@ char *readdirname(void *p)
   return(dname);
 }
 
-/*
Utility function used to decide if the last component 
of a path matches a (possibly wildcarded) entry in a namelist.
- */
+/*******************************************************************
+ Utility function used to decide if the last component 
+ of a path matches a (possibly wildcarded) entry in a namelist.
+********************************************************************/
 
 BOOL is_in_path(char *name, name_compare_entry *namelist)
 {
@@ -3763,19 +3880,19 @@ BOOL is_in_path(char *name, name_compare_entry *namelist)
   return False;
 }
 
-/*
Strip a '/' separated list into an array of 
name_compare_enties structures suitable for 
passing to is_in_path(). We do this for
speed so we can pre-parse all the names in the list 
and don't do it for each call to is_in_path().
namelist is modified here and is assumed to be 
a copy owned by the caller.
We also check if the entry contains a wildcard to
remove a potentially expensive call to mask_match
if possible.
-   */
-
+/*******************************************************************
+ Strip a '/' separated list into an array of 
+ name_compare_enties structures suitable for 
+ passing to is_in_path(). We do this for
+ speed so we can pre-parse all the names in the list 
+ and don't do it for each call to is_in_path().
+ namelist is modified here and is assumed to be 
+ a copy owned by the caller.
+ We also check if the entry contains a wildcard to
+ remove a potentially expensive call to mask_match
+ if possible.
+********************************************************************/
 void set_namearray(name_compare_entry **ppname_array, char *namelist)
 {
   char *name_end;
index 567bc14424e0e0cbe1d16542bd6661fb56eb1f75..316b58818fd942adb76c96e2e22c9c9b15245783 100644 (file)
@@ -470,12 +470,12 @@ BOOL get_dir_entry(int cnum,char *mask,int dirtype,char *fname,int *size,int *mo
          if (isrootdir && (strequal(filename,"..") || strequal(filename,".")))
            continue;
 
-         strcpy(fname,filename);
+         pstrcpy(fname,filename);
          *path = 0;
-         strcpy(path,Connections[cnum].dirpath);
+         pstrcpy(path,Connections[cnum].dirpath);
           if(needslash)
            strcat(path,"/");
-         strcpy(pathreal,path);
+         pstrcpy(pathreal,path);
          strcat(path,fname);
          strcat(pathreal,dname);
          if (sys_stat(pathreal,&sbuf) != 0) 
index 35f73eab2d1712a915b5329794dab6e78b22015c..f4d94791cf37876d037e9c904d9bcb786a0b0287 100644 (file)
@@ -1504,13 +1504,14 @@ BOOL check_hosts_equiv(char *user)
 
 int password_client = -1;
 static fstring pserver;
+static char *secserver_inbuf = NULL;
 
 /****************************************************************************
 attempted support for server level security 
 ****************************************************************************/
 BOOL server_cryptkey(char *buf)
 {
-  pstring inbuf,outbuf;
+  pstring outbuf;
   fstring pass_protocol;
   extern fstring remote_machine;
   char *p;
@@ -1519,6 +1520,14 @@ BOOL server_cryptkey(char *buf)
   struct in_addr dest_ip;
   int port = SMB_PORT;
   BOOL ret;
+  
+  if(secserver_inbuf == NULL) {
+    secserver_inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+    if(secserver_inbuf == NULL) {
+      DEBUG(0,("server_cryptkey: malloc fail for input buffer.\n"));
+      return False;
+    }
+  }
 
   if (password_client >= 0)
     close(password_client);
@@ -1530,7 +1539,7 @@ BOOL server_cryptkey(char *buf)
     strcpy(pass_protocol,"NT LM 0.12");
   }
 
-  bzero(inbuf,sizeof(inbuf));
+  bzero(secserver_inbuf,BUFFER_SIZE + SAFETY_MARGIN);
   bzero(outbuf,sizeof(outbuf));
 
   for (p=strtok(lp_passwordserver(),LIST_SEP); p ; p = strtok(NULL,LIST_SEP)) {
@@ -1596,8 +1605,8 @@ BOOL server_cryptkey(char *buf)
   send_smb(password_client,outbuf);
   
  
-  if (!receive_smb(password_client,inbuf,5000) ||
-      CVAL(inbuf,0) != 0x82) {
+  if (!receive_smb(password_client,secserver_inbuf,5000) ||
+      CVAL(secserver_inbuf,0) != 0x82) {
     DEBUG(1,("%s rejected the session\n",pserver));
     close(password_client); password_client = -1;
     return(False);
@@ -1618,21 +1627,21 @@ BOOL server_cryptkey(char *buf)
   SSVAL(outbuf,smb_flg2,0x1);
 
   send_smb(password_client,outbuf);
-  ret = receive_smb(password_client,inbuf,5000);
+  ret = receive_smb(password_client,secserver_inbuf,5000);
 
-  if (!ret || CVAL(inbuf,smb_rcls) || SVAL(inbuf,smb_vwv0)) {
+  if (!ret || CVAL(secserver_inbuf,smb_rcls) || SVAL(secserver_inbuf,smb_vwv0)) {
     DEBUG(1,("%s rejected the protocol\n",pserver));
     close(password_client); password_client= -1;
     return(False);
   }
 
-  if (!(CVAL(inbuf,smb_vwv1) & 1)) {
+  if (!(CVAL(secserver_inbuf,smb_vwv1) & 1)) {
     DEBUG(1,("%s isn't in user level security mode\n",pserver));
     close(password_client); password_client= -1;
     return(False);
   }
 
-  memcpy(buf,inbuf,smb_len(inbuf)+4);
+  memcpy(buf,secserver_inbuf,smb_len(secserver_inbuf)+4);
 
   DEBUG(3,("password server OK\n"));
 
@@ -1644,15 +1653,23 @@ attempted support for server level security
 ****************************************************************************/
 BOOL server_validate(char *buf)
 {
-  pstring inbuf,outbuf;  
+  pstring outbuf;  
   BOOL ret;
 
+  if(secserver_inbuf == NULL) {
+    secserver_inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+    if(secserver_inbuf == NULL) {
+      DEBUG(0,("server_validate: malloc fail for input buffer.\n"));
+      return False;
+    }
+  }
+
   if (password_client < 0) {
     DEBUG(1,("%s not connected\n",pserver));
     return(False);
   }  
 
-  bzero(inbuf,sizeof(inbuf));
+  bzero(secserver_inbuf,BUFFER_SIZE + SAFETY_MARGIN);
   memcpy(outbuf,buf,sizeof(outbuf));
 
   /* send a session setup command */
@@ -1662,18 +1679,18 @@ BOOL server_validate(char *buf)
 
   set_message(outbuf,smb_numwords(outbuf),smb_buflen(outbuf),False);
 
-  SCVAL(inbuf,smb_rcls,1);
+  SCVAL(secserver_inbuf,smb_rcls,1);
 
   send_smb(password_client,outbuf);
-  ret = receive_smb(password_client,inbuf,5000);
+  ret = receive_smb(password_client,secserver_inbuf,5000);
 
-  if (!ret || CVAL(inbuf,smb_rcls) != 0) {
+  if (!ret || CVAL(secserver_inbuf,smb_rcls) != 0) {
     DEBUG(1,("password server %s rejected the password\n",pserver));
     return(False);
   }
 
   /* if logged in as guest then reject */
-  if ((SVAL(inbuf,smb_vwv2) & 1) != 0) {
+  if ((SVAL(secserver_inbuf,smb_vwv2) & 1) != 0) {
     DEBUG(1,("password server %s gave us guest only\n",pserver));
     return(False);
   }
index c1c42be80130cfb7a2a26258407c58e427427b0e..8987e7c0c2bff4d38d567c4d2ef8c5f5812d041b 100644 (file)
@@ -42,6 +42,7 @@ extern BOOL short_case_preserve;
 extern pstring sesssetup_user;
 extern fstring myworkgroup;
 extern int Client;
+extern int global_oplock_break;
 
 /* this macro should always be used to extract an fnum (smb_fid) from
 a packet to ensure chaining works correctly */
@@ -388,7 +389,9 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   if (Protocol < PROTOCOL_NT1) {
     smb_apasslen = SVAL(inbuf,smb_vwv7);
     if (smb_apasslen > MAX_PASSWORD_LENGTH)
+    {
            overflow_attack(smb_apasslen);
+    }
 
     memcpy(smb_apasswd,smb_buf(inbuf),smb_apasslen);
     pstrcpy(user,smb_buf(inbuf)+smb_apasslen);
@@ -1163,7 +1166,7 @@ int reply_open(char *inbuf,char *outbuf)
   SSVAL(outbuf,smb_vwv6,rmode);
 
   if (oplock_request && lp_fake_oplocks(SNUM(cnum))) {
-    fsp->granted_oplock = True;
+    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
   }
     
   if(fsp->granted_oplock)
@@ -1250,7 +1253,7 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   }
 
   if (oplock_request && lp_fake_oplocks(SNUM(cnum))) {
-    fsp->granted_oplock = True;
+    smb_action |= EXTENDED_OPLOCK_GRANTED;
   }
 
   if(fsp->granted_oplock)
@@ -1377,7 +1380,7 @@ int reply_mknew(char *inbuf,char *outbuf)
   SSVAL(outbuf,smb_vwv0,fnum);
 
   if (oplock_request && lp_fake_oplocks(SNUM(cnum))) {
-    fsp->granted_oplock = True;
+    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
   }
  
   if(fsp->granted_oplock)
@@ -1453,7 +1456,7 @@ int reply_ctemp(char *inbuf,char *outbuf)
   strcpy(smb_buf(outbuf) + 1,fname2);
 
   if (oplock_request && lp_fake_oplocks(SNUM(cnum))) {
-    fsp->granted_oplock = True;
+    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
   }
   
   if(fsp->granted_oplock)
index d2ad803c9cc309a32fbf33ac25605b7e888c9810..708a2c272b997c48738ffa2c831fe527e1a6286d 100644 (file)
@@ -89,9 +89,11 @@ static int num_connections_open = 0;
 int oplock_sock = -1;
 uint16 oplock_port = 0;
 /* Current number of oplocks we have outstanding. */
-uint32 oplocks_open = 0;
+uint32 global_oplocks_open = 0;
 #endif /* USE_OPLOCKS */
 
+BOOL global_oplock_break = False;
+
 extern fstring remote_machine;
 
 pstring OriginalDir;
@@ -1355,17 +1357,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)))
@@ -1668,12 +1670,15 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
 
       do
       {
+
         broke_oplock = False;
         for(i = 0; i < num_shares; i++)
         {
+          min_share_mode_entry *share_entry = &old_shares[i];
+
           /* someone else has a share lock on it, check to see 
              if we can too */
-          if(check_share_mode(&old_shares[i], deny_mode, fname, fcbopen, &flags) == False)
+          if(check_share_mode(share_entry, deny_mode, fname, fcbopen, &flags) == False)
           {
             free((char *)old_shares);
             unlock_share_entry(cnum, dev, inode, token);
@@ -1688,23 +1693,31 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
            * has an oplock on this file. If so we must break it before
            * continuing. 
            */
-          if(old_shares[i].op_type != 0)
+          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 0 /* Work in progress..... */
-            if(break_oplock())
+            if(request_oplock_break(share_entry, dev, inode) == False)
             {
               free((char *)old_shares);
-              /* Error condition here... */
+              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;
-#endif
           }
 #endif /* USE_OPLOCKS */
-        }
+        } /* end for */
+
         if(broke_oplock)
         {
           free((char *)old_shares);
@@ -2312,6 +2325,52 @@ 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 = 0;
+
+  int msg_type = CVAL(inbuf,0);
+  int32 len = smb_len(outbuf);
+  int nread = len + 4;
+
+  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++;
+}
+
 #ifdef USE_OPLOCKS
 /****************************************************************************
   open the oplock IPC socket communication
@@ -2355,33 +2414,324 @@ static BOOL process_local_message(int oplock_sock, char *buffer, int buf_size)
 {
   int32 msg_len;
   int16 from_port;
-  struct in_addr from_addr;
   char *msg_start;
 
-  msg_len = IVAL(buffer,0);
-  from_port = SVAL(buffer,4);
-  memcpy((char *)&from_addr, &buffer[6], sizeof(struct in_addr));
+  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 sockaddr_in toaddr;
+
+        DEBUG(5,("process_local_message: oplock break request from \
+pid %d, dev %d, inode %d\n", remotepid, 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) == 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( oplock_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;
+        }
+      }
+      break;
+    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)
+{
+  extern int Client;
+  static char *inbuf = NULL;
+  static char *outbuf = NULL;
+  files_struct *fsp = NULL;
+  int fnum;
+
+  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))
+        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 */
+
+  /* Question - can a client asynchronously break an oplock ? Would it
+     ever do so ? If so this test is invalid for external smbd oplock
+     breaks and we should return True in these cases (JRA).
+   */
+
+  if(!fsp->granted_oplock)
+  {
+    DEBUG(0,("oplock_break: file %s (fnum = %d, dev = %x, inode = %x) has no oplock.\n",
+              fsp->name, fnum, dev, inode));
+    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.
+   */
+
+  /* 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. */
+  while(global_oplock_break && OPEN_FNUM(fnum))
+  {
+    if(receive_smb(Client,inbuf,OPLOCK_BREAK_TIMEOUT * 1000) == False)
+    {
+      if (smb_read_error == READ_EOF)
+      {
+        DEBUG(3,("oplock_break: end of file from client\n"));
+        return False;
+      }
+      if (smb_read_error == READ_ERROR)
+      {
+        DEBUG(3,("oplock_break: receive_smb error (%s)\n",
+                  strerror(errno)));
+        return False;
+      }
+    }
+    process_smb(inbuf, outbuf);
+  }
+
+  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.
+****************************************************************************/
 
-  msg_start = &buffer[6 + sizeof(struct in_addr)];
+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 = %x, port = %d \
+should be %d\n", pid, share_entry->op_port, oplock_port));
+      return False;
+    }
+    /* Call oplock break direct. */
+    return oplock_break(dev, inode);
+  }
+
+  /* We need to send a OPLOCK_BREAK_CMD message to the
+     port in the share mode entry. */
 
-  /* Validate message length. */
-  if(msg_len > (buf_size  - (6 + sizeof(struct in_addr))))
+  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);
+
+  /* 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,("process_local_message: invalid msg_len (%d) max can be %d\n",
-              msg_len, buf_size  - (6 + sizeof(struct in_addr))));
+    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;
   }
 
-  /* Validate message from address (must be localhost). */
-  if(from_addr.s_addr != htonl(INADDR_LOOPBACK))
+  /*
+   * 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)
   {
-    DEBUG(0,("process_local_message: invalid 'from' address \
-(was %x should be 127.0.0.1\n", from_addr.s_addr));
-   return False;
+    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;
+    }
+
+    break;
   }
 
+  DEBUG(3,("request_oplock_break: broke oplock.\n"));
+
   return True;
 }
+
 #endif /* USE_OPLOCKS */
 
 /****************************************************************************
@@ -4056,52 +4406,6 @@ int construct_reply(char *inbuf,char *outbuf,int size,int bufsize)
   return(outsize);
 }
 
-/****************************************************************************
-  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 = 0;
-
-  int msg_type = CVAL(inbuf,0);
-  int32 len = smb_len(outbuf);
-  int nread = len + 4;
-
-  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++;
-}
-
 /****************************************************************************
   process commands from the client
 ****************************************************************************/