local.h: Fix spelling mistake :-).
[kai/samba.git] / source3 / smbd / reply.c
index 5f030d537241a6250f769709787400a031138b13..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));
@@ -261,7 +290,26 @@ int reply_tcon_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   if (connection_num < 0)
     return(connection_error(inbuf,outbuf,connection_num));
 
-  set_message(outbuf,2,strlen(devicename)+1,True);
+  if (Protocol < PROTOCOL_NT1)
+  {
+    set_message(outbuf,2,strlen(devicename)+1,True);
+    strcpy(smb_buf(outbuf),devicename);
+  }
+  else
+  {
+    char *fsname = "SAMBA";
+    char *p;
+
+    set_message(outbuf,3,3,True);
+
+    p = smb_buf(outbuf);
+    strcpy(p,devicename); p = skip_string(p,1); /* device name */
+    strcpy(p,fsname); p = skip_string(p,1); /* filesystem type e.g NTFS */
+
+    set_message(outbuf,3,PTR_DIFF(p,smb_buf(outbuf)),False);
+
+    SSVAL(outbuf, smb_vwv2, 0x0); /* optional support */
+  }
   
   DEBUG(3,("%s tconX service=%s user=%s cnum=%d\n",timestring(),service,user,connection_num));
   
@@ -269,8 +317,6 @@ int reply_tcon_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   SSVAL(inbuf,smb_tid,connection_num);
   SSVAL(outbuf,smb_tid,connection_num);
 
-  strcpy(smb_buf(outbuf),devicename);
-
   return chain_reply(inbuf,outbuf,length,bufsize);
 }
 
@@ -342,19 +388,48 @@ 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);
+    uint32 client_caps = IVAL(inbuf,smb_vwv11);
+    enum remote_arch_types ra_type = get_remote_arch();
+
     char *p = smb_buf(inbuf);    
 
+    /* client_caps is used as final determination if client is NT or Win95. 
+       This is needed to return the correct error codes in some
+       circumstances.
+     */
+    
+    if(ra_type == RA_WINNT || ra_type == RA_WIN95)
+    {
+      if(client_caps & (CAP_NT_SMBS | CAP_STATUS32))
+        set_remote_arch( RA_WINNT);
+      else
+        set_remote_arch( RA_WIN95);
+    }
+
     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;
@@ -392,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)));
   }
@@ -409,8 +484,14 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   }
 
 
+  /* If no username is sent use the guest account */
   if (!*user)
-    strcpy(user,lp_guestaccount(-1));
+    {
+      strcpy(user,lp_guestaccount(-1));
+      /* If no user and no password then set guest flag. */
+      if( *smb_apasswd == 0)
+        guest = True;
+    }
 
   strlower(user);
 
@@ -420,25 +501,30 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
 
   add_session_user(user);
 
+  /* Check if the given username was the guest user with no password.
+     We need to do this check after add_session_user() as that
+     call can potentially change the username (via map_user).
+   */
 
-  if (!(lp_security() == SEC_SERVER && server_validate(inbuf)) &&
+  if(!guest && strequal(user,lp_guestaccount(-1)) && (*smb_apasswd == 0))
+    guest = True;
+
+  if (!guest && !(lp_security() == SEC_SERVER && server_validate(inbuf)) &&
       !check_hosts_equiv(user))
     {
 
-      if (strequal(user,lp_guestaccount(-1)) && (*smb_apasswd == 0))
-       guest = True;
-  
       /* now check if it's a valid username/password */
       /* If an NT password was supplied try and validate with that
-        first. This is superior as the passwords are mixed case 128 length unicode */
-      if(smb_ntpasslen && !guest)
+        first. This is superior as the passwords are mixed case 
+         128 length unicode */
+      if(smb_ntpasslen)
        {
          if(!password_ok(user,smb_ntpasswd,smb_ntpasslen,NULL))
            DEBUG(0,("NT Password did not match ! Defaulting to Lanman\n"));
          else
            valid_nt_password = True;
        } 
-      if (!valid_nt_password && !guest && !password_ok(user,smb_apasswd,smb_apasslen,NULL))
+      if (!valid_nt_password && !password_ok(user,smb_apasswd,smb_apasslen,NULL))
        {
          if (!computer_id && lp_security() >= SEC_USER) {
 #if (GUEST_SESSSETUP == 0)
@@ -513,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;
 
@@ -530,11 +616,12 @@ int reply_chkpth(char *inbuf,char *outbuf)
   int cnum,mode;
   pstring name;
   BOOL ok = False;
-  
+  BOOL bad_path = False;
   cnum = SVAL(inbuf,smb_tid);
   
-  strcpy(name,smb_buf(inbuf) + 1);
-  unix_convert(name,cnum,0);
+  pstrcpy(name,smb_buf(inbuf) + 1);
+  unix_convert(name,cnum,0,&bad_path);
 
   mode = SVAL(inbuf,smb_vwv0);
 
@@ -542,8 +629,31 @@ int reply_chkpth(char *inbuf,char *outbuf)
     ok = directory_exist(name,NULL);
 
   if (!ok)
-    return(ERROR(ERRDOS,ERRbadpath));
-  
+  {
+    /* We special case this - as when a Windows machine
+       is parsing a path is steps through the components
+       one at a time - if a component fails it expects
+       ERRbadpath, not ERRbadfile.
+     */
+    if(errno == ENOENT)
+    {
+      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));
+  }
   outsize = set_message(outbuf,0,0,True);
   
   DEBUG(3,("%s chkpth %s cnum=%d mode=%d\n",timestring(),name,cnum,mode));
@@ -565,11 +675,12 @@ int reply_getatr(char *inbuf,char *outbuf)
   int mode=0;
   uint32 size=0;
   time_t mtime=0;
-  
+  BOOL bad_path = False;
   cnum = SVAL(inbuf,smb_tid);
 
-  strcpy(fname,smb_buf(inbuf) + 1);
-  unix_convert(fname,cnum,0);
+  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"
      under WfWg - weird! */
@@ -583,23 +694,31 @@ int reply_getatr(char *inbuf,char *outbuf)
     }
   else
     if (check_name(fname,cnum))
+    {
+      if (sys_stat(fname,&sbuf) == 0)
       {
-       if (sys_stat(fname,&sbuf) == 0)
-         {
-           mode = dos_mode(cnum,fname,&sbuf);
-           size = sbuf.st_size;
-           mtime = sbuf.st_mtime;
-           if (mode & aDIR)
-             size = 0;
-           ok = True;
-         }
-       else
-         DEBUG(3,("stat of %s failed (%s)\n",fname,strerror(errno)));
+        mode = dos_mode(cnum,fname,&sbuf);
+        size = sbuf.st_size;
+        mtime = sbuf.st_mtime;
+        if (mode & aDIR)
+          size = 0;
+        ok = True;
+      }
+      else
+        DEBUG(3,("stat of %s failed (%s)\n",fname,strerror(errno)));
     }
   
   if (!ok)
+  {
+    if((errno == ENOENT) && bad_path)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
+
     return(UNIXERROR(ERRDOS,ERRbadfile));
-  
+  }
   outsize = set_message(outbuf,10,0,True);
 
   SSVAL(outbuf,smb_vwv0,mode);
@@ -631,11 +750,12 @@ int reply_setatr(char *inbuf,char *outbuf)
   BOOL ok=False;
   int mode;
   time_t mtime;
-  
+  BOOL bad_path = False;
   cnum = SVAL(inbuf,smb_tid);
   
-  strcpy(fname,smb_buf(inbuf) + 1);
-  unix_convert(fname,cnum,0);
+  pstrcpy(fname,smb_buf(inbuf) + 1);
+  unix_convert(fname,cnum,0,&bad_path);
 
   mode = SVAL(inbuf,smb_vwv0);
   mtime = make_unix_date3(inbuf+smb_vwv1);
@@ -648,8 +768,16 @@ int reply_setatr(char *inbuf,char *outbuf)
     ok = set_filetime(fname,mtime);
   
   if (!ok)
+  {
+    if((errno == ENOENT) && bad_path)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
+
     return(UNIXERROR(ERRDOS,ERRnoaccess));
-  
+  }
   outsize = set_message(outbuf,0,0,True);
   
   DEBUG(3,("%s setatr name=%s mode=%d\n",timestring(),fname,mode));
@@ -711,6 +839,7 @@ int reply_search(char *inbuf,char *outbuf)
   BOOL check_descend = False;
   BOOL expect_close = False;
   BOOL can_open = True;
+  BOOL bad_path = False;
 
   *mask = *directory = *fname = 0;
 
@@ -736,28 +865,34 @@ int reply_search(char *inbuf,char *outbuf)
     {
       pstring dir2;
 
-      strcpy(directory,smb_buf(inbuf)+1);
-      strcpy(dir2,smb_buf(inbuf)+1);
-      unix_convert(directory,cnum,0);
+      pstrcpy(directory,smb_buf(inbuf)+1);
+      pstrcpy(dir2,smb_buf(inbuf)+1);
+      unix_convert(directory,cnum,0,&bad_path);
       unix_format(dir2);
 
       if (!check_name(directory,cnum))
-       can_open = False;
+        can_open = False;
 
       p = strrchr(dir2,'/');
       if (p == NULL) 
-       {strcpy(mask,dir2);*dir2 = 0;}
+      {
+        strcpy(mask,dir2);
+        *dir2 = 0;
+      }
       else
-       {*p = 0;strcpy(mask,p+1);}
+      {
+        *p = 0;
+        pstrcpy(mask,p+1);
+      }
 
       p = strrchr(directory,'/');
       if (!p) 
-       *directory = 0;
+        *directory = 0;
       else
-       *p = 0;
+        *p = 0;
 
       if (strlen(directory) == 0)
-       strcpy(directory,"./");
+        strcpy(directory,"./");
       bzero(status,21);
       CVAL(status,0) = dirtype;
     }
@@ -781,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,".");
@@ -803,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);
@@ -821,7 +956,18 @@ int reply_search(char *inbuf,char *outbuf)
        {
          dptr_num = dptr_create(cnum,directory,expect_close,SVAL(inbuf,smb_pid));
          if (dptr_num < 0)
-           return(ERROR(ERRDOS,ERRnofids));
+        {
+          if(dptr_num == -2)
+          {
+            if((errno == ENOENT) && bad_path)
+            {
+              unix_ERR_class = ERRDOS;
+              unix_ERR_code = ERRbadpath;
+            }
+            return (UNIXERROR(ERRDOS,ERRnofids));
+          }
+          return(ERROR(ERRDOS,ERRnofids));
+        }
        }
 
       DEBUG(4,("dptr_num is %d\n",dptr_num));
@@ -966,29 +1112,49 @@ int reply_open(char *inbuf,char *outbuf)
   int unixmode;
   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);
-  unix_convert(fname,cnum,0);
+  pstrcpy(fname,smb_buf(inbuf)+1);
+  unix_convert(fname,cnum,0,&bad_path);
     
   fnum = find_free_file();
   if (fnum < 0)
     return(ERROR(ERRSRV,ERRnofids));
 
   if (!check_name(fname,cnum))
+  {
+    if((errno == ENOENT) && bad_path)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
     return(UNIXERROR(ERRDOS,ERRnoaccess));
-  
+  }
   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)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
     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));
   }
@@ -1010,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);
 }
 
@@ -1026,10 +1194,9 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   pstring fname;
   int cnum = SVAL(inbuf,smb_tid);
   int fnum = -1;
-  int openmode = 0;
   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); 
@@ -1040,6 +1207,8 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   int size=0,fmode=0,mtime=0,rmode=0;
   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))
@@ -1047,31 +1216,41 @@ 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));
-  unix_convert(fname,cnum,0);
+  pstrcpy(fname,smb_buf(inbuf));
+  unix_convert(fname,cnum,0,&bad_path);
     
-  /* now add create and trunc bits */
-  if (smb_ofun & 0x10)
-    openmode |= O_CREAT;
-  if ((smb_ofun & 0x3) == 2)
-    openmode |= O_TRUNC;
-  
   fnum = find_free_file();
   if (fnum < 0)
     return(ERROR(ERRSRV,ERRnofids));
 
   if (!check_name(fname,cnum))
+  {
+    if((errno == ENOENT) && bad_path)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
     return(UNIXERROR(ERRDOS,ERRnoaccess));
+  }
 
   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)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
     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));
   }
@@ -1085,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);
@@ -1146,13 +1331,16 @@ int reply_mknew(char *inbuf,char *outbuf)
   int createmode;
   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);
-  unix_convert(fname,cnum,0);
+  pstrcpy(fname,smb_buf(inbuf)+1);
+  unix_convert(fname,cnum,0,&bad_path);
 
   if (createmode & aVOLID)
     {
@@ -1166,7 +1354,14 @@ int reply_mknew(char *inbuf,char *outbuf)
     return(ERROR(ERRSRV,ERRnofids));
 
   if (!check_name(fname,cnum))
+  {
+    if((errno == ENOENT) && bad_path)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
     return(UNIXERROR(ERRDOS,ERRnoaccess));
+  }
 
   if(com == SMBmknew)
   {
@@ -1180,18 +1375,31 @@ 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) 
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
     return(UNIXERROR(ERRDOS,ERRnoaccess));
-  
+  }
   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));
   
@@ -1211,11 +1419,15 @@ int reply_ctemp(char *inbuf,char *outbuf)
   int outsize = 0;
   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);
-  unix_convert(fname,cnum,0);
+  pstrcpy(fname,smb_buf(inbuf)+1);
+  strcat(fname,"/TMXXXXXX");
+  unix_convert(fname,cnum,0,&bad_path);
   
   unixmode = unix_mode(cnum,createmode);
   
@@ -1224,26 +1436,46 @@ int reply_ctemp(char *inbuf,char *outbuf)
     return(ERROR(ERRSRV,ERRnofids));
 
   if (!check_name(fname,cnum))
+  {
+    if((errno == ENOENT) && bad_path)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
     return(UNIXERROR(ERRDOS,ERRnoaccess));
+  }
 
   strcpy(fname2,(char *)mktemp(fname));
 
   /* 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)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
     return(UNIXERROR(ERRDOS,ERRnoaccess));
+  }
 
   outsize = set_message(outbuf,1,2 + strlen(fname2),True);
   SSVAL(outbuf,smb_vwv0,fnum);
   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));
   
@@ -1289,17 +1521,18 @@ int reply_unlink(char *inbuf,char *outbuf)
   int error = ERRnoaccess;
   BOOL has_wild;
   BOOL exists=False;
+  BOOL bad_path = False;
 
   *directory = *mask = 0;
 
   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));
    
-  unix_convert(name,cnum,0);
+  unix_convert(name,cnum,0,&bad_path);
 
   p = strrchr(name,'/');
   if (!p) {
@@ -1326,7 +1559,7 @@ int reply_unlink(char *inbuf,char *outbuf)
     char *dname;
 
     if (check_name(directory,cnum))
-      dirptr = OpenDir(directory, True);
+      dirptr = OpenDir(cnum, directory, True);
 
     /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
        the pattern matches against the long name, otherwise the short name 
@@ -1343,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;
 
@@ -1361,7 +1594,14 @@ int reply_unlink(char *inbuf,char *outbuf)
     if (exists)
       return(ERROR(ERRDOS,error));
     else
+    {
+      if((errno == ENOENT) && bad_path)
+      {
+        unix_ERR_class = ERRDOS;
+        unix_ERR_code = ERRbadpath;
+      }
       return(UNIXERROR(ERRDOS,error));
+    }
   }
   
   outsize = set_message(outbuf,0,0,True);
@@ -1377,12 +1617,26 @@ int reply_readbraw(char *inbuf, char *outbuf)
 {
   int cnum,maxcount,mincount,fnum;
   int nread = 0;
-  int startpos;
+  uint32 startpos;
   char *header = outbuf;
   int ret=0;
   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);
 
@@ -1421,7 +1675,7 @@ int reply_readbraw(char *inbuf, char *outbuf)
          Files[fnum].size = size;
       }
 
-      nread = MIN(maxcount,size - startpos);     
+      nread = MIN(maxcount,(int)(size - startpos));      
     }
 
   if (nread < mincount)
@@ -1518,7 +1772,7 @@ int reply_read(char *inbuf,char *outbuf)
   int cnum,numtoread,fnum;
   int nread = 0;
   char *data;
-  int startpos;
+  uint32 startpos;
   int outsize = 0;
   
   cnum = SVAL(inbuf,smb_tid);
@@ -2214,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)
       {
@@ -2238,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));
@@ -2349,7 +2604,7 @@ int reply_printqueue(char *inbuf,char *outbuf)
       {
        put_dos_date2(p,0,queue[i].time);
        CVAL(p,4) = (queue[i].status==LPQ_PRINTING?2:3);
-       SSVAL(p,5,queue[i].job);
+       SSVAL(p,5,printjob_encode(SNUM(cnum), queue[i].job));
        SIVAL(p,7,queue[i].size);
        CVAL(p,11) = 0;
        StrnCpy(p+12,queue[i].user,16);
@@ -2414,17 +2669,25 @@ int reply_mkdir(char *inbuf,char *outbuf)
   pstring directory;
   int cnum;
   int outsize,ret= -1;
-  
-  strcpy(directory,smb_buf(inbuf) + 1);
+  BOOL bad_path = False;
+  pstrcpy(directory,smb_buf(inbuf) + 1);
   cnum = SVAL(inbuf,smb_tid);
-  unix_convert(directory,cnum,0);
+  unix_convert(directory,cnum,0,&bad_path);
   
   if (check_name(directory,cnum))
     ret = sys_mkdir(directory,unix_mode(cnum,aDIR));
   
   if (ret < 0)
+  {
+    if((errno == ENOENT) && bad_path)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
     return(UNIXERROR(ERRDOS,ERRnoaccess));
-  
+  }
   outsize = set_message(outbuf,0,0,True);
   
   DEBUG(3,("%s mkdir %s cnum=%d ret=%d\n",timestring(),directory,cnum,ret));
@@ -2432,6 +2695,66 @@ int reply_mkdir(char *inbuf,char *outbuf)
   return(outsize);
 }
 
+/****************************************************************************
+Static function used by reply_rmdir to delete an entire directory
+tree recursively.
+****************************************************************************/
+static BOOL recursive_rmdir(char *directory)
+{
+  char *dname = NULL;
+  BOOL ret = False;
+  void *dirptr = OpenDir(-1, directory, False);
+
+  if(dirptr == NULL)
+    return True;
+
+  while((dname = ReadDirName(dirptr)))
+  {
+    pstring fullname;
+    struct stat st;
+
+    if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
+      continue;
+
+    /* Construct the full name. */
+    if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname))
+    {
+      errno = ENOMEM;
+      ret = True;
+      break;
+    }
+    strcpy(fullname, directory);
+    strcat(fullname, "/");
+    strcat(fullname, dname);
+
+    if(sys_lstat(fullname, &st) != 0)
+    {
+      ret = True;
+      break;
+    }
+
+    if(st.st_mode & S_IFDIR)
+    {
+      if(recursive_rmdir(fullname)!=0)
+      {
+        ret = True;
+        break;
+      }
+      if(sys_rmdir(fullname) != 0)
+      {
+        ret = True;
+        break;
+      }
+    }
+    else if(sys_unlink(fullname) != 0)
+    {
+      ret = True;
+      break;
+    }
+  }
+  CloseDir(dirptr);
+  return ret;
+}
 
 /****************************************************************************
   reply to a rmdir
@@ -2442,17 +2765,18 @@ int reply_rmdir(char *inbuf,char *outbuf)
   int cnum;
   int outsize = 0;
   BOOL ok = False;
-  
+  BOOL bad_path = False;
+
   cnum = SVAL(inbuf,smb_tid);
-  strcpy(directory,smb_buf(inbuf) + 1);
-  unix_convert(directory,cnum,0);
+  pstrcpy(directory,smb_buf(inbuf) + 1);
+  unix_convert(directory,cnum,0,&bad_path);
   
   if (check_name(directory,cnum))
     {
 
       dptr_closepath(directory,SVAL(inbuf,smb_pid));
       ok = (sys_rmdir(directory) == 0);
-      if(!ok && (errno == ENOTEMPTY) && lp_veto_files())
+      if(!ok && (errno == ENOTEMPTY) && lp_veto_files(SNUM(cnum)))
         {
           /* Check to see if the only thing in this directory are
              vetoed files/directories. If so then delete them and
@@ -2460,7 +2784,7 @@ int reply_rmdir(char *inbuf,char *outbuf)
              do a recursive delete) then fail the rmdir. */
           BOOL all_veto_files = True;
           char *dname;
-          void *dirptr = OpenDir(directory, False);
+          void *dirptr = OpenDir(cnum, directory, False);
 
           if(dirptr != NULL)
             {
@@ -2469,7 +2793,7 @@ int reply_rmdir(char *inbuf,char *outbuf)
                    {
                   if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
                     continue;
-                  if(!is_vetoed_name(dname))
+                  if(!IS_VETO_PATH(cnum, dname))
                     {
                       all_veto_files = False;
                       break;
@@ -2492,17 +2816,22 @@ int reply_rmdir(char *inbuf,char *outbuf)
                           errno = ENOMEM;
                           break;
                         }
-                      strcpy(fullname, directory);
+                      pstrcpy(fullname, directory);
                       strcat(fullname, "/");
                       strcat(fullname, dname);
                       
                       if(sys_lstat(fullname, &st) != 0)
                         break;
                       if(st.st_mode & S_IFDIR)
+                      {
+                        if(lp_recursive_veto_delete(SNUM(cnum)))
                         {
-                          if(sys_rmdir(fullname) != 0)
+                          if(recursive_rmdir(fullname) != 0)
                             break;
                         }
+                        if(sys_rmdir(fullname) != 0)
+                          break;
+                      }
                       else if(sys_unlink(fullname) != 0)
                         break;
                     }
@@ -2523,8 +2852,15 @@ int reply_rmdir(char *inbuf,char *outbuf)
     }
   
   if (!ok)
+  {
+    if((errno == ENOENT) && bad_path)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
     return(UNIXERROR(ERRDOS,ERRbadpath));
-  
+  }
   outsize = set_message(outbuf,0,0,True);
   
   DEBUG(3,("%s rmdir %s\n",timestring(),directory));
@@ -2547,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;
@@ -2628,18 +2964,20 @@ int reply_mv(char *inbuf,char *outbuf)
   int error = ERRnoaccess;
   BOOL has_wild;
   BOOL exists=False;
+  BOOL bad_path1 = False;
+  BOOL bad_path2 = False;
 
   *directory = *mask = 0;
 
   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));
    
-  unix_convert(name,cnum,0);
-  unix_convert(newname,cnum,newname_last_component);
+  unix_convert(name,cnum,0,&bad_path1);
+  unix_convert(newname,cnum,newname_last_component,&bad_path2);
 
   /*
    * Split the old name into directory and last component
@@ -2736,7 +3074,7 @@ int reply_mv(char *inbuf,char *outbuf)
     pstring destname;
 
     if (check_name(directory,cnum))
-      dirptr = OpenDir(directory, True);
+      dirptr = OpenDir(cnum, directory, True);
 
     if (dirptr)
       {
@@ -2748,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;
 
@@ -2774,7 +3112,14 @@ int reply_mv(char *inbuf,char *outbuf)
     if (exists)
       return(ERROR(ERRDOS,error));
     else
+    {
+      if((errno == ENOENT) && (bad_path1 || bad_path2))
+      {
+        unix_ERR_class = ERRDOS;
+        unix_ERR_code = ERRbadpath;
+      }
       return(UNIXERROR(ERRDOS,error));
+    }
   }
   
   outsize = set_message(outbuf,0,0,True);
@@ -2794,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) 
@@ -2810,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);
 
@@ -2823,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);
@@ -2864,13 +3209,15 @@ int reply_copy(char *inbuf,char *outbuf)
   int ofun = SVAL(inbuf,smb_vwv1);
   int flags = SVAL(inbuf,smb_vwv2);
   BOOL target_is_directory=False;
+  BOOL bad_path1 = False;
+  BOOL bad_path2 = False;
 
   *directory = *mask = 0;
 
   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));
    
@@ -2880,8 +3227,8 @@ int reply_copy(char *inbuf,char *outbuf)
     return(ERROR(ERRSRV,ERRinvdevice));
   }
 
-  unix_convert(name,cnum,0);
-  unix_convert(newname,cnum,0);
+  unix_convert(name,cnum,0,&bad_path1);
+  unix_convert(newname,cnum,0,&bad_path2);
 
   target_is_directory = directory_exist(newname,NULL);
 
@@ -2927,7 +3274,7 @@ int reply_copy(char *inbuf,char *outbuf)
     pstring destname;
 
     if (check_name(directory,cnum))
-      dirptr = OpenDir(directory, True);
+      dirptr = OpenDir(cnum, directory, True);
 
     if (dirptr)
       {
@@ -2939,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;
 
@@ -2959,7 +3306,14 @@ int reply_copy(char *inbuf,char *outbuf)
     if (exists)
       return(ERROR(ERRDOS,error));
     else
+    {
+      if((errno == ENOENT) && (bad_path1 || bad_path2))
+      {
+        unix_ERR_class = ERRDOS;
+        unix_ERR_code = ERRbadpath;
+      }
       return(UNIXERROR(ERRDOS,error));
+    }
   }
   
   outsize = set_message(outbuf,1,0,True);
@@ -2986,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)
@@ -3016,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;
@@ -3033,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++) {
@@ -3067,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;
 
@@ -3084,7 +3483,7 @@ int reply_readbmpx(char *inbuf,char *outbuf,int length,int bufsize)
   int nread = -1;
   int total_read;
   char *data;
-  int32 startpos;
+  uint32 startpos;
   int outsize, mincount, maxcount;
   int max_per_packet;
   int tcount;
@@ -3108,7 +3507,7 @@ int reply_readbmpx(char *inbuf,char *outbuf,int length,int bufsize)
   mincount = SVAL(inbuf,smb_vwv4);
 
   data = smb_buf(outbuf);
-  pad = ((int)data)%4;
+  pad = ((long)data)%4;
   if (pad) pad = 4 - pad;
   data += pad;
 
@@ -3155,7 +3554,7 @@ int reply_writebmpx(char *inbuf,char *outbuf)
   int cnum,numtowrite,fnum;
   int nwritten = -1;
   int outsize = 0;
-  int32 startpos;
+  uint32 startpos;
   int tcount, write_through, smb_doff;
   char *data;
   
@@ -3344,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);
 }
@@ -3400,8 +3819,3 @@ int reply_getattrE(char *inbuf,char *outbuf)
   
   return(outsize);
 }
-
-
-
-
-