local.h: Fix spelling mistake :-).
[kai/samba.git] / source3 / smbd / reply.c
index cb0e5d7628dd6522f2e20401deb2b347d2c4ba56..baccb76291146b9714eb1d8bab6ca6c46b8f5c7a 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 */
@@ -49,43 +50,54 @@ a packet to ensure chaining works correctly */
 
 
 /****************************************************************************
-  reply to an special message 
+report a possible attack via the password buffer overflow bug
 ****************************************************************************/
-int reply_special(char *inbuf,char *outbuf)
+static void overflow_attack(int len)
 {
-  int outsize = 4;
-  int msg_type = CVAL(inbuf,0);
-  int msg_flags = CVAL(inbuf,1);
-  pstring name1,name2;
-  extern fstring remote_machine;
-  extern fstring local_machine;
-  char *p;
-
-  *name1 = *name2 = 0;
+       DEBUG(0,("ERROR: Invalid password length %d\n", len));
+       DEBUG(0,("your machine may be under attack by a user exploiting an old bug\n"));
+       DEBUG(0,("Attack was from IP=%s\n", client_addr()));
+       exit_server("possible attack");
+}
 
-  smb_setlen(outbuf,0);
 
-  switch (msg_type)
-    {
+/****************************************************************************
+  reply to an special message 
+****************************************************************************/
+int reply_special(char *inbuf,char *outbuf)
+{
+       int outsize = 4;
+       int msg_type = CVAL(inbuf,0);
+       int msg_flags = CVAL(inbuf,1);
+       pstring name1,name2;
+       extern fstring remote_machine;
+       extern fstring local_machine;
+       char *p;
+       
+       *name1 = *name2 = 0;
+       
+       smb_setlen(outbuf,0);
+       
+       switch (msg_type) {
     case 0x81: /* session request */
       CVAL(outbuf,0) = 0x82;
       CVAL(outbuf,3) = 0;
-      if (name_len(inbuf+4) > 50)
-       {
-         DEBUG(0,("Invalid name length in session request\n"));
-         return(0);
-       }
+      if (name_len(inbuf+4) > 50 || name_len(inbuf+4 + name_len(inbuf + 4)) > 50) {
+             DEBUG(0,("Invalid name length in session request\n"));
+             return(0);
+      }
       name_extract(inbuf,4,name1);
       name_extract(inbuf,4 + name_len(inbuf + 4),name2);
-      DEBUG(2,("netbios connect: name1=%s name2=%s\n",name1,name2));      
+               DEBUG(2,("netbios connect: name1=%s name2=%s\n",
+                        name1,name2));      
 
-      strcpy(remote_machine,name2);
+      fstrcpy(remote_machine,name2);
       trim_string(remote_machine," "," ");
       p = strchr(remote_machine,' ');
       strlower(remote_machine);
       if (p) *p = 0;
 
-      strcpy(local_machine,name1);
+      fstrcpy(local_machine,name1);
       trim_string(local_machine," "," ");
       p = strchr(local_machine,' ');
       strlower(local_machine);
@@ -97,14 +109,28 @@ int reply_special(char *inbuf,char *outbuf)
       reopen_logs();
 
       break;
-    case 0x85: /* session keepalive */
-    default:
-      return(0);
-    }
-  
-  DEBUG(5,("%s init msg_type=0x%x msg_flags=0x%x\n",timestring(),msg_type,msg_flags));
-  
-  return(outsize);
+               
+       case 0x89: /* session keepalive request 
+                     (some old clients produce this?) */
+               CVAL(outbuf,0) = 0x85;
+               CVAL(outbuf,3) = 0;
+               break;
+               
+       case 0x82: /* positive session response */
+       case 0x83: /* negative session response */
+       case 0x84: /* retarget session response */
+               DEBUG(0,("Unexpected session response\n"));
+               break;
+               
+       case 0x85: /* session keepalive */
+       default:
+               return(0);
+       }
+       
+       DEBUG(5,("%s init msg_type=0x%x msg_flags=0x%x\n",
+                timestring(),msg_type,msg_flags));
+       
+       return(outsize);
 }
 
 
@@ -147,25 +173,25 @@ static void parse_connect(char *p,char *service,char *user,
     
   p2 = strrchr(p,'\\');
   if (p2 == NULL)
-    strcpy(service,p);
+    fstrcpy(service,p);
   else
-    strcpy(service,p2+1);
+    fstrcpy(service,p2+1);
   
   p += strlen(p) + 2;
   
-  strcpy(password,p);
+  fstrcpy(password,p);
   *pwlen = strlen(password);
 
   p += strlen(p) + 2;
 
-  strcpy(dev,p);
+  fstrcpy(dev,p);
   
   *user = 0;
   p = strchr(service,'%');
   if (p != NULL)
     {
       *p = 0;
-      strcpy(user,p+1);
+      fstrcpy(user,p+1);
     }
 }
 
@@ -225,6 +251,10 @@ int reply_tcon_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   /* we might have to close an old one */
   if ((SVAL(inbuf,smb_vwv2) & 0x1) != 0)
     close_cnum(SVAL(inbuf,smb_tid),vuid);
+
+  if (passlen > MAX_PASS_LEN) {
+         overflow_attack(passlen);
+  }
   
   {
     char *path;
@@ -239,18 +269,17 @@ int reply_tcon_and_X(char *inbuf,char *outbuf,int length,int bufsize)
       passlen = strlen(password);
     }
     
-    DEBUG(4,("parsing net-path %s, passlen=%d\n",path,passlen));
-    strcpy(service,path+2);
+    fstrcpy(service,path+2);
     p = strchr(service,'\\');
     if (!p)
       return(ERROR(ERRSRV,ERRinvnetname));
     *p = 0;
-    strcpy(service,p+1);
+    fstrcpy(service,p+1);
     p = strchr(service,'%');
     if (p)
       {
        *p++ = 0;
-       strcpy(user,p);
+       fstrcpy(user,p);
       }
     StrnCpy(devicename,path + strlen(path) + 1,6);
     DEBUG(4,("Got device type %s\n",devicename));
@@ -359,11 +388,17 @@ 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_PASS_LEN)
+    {
+           overflow_attack(smb_apasslen);
+    }
+
     memcpy(smb_apasswd,smb_buf(inbuf),smb_apasslen);
-    StrnCpy(user,smb_buf(inbuf)+smb_apasslen,sizeof(user)-1);
+    pstrcpy(user,smb_buf(inbuf)+smb_apasslen);
 
-    if (lp_security() != SEC_SERVER && !doencrypt)
-      smb_apasslen = strlen(smb_apasswd);
+    if (lp_security() != SEC_SERVER && !doencrypt) {
+           smb_apasslen = strlen(smb_apasswd);
+    }
   } else {
     uint16 passlen1 = SVAL(inbuf,smb_vwv7);
     uint16 passlen2 = SVAL(inbuf,smb_vwv8);
@@ -388,6 +423,13 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
     if (passlen1 != 24 && passlen2 != 24)
       doencrypt = False;
 
+    if (passlen1 > MAX_PASS_LEN) {
+           overflow_attack(passlen1);
+    }
+
+    passlen1 = MIN(passlen1, MAX_PASS_LEN);
+    passlen2 = MIN(passlen2, MAX_PASS_LEN);
+
     if(doencrypt) {
       /* Save the lanman2 password and the NT md4 password. */
       smb_apasslen = passlen1;
@@ -425,7 +467,7 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
     }
     
     p += passlen1 + passlen2;
-    strcpy(user,p); p = skip_string(p,1);
+    fstrcpy(user,p); p = skip_string(p,1);
     DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s]\n",
             p,skip_string(p,1),skip_string(p,2)));
   }
@@ -557,7 +599,7 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   if (!done_sesssetup)
     max_send = MIN(max_send,smb_bufsize);
 
-  DEBUG(1,(" Client requested max send size of %d\n", max_send));
+  DEBUG(6,("Client requested max send size of %d\n", max_send));
 
   done_sesssetup = True;
 
@@ -578,7 +620,7 @@ int reply_chkpth(char *inbuf,char *outbuf)
  
   cnum = SVAL(inbuf,smb_tid);
   
-  strcpy(name,smb_buf(inbuf) + 1);
+  pstrcpy(name,smb_buf(inbuf) + 1);
   unix_convert(name,cnum,0,&bad_path);
 
   mode = SVAL(inbuf,smb_vwv0);
@@ -598,6 +640,17 @@ int reply_chkpth(char *inbuf,char *outbuf)
       unix_ERR_class = ERRDOS;
       unix_ERR_code = ERRbadpath;
     }
+
+#if 0
+    /* Ugly - NT specific hack - maybe not needed ? (JRA) */
+    if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) &&
+       (get_remote_arch() == RA_WINNT))
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbaddirectory;
+    }
+#endif
+
     return(UNIXERROR(ERRDOS,ERRbadpath));
   }
  
@@ -626,7 +679,7 @@ int reply_getatr(char *inbuf,char *outbuf)
  
   cnum = SVAL(inbuf,smb_tid);
 
-  strcpy(fname,smb_buf(inbuf) + 1);
+  pstrcpy(fname,smb_buf(inbuf) + 1);
   unix_convert(fname,cnum,0,&bad_path);
 
   /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
@@ -701,7 +754,7 @@ int reply_setatr(char *inbuf,char *outbuf)
  
   cnum = SVAL(inbuf,smb_tid);
   
-  strcpy(fname,smb_buf(inbuf) + 1);
+  pstrcpy(fname,smb_buf(inbuf) + 1);
   unix_convert(fname,cnum,0,&bad_path);
 
   mode = SVAL(inbuf,smb_vwv0);
@@ -812,8 +865,8 @@ int reply_search(char *inbuf,char *outbuf)
     {
       pstring dir2;
 
-      strcpy(directory,smb_buf(inbuf)+1);
-      strcpy(dir2,smb_buf(inbuf)+1);
+      pstrcpy(directory,smb_buf(inbuf)+1);
+      pstrcpy(dir2,smb_buf(inbuf)+1);
       unix_convert(directory,cnum,0,&bad_path);
       unix_format(dir2);
 
@@ -829,7 +882,7 @@ int reply_search(char *inbuf,char *outbuf)
       else
       {
         *p = 0;
-        strcpy(mask,p+1);
+        pstrcpy(mask,p+1);
       }
 
       p = strrchr(directory,'/');
@@ -863,7 +916,7 @@ int reply_search(char *inbuf,char *outbuf)
     if ((p = strrchr(mask,' ')))
       {
        fstring ext;
-       strcpy(ext,p+1);
+       fstrcpy(ext,p+1);
        *p = 0;
        trim_string(mask,NULL," ");
        strcat(mask,".");
@@ -885,7 +938,7 @@ int reply_search(char *inbuf,char *outbuf)
   if (!strchr(mask,'.') && strlen(mask)>8)
     {
       fstring tmp;
-      strcpy(tmp,&mask[8]);
+      fstrcpy(tmp,&mask[8]);
       mask[8] = '.';
       mask[9] = 0;
       strcat(mask,tmp);
@@ -1060,12 +1113,14 @@ int reply_open(char *inbuf,char *outbuf)
   int rmode=0;
   struct stat sbuf;
   BOOL bad_path = False;
+  files_struct *fsp;
+  int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
  
   cnum = SVAL(inbuf,smb_tid);
 
   share_mode = SVAL(inbuf,smb_vwv0);
 
-  strcpy(fname,smb_buf(inbuf)+1);
+  pstrcpy(fname,smb_buf(inbuf)+1);
   unix_convert(fname,cnum,0,&bad_path);
     
   fnum = find_free_file();
@@ -1084,9 +1139,12 @@ int reply_open(char *inbuf,char *outbuf)
  
   unixmode = unix_mode(cnum,aARCH);
       
-  open_file_shared(fnum,cnum,fname,share_mode,3,unixmode,&rmode,NULL);
+  open_file_shared(fnum,cnum,fname,share_mode,3,unixmode,
+                   oplock_request,&rmode,NULL);
 
-  if (!Files[fnum].open)
+  fsp = &Files[fnum];
+
+  if (!fsp->open)
   {
     if((errno == ENOENT) && bad_path)
     {
@@ -1096,7 +1154,7 @@ int reply_open(char *inbuf,char *outbuf)
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
 
-  if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) {
+  if (fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
     close_file(fnum);
     return(ERROR(ERRDOS,ERRnoaccess));
   }
@@ -1118,10 +1176,12 @@ int reply_open(char *inbuf,char *outbuf)
   SIVAL(outbuf,smb_vwv4,size);
   SSVAL(outbuf,smb_vwv6,rmode);
 
-  if (lp_fake_oplocks(SNUM(cnum))) {
-    CVAL(outbuf,smb_flg) |= (CVAL(inbuf,smb_flg) & (1<<5));
+  if (oplock_request && lp_fake_oplocks(SNUM(cnum))) {
+    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
   }
     
+  if(fsp->granted_oplock)
+    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
   return(outsize);
 }
 
@@ -1136,7 +1196,7 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   int fnum = -1;
   int smb_mode = SVAL(inbuf,smb_vwv3);
   int smb_attr = SVAL(inbuf,smb_vwv5);
-  BOOL oplock_request = BITSETW(inbuf+smb_vwv2,1);
+  BOOL oplock_request = EXTENDED_OPLOCK_REQUEST(inbuf);
 #if 0
   int open_flags = SVAL(inbuf,smb_vwv2);
   int smb_sattr = SVAL(inbuf,smb_vwv4); 
@@ -1148,6 +1208,7 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   struct stat sbuf;
   int smb_action = 0;
   BOOL bad_path = False;
+  files_struct *fsp;
 
   /* If it's an IPC, pass off the pipe handler. */
   if (IS_IPC(cnum))
@@ -1155,7 +1216,7 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
 
   /* XXXX we need to handle passed times, sattr and flags */
 
-  strcpy(fname,smb_buf(inbuf));
+  pstrcpy(fname,smb_buf(inbuf));
   unix_convert(fname,cnum,0,&bad_path);
     
   fnum = find_free_file();
@@ -1175,9 +1236,11 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   unixmode = unix_mode(cnum,smb_attr | aARCH);
       
   open_file_shared(fnum,cnum,fname,smb_mode,smb_ofun,unixmode,
-                  &rmode,&smb_action);
+                  oplock_request, &rmode,&smb_action);
       
-  if (!Files[fnum].open)
+  fsp = &Files[fnum];
+
+  if (!fsp->open)
   {
     if((errno == ENOENT) && bad_path)
     {
@@ -1187,7 +1250,7 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
 
-  if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) {
+  if (fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
     close_file(fnum);
     return(ERROR(ERRDOS,ERRnoaccess));
   }
@@ -1201,7 +1264,13 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   }
 
   if (oplock_request && lp_fake_oplocks(SNUM(cnum))) {
-    smb_action |= (1<<15);
+    smb_action |= EXTENDED_OPLOCK_GRANTED;
+    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+  }
+
+  if(fsp->granted_oplock) {
+    smb_action |= EXTENDED_OPLOCK_GRANTED;
+    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
   }
 
   set_message(outbuf,15,0,True);
@@ -1263,12 +1332,14 @@ int reply_mknew(char *inbuf,char *outbuf)
   mode_t unixmode;
   int ofun = 0;
   BOOL bad_path = False;
+  files_struct *fsp;
+  int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
  
   com = SVAL(inbuf,smb_com);
   cnum = SVAL(inbuf,smb_tid);
 
   createmode = SVAL(inbuf,smb_vwv0);
-  strcpy(fname,smb_buf(inbuf)+1);
+  pstrcpy(fname,smb_buf(inbuf)+1);
   unix_convert(fname,cnum,0,&bad_path);
 
   if (createmode & aVOLID)
@@ -1304,9 +1375,12 @@ int reply_mknew(char *inbuf,char *outbuf)
   }
 
   /* Open file in dos compatibility share mode. */
-  open_file_shared(fnum,cnum,fname,(DENY_FCB<<4)|0xF, ofun, unixmode, NULL, NULL);
+  open_file_shared(fnum,cnum,fname,(DENY_FCB<<4)|0xF, ofun, unixmode, 
+                   oplock_request, NULL, NULL);
   
-  if (!Files[fnum].open)
+  fsp = &Files[fnum];
+
+  if (!fsp->open)
   {
     if((errno == ENOENT) && bad_path) 
     {
@@ -1319,10 +1393,13 @@ int reply_mknew(char *inbuf,char *outbuf)
   outsize = set_message(outbuf,1,0,True);
   SSVAL(outbuf,smb_vwv0,fnum);
 
-  if (lp_fake_oplocks(SNUM(cnum))) {
-    CVAL(outbuf,smb_flg) |= (CVAL(inbuf,smb_flg) & (1<<5));
+  if (oplock_request && lp_fake_oplocks(SNUM(cnum))) {
+    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
   }
-  
+  if(fsp->granted_oplock)
+    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
   DEBUG(2,("new file %s\n",fname));
   DEBUG(3,("%s mknew %s fd=%d fnum=%d cnum=%d dmode=%d umode=%o\n",timestring(),fname,Files[fnum].fd_ptr->fd,fnum,cnum,createmode,unixmode));
   
@@ -1343,10 +1420,13 @@ int reply_ctemp(char *inbuf,char *outbuf)
   int createmode;
   mode_t unixmode;
   BOOL bad_path = False;
+  files_struct *fsp;
+  int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
  
   cnum = SVAL(inbuf,smb_tid);
   createmode = SVAL(inbuf,smb_vwv0);
-  sprintf(fname,"%s/TMXXXXXX",smb_buf(inbuf)+1);
+  pstrcpy(fname,smb_buf(inbuf)+1);
+  strcat(fname,"/TMXXXXXX");
   unix_convert(fname,cnum,0,&bad_path);
   
   unixmode = unix_mode(cnum,createmode);
@@ -1369,9 +1449,12 @@ int reply_ctemp(char *inbuf,char *outbuf)
 
   /* Open file in dos compatibility share mode. */
   /* We should fail if file exists. */
-  open_file_shared(fnum,cnum,fname2,(DENY_FCB<<4)|0xF, 0x10, unixmode, NULL, NULL);
+  open_file_shared(fnum,cnum,fname2,(DENY_FCB<<4)|0xF, 0x10, unixmode, 
+                   oplock_request, NULL, NULL);
 
-  if (!Files[fnum].open)
+  fsp = &Files[fnum];
+
+  if (!fsp->open)
   {
     if((errno == ENOENT) && bad_path)
     {
@@ -1386,10 +1469,13 @@ int reply_ctemp(char *inbuf,char *outbuf)
   CVAL(smb_buf(outbuf),0) = 4;
   strcpy(smb_buf(outbuf) + 1,fname2);
 
-  if (lp_fake_oplocks(SNUM(cnum))) {
-    CVAL(outbuf,smb_flg) |= (CVAL(inbuf,smb_flg) & (1<<5));
+  if (oplock_request && lp_fake_oplocks(SNUM(cnum))) {
+    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
   }
   
+  if(fsp->granted_oplock)
+    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+
   DEBUG(2,("created temp file %s\n",fname2));
   DEBUG(3,("%s ctemp %s fd=%d fnum=%d cnum=%d dmode=%d umode=%o\n",timestring(),fname2,Files[fnum].fd_ptr->fd,fnum,cnum,createmode,unixmode));
   
@@ -1442,7 +1528,7 @@ int reply_unlink(char *inbuf,char *outbuf)
   cnum = SVAL(inbuf,smb_tid);
   dirtype = SVAL(inbuf,smb_vwv0);
   
-  strcpy(name,smb_buf(inbuf) + 1);
+  pstrcpy(name,smb_buf(inbuf) + 1);
    
   DEBUG(3,("reply_unlink : %s\n",name));
    
@@ -1490,7 +1576,7 @@ int reply_unlink(char *inbuf,char *outbuf)
        while ((dname = ReadDirName(dirptr)))
          {
            pstring fname;
-           strcpy(fname,dname);
+           pstrcpy(fname,dname);
            
            if(!mask_match(fname, mask, case_sensitive, False)) continue;
 
@@ -1537,6 +1623,20 @@ int reply_readbraw(char *inbuf, char *outbuf)
   int fd;
   char *fname;
 
+  /*
+   * Special check if an oplock break has been issued
+   * and the readraw request croses on the wire, we must
+   * return a zero length response here.
+   */
+
+  if(global_oplock_break)
+  {
+    _smb_setlen(header,0);
+    transfer_file(0,Client,0,header,4,0);
+    DEBUG(5,("readbraw - oplock break finished\n"));
+    return -1;
+  }
+
   cnum = SVAL(inbuf,smb_tid);
   fnum = GETFNUM(inbuf,smb_vwv0);
 
@@ -2368,7 +2468,7 @@ int reply_printopen(char *inbuf,char *outbuf)
   {
     pstring s;
     char *p;
-    StrnCpy(s,smb_buf(inbuf)+1,sizeof(pstring)-1);
+    pstrcpy(s,smb_buf(inbuf)+1);
     p = s;
     while (*p)
       {
@@ -2392,7 +2492,8 @@ int reply_printopen(char *inbuf,char *outbuf)
     return(ERROR(ERRDOS,ERRnoaccess));
 
   /* Open for exclusive use, write only. */
-  open_file_shared(fnum,cnum,fname2,(DENY_ALL<<4)|1, 0x12, unix_mode(cnum,0), NULL, NULL);
+  open_file_shared(fnum,cnum,fname2,(DENY_ALL<<4)|1, 0x12, unix_mode(cnum,0), 
+                   0, NULL, NULL);
 
   if (!Files[fnum].open)
     return(UNIXERROR(ERRDOS,ERRnoaccess));
@@ -2570,7 +2671,7 @@ int reply_mkdir(char *inbuf,char *outbuf)
   int outsize,ret= -1;
   BOOL bad_path = False;
  
-  strcpy(directory,smb_buf(inbuf) + 1);
+  pstrcpy(directory,smb_buf(inbuf) + 1);
   cnum = SVAL(inbuf,smb_tid);
   unix_convert(directory,cnum,0,&bad_path);
   
@@ -2667,7 +2768,7 @@ int reply_rmdir(char *inbuf,char *outbuf)
   BOOL bad_path = False;
 
   cnum = SVAL(inbuf,smb_tid);
-  strcpy(directory,smb_buf(inbuf) + 1);
+  pstrcpy(directory,smb_buf(inbuf) + 1);
   unix_convert(directory,cnum,0,&bad_path);
   
   if (check_name(directory,cnum))
@@ -2715,7 +2816,7 @@ int reply_rmdir(char *inbuf,char *outbuf)
                           errno = ENOMEM;
                           break;
                         }
-                      strcpy(fullname, directory);
+                      pstrcpy(fullname, directory);
                       strcat(fullname, "/");
                       strcat(fullname, dname);
                       
@@ -2782,21 +2883,21 @@ static BOOL resolve_wildcards(char *name1,char *name2)
 
   if (!name1 || !name2) return(False);
   
-  strcpy(root1,name1);
-  strcpy(root2,name2);
+  fstrcpy(root1,name1);
+  fstrcpy(root2,name2);
   p = strrchr(root1,'.');
   if (p) {
     *p = 0;
-    strcpy(ext1,p+1);
+    fstrcpy(ext1,p+1);
   } else {
-    strcpy(ext1,"");    
+    fstrcpy(ext1,"");    
   }
   p = strrchr(root2,'.');
   if (p) {
     *p = 0;
-    strcpy(ext2,p+1);
+    fstrcpy(ext2,p+1);
   } else {
-    strcpy(ext2,"");    
+    fstrcpy(ext2,"");    
   }
 
   p = root1;
@@ -2870,8 +2971,8 @@ int reply_mv(char *inbuf,char *outbuf)
 
   cnum = SVAL(inbuf,smb_tid);
   
-  strcpy(name,smb_buf(inbuf) + 1);
-  strcpy(newname,smb_buf(inbuf) + 3 + strlen(name));
+  pstrcpy(name,smb_buf(inbuf) + 1);
+  pstrcpy(newname,smb_buf(inbuf) + 3 + strlen(name));
    
   DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
    
@@ -2985,14 +3086,14 @@ int reply_mv(char *inbuf,char *outbuf)
        while ((dname = ReadDirName(dirptr)))
          {
            pstring fname;
-           strcpy(fname,dname);
+           pstrcpy(fname,dname);
            
            if(!mask_match(fname, mask, case_sensitive, False)) continue;
 
            error = ERRnoaccess;
            sprintf(fname,"%s/%s",directory,dname);
            if (!can_rename(fname,cnum)) continue;
-           strcpy(destname,newname);
+           pstrcpy(destname,newname);
 
            if (!resolve_wildcards(fname,destname)) continue;
 
@@ -3038,7 +3139,7 @@ static BOOL copy_file(char *src,char *dest1,int cnum,int ofun,
   int fnum1,fnum2;
   pstring dest;
   
-  strcpy(dest,dest1);
+  pstrcpy(dest,dest1);
   if (target_is_directory) {
     char *p = strrchr(src,'/');
     if (p) 
@@ -3054,7 +3155,7 @@ static BOOL copy_file(char *src,char *dest1,int cnum,int ofun,
   fnum1 = find_free_file();
   if (fnum1<0) return(False);
   open_file_shared(fnum1,cnum,src,(DENY_NONE<<4),
-                  1,0,&Access,&action);
+                  1,0,0,&Access,&action);
 
   if (!Files[fnum1].open) return(False);
 
@@ -3067,7 +3168,7 @@ static BOOL copy_file(char *src,char *dest1,int cnum,int ofun,
     return(False);
   }
   open_file_shared(fnum2,cnum,dest,(DENY_NONE<<4)|1,
-                  ofun,st.st_mode,&Access,&action);
+                  ofun,st.st_mode,0,&Access,&action);
 
   if (!Files[fnum2].open) {
     close_file(fnum1);
@@ -3115,8 +3216,8 @@ int reply_copy(char *inbuf,char *outbuf)
 
   cnum = SVAL(inbuf,smb_tid);
   
-  strcpy(name,smb_buf(inbuf));
-  strcpy(newname,smb_buf(inbuf) + 1 + strlen(name));
+  pstrcpy(name,smb_buf(inbuf));
+  pstrcpy(newname,smb_buf(inbuf) + 1 + strlen(name));
    
   DEBUG(3,("reply_copy : %s -> %s\n",name,newname));
    
@@ -3185,7 +3286,7 @@ int reply_copy(char *inbuf,char *outbuf)
        while ((dname = ReadDirName(dirptr)))
          {
            pstring fname;
-           strcpy(fname,dname);
+           pstrcpy(fname,dname);
            
            if(!mask_match(fname, mask, case_sensitive, False)) continue;
 
@@ -3239,7 +3340,7 @@ int reply_setdir(char *inbuf,char *outbuf)
   if (!CAN_SETDIR(snum))
     return(ERROR(ERRDOS,ERRnoaccess));
   
-  strcpy(newdir,smb_buf(inbuf) + 1);
+  pstrcpy(newdir,smb_buf(inbuf) + 1);
   strlower(newdir);
   
   if (strlen(newdir) == 0)
@@ -3269,7 +3370,10 @@ int reply_setdir(char *inbuf,char *outbuf)
 int reply_lockingX(char *inbuf,char *outbuf,int length,int bufsize)
 {
   int fnum = GETFNUM(inbuf,smb_vwv2);
-  uint16 locktype = SVAL(inbuf,smb_vwv3);
+  unsigned char locktype = CVAL(inbuf,smb_vwv3);
+#if 0
+  unsigned char oplocklevel = CVAL(inbuf,smb_vwv3+1);
+#endif
   uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
   uint16 num_locks = SVAL(inbuf,smb_vwv7);
   uint32 count, offset;
@@ -3286,6 +3390,48 @@ int reply_lockingX(char *inbuf,char *outbuf,int length,int bufsize)
   CHECK_ERROR(fnum);
 
   data = smb_buf(inbuf);
+
+  /* Check if this is an oplock break on a file
+     we have granted an oplock on.
+   */
+  if((locktype == LOCKING_ANDX_OPLOCK_RELEASE) && 
+     (num_ulocks == 0) && (num_locks == 0) &&
+     (CVAL(inbuf,smb_vwv0) == 0xFF))
+  {
+    share_lock_token token;
+    files_struct *fsp = &Files[fnum];
+    uint32 dev = fsp->fd_ptr->dev;
+    uint32 inode = fsp->fd_ptr->inode;
+
+    DEBUG(5,("reply_lockingX: oplock break reply from client for fnum = %d\n",
+              fnum));
+    /*
+     * Make sure we have granted an oplock on this file.
+     */
+    if(!fsp->granted_oplock)
+    {
+      DEBUG(0,("reply_lockingX: Error : oplock break from client for fnum = %d and \
+no oplock granted on this file.\n", fnum));
+      return ERROR(ERRDOS,ERRlock);
+    }
+
+    /* Remove the oplock flag from the sharemode. */
+    lock_share_entry(fsp->cnum, dev, inode, &token);
+    if(remove_share_oplock( fnum, token)==False)
+    {
+      DEBUG(0,("reply_lockingX: failed to remove share oplock for fnum %d, \
+dev = %x, inode = %x\n", fnum, dev, inode));
+      unlock_share_entry(fsp->cnum, dev, inode, token);
+      return -1;
+    }
+    unlock_share_entry(fsp->cnum, dev, inode, token);
+
+    /* Clear the granted flag and return. */
+
+    fsp->granted_oplock = False;
+    return -1;
+  }
+
   /* Data now points at the beginning of the list
      of smb_unlkrng structs */
   for(i = 0; i < (int)num_ulocks; i++) {
@@ -3320,7 +3466,7 @@ int reply_lockingX(char *inbuf,char *outbuf,int length,int bufsize)
   set_message(outbuf,2,0,True);
   
   DEBUG(3,("%s lockingX fnum=%d cnum=%d type=%d num_locks=%d num_ulocks=%d\n",
-       timestring(),fnum,cnum,locktype,num_locks,num_ulocks));
+       timestring(),fnum,cnum,(unsigned int)locktype,num_locks,num_ulocks));
 
   chain_fnum = fnum;
 
@@ -3597,11 +3743,31 @@ int reply_setattrE(char *inbuf,char *outbuf)
   unix_times.actime = make_unix_date2(inbuf+smb_vwv3);
   unix_times.modtime = make_unix_date2(inbuf+smb_vwv5);
   
+  /* 
+   * Patch from Ray Frush <frush@engr.colostate.edu>
+   * Sometimes times are sent as zero - ignore them.
+   */
+
+  if ((unix_times.actime == 0) && (unix_times.modtime == 0)) 
+  {
+    /* Ignore request */
+    DEBUG(3,("%s reply_setattrE fnum=%d cnum=%d ignoring zero request - \
+not setting timestamps of 0\n",
+          timestring(), fnum,cnum,unix_times.actime,unix_times.modtime));
+    return(outsize);
+  }
+  else if ((unix_times.actime != 0) && (unix_times.modtime == 0)) 
+  {
+    /* set modify time = to access time if modify time was 0 */
+    unix_times.modtime = unix_times.actime;
+  }
+
   /* Set the date on this file */
   if(sys_utime(Files[fnum].name, &unix_times))
     return(ERROR(ERRDOS,ERRnoaccess));
   
-  DEBUG(3,("%s reply_setattrE fnum=%d cnum=%d\n",timestring(),fnum,cnum));
+  DEBUG(3,("%s reply_setattrE fnum=%d cnum=%d actime=%d modtime=%d\n",
+    timestring(), fnum,cnum,unix_times.actime,unix_times.modtime));
 
   return(outsize);
 }
@@ -3653,8 +3819,3 @@ int reply_getattrE(char *inbuf,char *outbuf)
   
   return(outsize);
 }
-
-
-
-
-