use FSTYPE_STRING not "SAMBA" for filesystem type
[samba.git] / source / smbd / reply.c
index 5dbd39f746395b05d471d583a0235b2b40346826..83a4293fad427d028c96bd355ed9a0dd31ad78ad 100644 (file)
@@ -2,7 +2,7 @@
    Unix SMB/Netbios implementation.
    Version 1.9.
    Main SMB reply routines
-   Copyright (C) Andrew Tridgell 1992-1995
+   Copyright (C) Andrew Tridgell 1992-1998
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
 #include "includes.h"
 #include "trans2.h"
+#include "nterr.h"
 
 /* look in server.c for some explanation of these variables */
 extern int Protocol;
 extern int DEBUGLEVEL;
-extern int maxxmit;
+extern int max_send;
+extern int max_recv;
 extern int chain_fnum;
 extern char magic_char;
 extern connection_struct Connections[];
@@ -39,7 +41,9 @@ extern BOOL case_sensitive;
 extern BOOL case_preserve;
 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 */
@@ -47,62 +51,98 @@ 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;
+       DEBUG(0,("%s: ERROR: Invalid password length %d\n", timestring(), 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");
+}
 
-  *name1 = *name2 = 0;
 
-  smb_setlen(outbuf,0);
+/****************************************************************************
+  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;
+       int len;
+       char name_type = 0;
+       
+       *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 || 
+                   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));      
+
+               fstrcpy(remote_machine,name2);
+               remote_machine[15] = 0;
+               trim_string(remote_machine," "," ");
+               strlower(remote_machine);
+
+               fstrcpy(local_machine,name1);
+               len = strlen(local_machine);
+               if (len == 16) {
+                       name_type = local_machine[15];
+                       local_machine[15] = 0;
+               }
+               trim_string(local_machine," "," ");
+               strlower(local_machine);
+
+               if (name_type == 'R') {
+                       /* We are being asked for a pathworks session --- 
+                          no thanks! */
+                       CVAL(outbuf, 0) = 0x83;
+                       break;
+               }
 
-  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);
+               add_session_user(remote_machine);
+
+               reload_services(True);
+               reopen_logs();
+
+               break;
+               
+       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);
        }
-      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));      
-
-      strcpy(remote_machine,name2);
-      trim_string(remote_machine," "," ");
-      p = strchr(remote_machine,' ');
-      strlower(remote_machine);
-      if (p) *p = 0;
-
-      strcpy(local_machine,name1);
-      trim_string(local_machine," "," ");
-      p = strchr(local_machine,' ');
-      strlower(local_machine);
-      if (p) *p = 0;
-
-      add_session_user(remote_machine);
-
-      reload_services(True);
-      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);
+       
+       DEBUG(5,("%s init msg_type=0x%x msg_flags=0x%x\n",
+                timestring(),msg_type,msg_flags));
+       
+       return(outsize);
 }
 
 
@@ -145,25 +185,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);
     }
 }
 
@@ -194,7 +234,7 @@ int reply_tcon(char *inbuf,char *outbuf)
     return(connection_error(inbuf,outbuf,connection_num));
   
   outsize = set_message(outbuf,2,0,True);
-  SSVAL(outbuf,smb_vwv0,maxxmit);
+  SSVAL(outbuf,smb_vwv0,max_recv);
   SSVAL(outbuf,smb_vwv1,connection_num);
   SSVAL(outbuf,smb_tid,connection_num);
   
@@ -216,13 +256,16 @@ int reply_tcon_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   int connection_num;
   uint16 vuid = SVAL(inbuf,smb_uid);
   int passlen = SVAL(inbuf,smb_vwv3);
-  BOOL doencrypt = SMBENCRYPT();
 
   *service = *user = *password = *devicename = 0;
 
   /* 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;
@@ -231,24 +274,23 @@ int reply_tcon_and_X(char *inbuf,char *outbuf,int length,int bufsize)
     password[passlen]=0;    
     path = smb_buf(inbuf) + passlen;
 
-    if (!doencrypt || passlen != 24) {
+    if (passlen != 24) {
       if (strequal(password," "))
        *password = 0;
       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));
@@ -259,7 +301,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 = FSTYPE_STRING;
+    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));
   
@@ -267,8 +328,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);
 }
 
@@ -307,6 +366,74 @@ int reply_ioctl(char *inbuf,char *outbuf)
 #endif
 }
 
+/****************************************************************************
+ always return an error: it's just a matter of which one...
+ ****************************************************************************/
+static int session_trust_account(char *inbuf, char *outbuf, char *user,
+                                char *smb_passwd, int smb_passlen,
+                                char *smb_nt_passwd, int smb_nt_passlen)
+{
+        struct smb_passwd *smb_trust_acct = NULL; /* check if trust account exists */
+        if (lp_security() == SEC_USER)
+        {
+                smb_trust_acct = get_smbpwd_entry(user, 0);
+        }
+        else
+        {
+                DEBUG(3,("Trust account %s only supported with security = user\n", user));
+                SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+                return(ERROR(0, 0xc0000000|NT_STATUS_LOGON_FAILURE));
+        }
+
+        if (smb_trust_acct == NULL)
+        {
+                /* lkclXXXX: workstation entry doesn't exist */
+                DEBUG(4,("Trust account %s user doesn't exist\n",user));
+                SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+                return(ERROR(0, 0xc0000000|NT_STATUS_NO_SUCH_USER));
+        }
+        else
+        {
+                if ((smb_passlen != 24) || (smb_nt_passlen != 24))
+                {
+                        DEBUG(4,("Trust account %s - password length wrong.\n", user));
+                        SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+                        return(ERROR(0, 0xc0000000|NT_STATUS_LOGON_FAILURE));
+                }
+
+                if (!smb_password_ok(smb_trust_acct, smb_passwd, smb_nt_passwd))
+                {
+                        DEBUG(4,("Trust Account %s - password failed\n", user));
+                        SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+                        return(ERROR(0, 0xc0000000|NT_STATUS_LOGON_FAILURE));
+                }
+
+                if (IS_BITS_SET_ALL(smb_trust_acct->acct_ctrl, ACB_DOMTRUST))
+                {
+                        DEBUG(4,("Domain trust account %s denied by server\n",user));
+                        SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+                        return(ERROR(0, 0xc0000000|NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT));
+                }
+
+                if (IS_BITS_SET_ALL(smb_trust_acct->acct_ctrl, ACB_SVRTRUST))
+                {
+                        DEBUG(4,("Server trust account %s denied by server\n",user));
+                        SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+                        return(ERROR(0, 0xc0000000|NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT));
+                }
+                if (IS_BITS_SET_ALL(smb_trust_acct->acct_ctrl, ACB_WSTRUST))
+                {
+                        DEBUG(4,("Wksta trust account %s denied by server\n", user));
+                        SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+                        return(ERROR(0, 0xc0000000|NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT));
+                }
+        }
+
+        /* don't know what to do: indicate logon failure */
+        SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+        return(ERROR(0, 0xc0000000|NT_STATUS_LOGON_FAILURE));
+}
+
 
 /****************************************************************************
 reply to a session setup command
@@ -327,11 +454,12 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   BOOL valid_nt_password = False;
   pstring user;
   BOOL guest=False;
-  BOOL computer_id=False;
   static BOOL done_sesssetup = False;
   BOOL doencrypt = SMBENCRYPT();
+  char *domain = "";
 
   *smb_apasswd = 0;
+  *smb_ntpasswd = 0;
   
   smb_bufsize = SVAL(inbuf,smb_vwv2);
   smb_mpxmax = SVAL(inbuf,smb_vwv3);
@@ -340,25 +468,57 @@ 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);
+    smb_apasswd[smb_apasslen] = 0;
+    pstrcpy(user,smb_buf(inbuf)+smb_apasslen);
 
-    if (lp_security() != SEC_SERVER && !doencrypt)
-      smb_apasslen = strlen(smb_apasswd);
+    if (!doencrypt && (lp_security() != SEC_SERVER)) {
+           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(doencrypt) {
+    if (passlen1 > MAX_PASS_LEN) {
+           overflow_attack(passlen1);
+    }
+
+    passlen1 = MIN(passlen1, MAX_PASS_LEN);
+    passlen2 = MIN(passlen2, MAX_PASS_LEN);
+
+    if(doencrypt || (lp_security() == SEC_SERVER)) {
       /* Save the lanman2 password and the NT md4 password. */
       smb_apasslen = passlen1;
       memcpy(smb_apasswd,p,smb_apasslen);
+      smb_apasswd[smb_apasslen] = 0;
       smb_ntpasslen = passlen2;
       memcpy(smb_ntpasswd,p+passlen1,smb_ntpasslen);
+      smb_ntpasswd[smb_ntpasslen] = 0;
     } else {
       /* both Win95 and WinNT stuff up the password lengths for
         non-encrypting systems. Uggh. 
@@ -390,9 +550,11 @@ 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);
+    domain = p;
+
     DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s]\n",
-            p,skip_string(p,1),skip_string(p,2)));
+            domain,skip_string(p,1),skip_string(p,2)));
   }
 
 
@@ -401,14 +563,21 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   /* If name ends in $ then I think it's asking about whether a */
   /* computer with that name (minus the $) has access. For now */
   /* say yes to everything ending in $. */
-  if (user[strlen(user) - 1] == '$') {
-    computer_id = True;
-    user[strlen(user) - 1] = '\0';
+  if ((user[strlen(user) - 1] == '$') && (smb_apasslen == 24) && (smb_ntpasslen == 24))
+  {
+    return session_trust_account(inbuf, outbuf, user, 
+                                 smb_apasswd, smb_apasslen,
+                                 smb_ntpasswd, smb_ntpasslen);
   }
 
-
+  /* 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);
 
@@ -418,27 +587,35 @@ 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(!guest && strequal(user,lp_guestaccount(-1)) && (*smb_apasswd == 0))
+    guest = True;
 
-  if (!(lp_security() == SEC_SERVER && server_validate(inbuf)) &&
+  if (!guest && !(lp_security() == SEC_SERVER && 
+                 server_validate(user, domain, 
+                                 smb_apasswd, smb_apasslen, 
+                                 smb_ntpasswd, smb_ntpasslen)) &&
       !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 (lp_security() >= SEC_USER) {
 #if (GUEST_SESSSETUP == 0)
            return(ERROR(ERRSRV,ERRbadpw));
 #endif
@@ -479,7 +656,7 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
     p = smb_buf(outbuf);
     strcpy(p,"Unix"); p = skip_string(p,1);
     strcpy(p,"Samba "); strcat(p,VERSION); p = skip_string(p,1);
-    strcpy(p,lp_workgroup()); p = skip_string(p,1);
+    strcpy(p,myworkgroup); p = skip_string(p,1);
     set_message(outbuf,3,PTR_DIFF(p,smb_buf(outbuf)),False);
     /* perhaps grab OS version here?? */
   }
@@ -498,7 +675,7 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
     uid = pw->pw_uid;
   }
 
-  if (guest && !computer_id)
+  if (guest)
     SSVAL(outbuf,smb_vwv2,1);
 
   /* register the name and uid as being validated, so further connections
@@ -509,7 +686,9 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   SSVAL(inbuf,smb_uid,sess_vuid);
 
   if (!done_sesssetup)
-    maxxmit = MIN(maxxmit,smb_bufsize);
+    max_send = MIN(max_send,smb_bufsize);
+
+  DEBUG(6,("Client requested max send size of %d\n", max_send));
 
   done_sesssetup = True;
 
@@ -526,11 +705,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);
 
@@ -538,8 +718,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));
@@ -561,11 +764,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! */
@@ -579,27 +783,38 @@ 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);
-  put_dos_date3(outbuf,smb_vwv1,mtime);
+  if(lp_dos_filetime_resolution(SNUM(cnum)) )
+    put_dos_date3(outbuf,smb_vwv1,mtime & ~1);
+  else
+    put_dos_date3(outbuf,smb_vwv1,mtime);
   SIVAL(outbuf,smb_vwv3,size);
 
   if (Protocol >= PROTOCOL_NT1) {
@@ -627,11 +842,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);
@@ -641,11 +857,19 @@ int reply_setatr(char *inbuf,char *outbuf)
   if (check_name(fname,cnum))
     ok =  (dos_chmod(cnum,fname,mode,NULL) == 0);
   if (ok)
-    ok = set_filetime(fname,mtime);
+    ok = set_filetime(cnum,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));
@@ -707,6 +931,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;
 
@@ -732,28 +957,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;
     }
@@ -777,7 +1008,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,".");
@@ -799,7 +1030,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);
@@ -817,7 +1048,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));
@@ -962,30 +1204,52 @@ 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;
+    }
+    Files[fnum].reserved = False;
     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);
+
+  fsp = &Files[fnum];
 
-  if (!Files[fnum].open)
+  if (!fsp->open)
+  {
+    if((errno == ENOENT) && bad_path)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
+    Files[fnum].reserved = False;
     return(UNIXERROR(ERRDOS,ERRnoaccess));
+  }
 
-  if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) {
-    close_file(fnum);
+  if (fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
+    close_file(fnum,False);
     return(ERROR(ERRDOS,ERRnoaccess));
   }
     
@@ -995,21 +1259,26 @@ int reply_open(char *inbuf,char *outbuf)
 
   if (fmode & aDIR) {
     DEBUG(3,("attempt to open a directory %s\n",fname));
-    close_file(fnum);
+    close_file(fnum,False);
     return(ERROR(ERRDOS,ERRnoaccess));
   }
   
   outsize = set_message(outbuf,7,0,True);
   SSVAL(outbuf,smb_vwv0,fnum);
   SSVAL(outbuf,smb_vwv1,fmode);
-  put_dos_date3(outbuf,smb_vwv2,mtime);
+  if(lp_dos_filetime_resolution(SNUM(cnum)) )
+    put_dos_date3(outbuf,smb_vwv2,mtime & ~1);
+  else
+    put_dos_date3(outbuf,smb_vwv2,mtime);
   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);
 }
 
@@ -1022,10 +1291,13 @@ 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);
+  /* Breakout the oplock request bits so we can set the
+     reply bits separately. */
+  BOOL ex_oplock_request = EXTENDED_OPLOCK_REQUEST(inbuf);
+  BOOL core_oplock_request = CORE_OPLOCK_REQUEST(inbuf);
+  BOOL oplock_request = ex_oplock_request | core_oplock_request;
 #if 0
   int open_flags = SVAL(inbuf,smb_vwv2);
   int smb_sattr = SVAL(inbuf,smb_vwv4); 
@@ -1036,6 +1308,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))
@@ -1043,32 +1317,44 @@ 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;
+    }
+    Files[fnum].reserved = False;
     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;
+    }
+    Files[fnum].reserved = False;
     return(UNIXERROR(ERRDOS,ERRnoaccess));
+  }
 
-  if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) {
-    close_file(fnum);
+  if (fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
+    close_file(fnum,False);
     return(ERROR(ERRDOS,ERRnoaccess));
   }
 
@@ -1076,18 +1362,43 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   fmode = dos_mode(cnum,fname,&sbuf);
   mtime = sbuf.st_mtime;
   if (fmode & aDIR) {
-    close_file(fnum);
+    close_file(fnum,False);
     return(ERROR(ERRDOS,ERRnoaccess));
   }
 
-  if (oplock_request && lp_fake_oplocks(SNUM(cnum))) {
-    smb_action |= (1<<15);
+  /* If the caller set the extended oplock request bit
+     and we granted one (by whatever means) - set the
+     correct bit for extended oplock reply.
+   */
+
+  if (ex_oplock_request && lp_fake_oplocks(SNUM(cnum))) {
+    smb_action |= EXTENDED_OPLOCK_GRANTED;
+  }
+
+  if(ex_oplock_request && fsp->granted_oplock) {
+    smb_action |= EXTENDED_OPLOCK_GRANTED;
+  }
+
+  /* If the caller set the core oplock request bit
+     and we granted one (by whatever means) - set the
+     correct bit for core oplock reply.
+   */
+
+  if (core_oplock_request && lp_fake_oplocks(SNUM(cnum))) {
+    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+  }
+
+  if(core_oplock_request && fsp->granted_oplock) {
+    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
   }
 
   set_message(outbuf,15,0,True);
   SSVAL(outbuf,smb_vwv2,fnum);
   SSVAL(outbuf,smb_vwv3,fmode);
-  put_dos_date3(outbuf,smb_vwv4,mtime);
+  if(lp_dos_filetime_resolution(SNUM(cnum)) )
+    put_dos_date3(outbuf,smb_vwv4,mtime & ~1);
+  else
+    put_dos_date3(outbuf,smb_vwv4,mtime);
   SIVAL(outbuf,smb_vwv6,size);
   SSVAL(outbuf,smb_vwv8,rmode);
   SSVAL(outbuf,smb_vwv11,smb_action);
@@ -1115,8 +1426,8 @@ int reply_ulogoffX(char *inbuf,char *outbuf,int length,int bufsize)
   if ((vuser != 0) && (lp_security() != SEC_SHARE)) {
     int i;
     for (i=0;i<MAX_OPEN_FILES;i++)
-      if (Files[i].uid == vuser->uid && Files[i].open) {
-       close_file(i);
+      if ((Files[i].vuid == vuid) && Files[i].open) {
+       close_file(i,False);
       }
   }
 
@@ -1131,7 +1442,7 @@ int reply_ulogoffX(char *inbuf,char *outbuf,int length,int bufsize)
 
 
 /****************************************************************************
-  reply to a mknew
+  reply to a mknew or a create
 ****************************************************************************/
 int reply_mknew(char *inbuf,char *outbuf)
 {
@@ -1141,13 +1452,17 @@ int reply_mknew(char *inbuf,char *outbuf)
   int outsize = 0;
   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)
     {
@@ -1156,28 +1471,59 @@ int reply_mknew(char *inbuf,char *outbuf)
   
   unixmode = unix_mode(cnum,createmode);
   
-  if (com == SMBmknew && file_exist(fname,NULL))
-    return(ERROR(ERRDOS,ERRfilexists));
-    
   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;
+    }
+    Files[fnum].reserved = False;
     return(UNIXERROR(ERRDOS,ERRnoaccess));
+  }
+
+  if(com == SMBmknew)
+  {
+    /* We should fail if file exists. */
+    ofun = 0x10;
+  }
+  else
+  {
+    /* SMBcreate - Create if file doesn't exist, truncate if it does. */
+    ofun = 0x12;
+  }
 
-  open_file(fnum,cnum,fname,O_RDWR | O_CREAT | O_TRUNC,unixmode, 0);
+  /* Open file in dos compatibility share mode. */
+  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;
+    }
+    Files[fnum].reserved = False;
     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));
   
@@ -1197,11 +1543,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);
   
@@ -1210,24 +1560,48 @@ 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;
+    }
+    Files[fnum].reserved = False;
     return(UNIXERROR(ERRDOS,ERRnoaccess));
+  }
 
   strcpy(fname2,(char *)mktemp(fname));
 
-  open_file(fnum,cnum,fname2,O_RDWR | O_CREAT | O_TRUNC,unixmode, 0);
+  /* 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, 
+                   oplock_request, NULL, NULL);
+
+  fsp = &Files[fnum];
 
-  if (!Files[fnum].open)
+  if (!fsp->open)
+  {
+    if((errno == ENOENT) && bad_path)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
+    Files[fnum].reserved = False;
     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));
   
@@ -1253,7 +1627,7 @@ static BOOL can_delete(char *fname,int cnum,int dirtype)
   }
   if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM))
     return(False);
-  if (!check_file_sharing(cnum,fname)) return(False);
+  if (!check_file_sharing(cnum,fname,False)) return(False);
   return(True);
 }
 
@@ -1273,17 +1647,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) {
@@ -1310,7 +1685,7 @@ int reply_unlink(char *inbuf,char *outbuf)
     char *dname;
 
     if (check_name(directory,cnum))
-      dirptr = OpenDir(directory);
+      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 
@@ -1327,7 +1702,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;
 
@@ -1345,7 +1720,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);
@@ -1361,12 +1743,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);
 
@@ -1405,7 +1801,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)
@@ -1421,8 +1817,10 @@ int reply_readbraw(char *inbuf, char *outbuf)
     int predict=0;
     _smb_setlen(header,nread);
 
+#if USE_READ_PREDICTION
     if (!Files[fnum].can_write)
       predict = read_predict(fd,startpos,header+4,NULL,nread);
+#endif
 
     if ((nread-predict) > 0)
       seek_file(fnum,startpos + predict);
@@ -1502,7 +1900,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);
@@ -1556,6 +1954,10 @@ int reply_read_and_X(char *inbuf,char *outbuf,int length,int bufsize)
 
   cnum = SVAL(inbuf,smb_tid);
 
+  /* If it's an IPC, pass off the pipe handler. */
+  if (IS_IPC(cnum))
+    return reply_pipe_read_and_X(inbuf,outbuf,length,bufsize);
+
   CHECK_FNUM(fnum,cnum);
   CHECK_READ(fnum);
   CHECK_ERROR(fnum);
@@ -1965,7 +2367,12 @@ int reply_close(char *inbuf,char *outbuf)
 
   cnum = SVAL(inbuf,smb_tid);
 
+  /* If it's an IPC, pass off to the pipe handler. */
+  if (IS_IPC(cnum))
+    return reply_pipe_close(inbuf,outbuf);
+
   fnum = GETFNUM(inbuf,smb_vwv0);
+
   CHECK_FNUM(fnum,cnum);
 
   if(HAS_CACHED_ERROR(fnum)) {
@@ -1976,9 +2383,9 @@ int reply_close(char *inbuf,char *outbuf)
   mtime = make_unix_date3(inbuf+smb_vwv1);
 
   /* try and set the date */
-  set_filetime(Files[fnum].name,mtime);
+  set_filetime(cnum, Files[fnum].name,mtime);
 
-  close_file(fnum);
+  close_file(fnum,True);
 
   /* We have a cached error */
   if(eclass || err)
@@ -2023,9 +2430,9 @@ int reply_writeclose(char *inbuf,char *outbuf)
       
   nwritten = write_file(fnum,data,numtowrite);
 
-  set_filetime(Files[fnum].name,mtime);
+  set_filetime(cnum, Files[fnum].name,mtime);
   
-  close_file(fnum);
+  close_file(fnum,True);
 
   DEBUG(3,("%s writeclose fnum=%d cnum=%d num=%d wrote=%d (numopen=%d)\n",
           timestring(),fnum,cnum,numtowrite,nwritten,
@@ -2140,11 +2547,17 @@ int reply_echo(char *inbuf,char *outbuf)
 
   cnum = SVAL(inbuf,smb_tid);
 
+  /* According to the latest CIFS spec we shouldn't
+     care what the TID is.
+   */
+
+#if 0
   if (cnum != 0xFFFF && !OPEN_CNUM(cnum))
     {
       DEBUG(4,("Invalid cnum in echo (%d)\n",cnum));
       return(ERROR(ERRSRV,ERRinvnid));
     }
+#endif
 
   /* copy any incoming data back out */
   if (data_len > 0)
@@ -2192,7 +2605,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)
       {
@@ -2212,14 +2625,19 @@ int reply_printopen(char *inbuf,char *outbuf)
 
   strcpy(fname2,(char *)mktemp(fname));
 
-  if (!check_name(fname2,cnum))
-    return(ERROR(ERRDOS,ERRnoaccess));
+  if (!check_name(fname2,cnum)) {
+         Files[fnum].reserved = False;
+         return(ERROR(ERRDOS,ERRnoaccess));
+  }
 
-  open_file(fnum,cnum,fname2,O_WRONLY | O_CREAT | O_TRUNC,
-           unix_mode(cnum,0), 0);
+  /* Open for exclusive use, write only. */
+  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));
+  if (!Files[fnum].open) {
+         Files[fnum].reserved = False;
+         return(UNIXERROR(ERRDOS,ERRnoaccess));
+  }
 
   /* force it to be a print file */
   Files[fnum].print_file = True;
@@ -2250,7 +2668,7 @@ int reply_printclose(char *inbuf,char *outbuf)
   if (!CAN_PRINT(cnum))
     return(ERROR(ERRDOS,ERRnoaccess));
   
-  close_file(fnum);
+  close_file(fnum,True);
   
   DEBUG(3,("%s printclose fd=%d fnum=%d cnum=%d\n",timestring(),Files[fnum].fd_ptr->fd,fnum,cnum));
   
@@ -2306,7 +2724,7 @@ int reply_printqueue(char *inbuf,char *outbuf)
       DEBUG(5,("connection not open or not a printer, using cnum %d\n",cnum));
     }
 
-  if (!become_user(cnum,vuid))
+  if (!become_user(&Connections[cnum], cnum, vuid))
     return(ERROR(ERRSRV,ERRinvnid));
 
   {
@@ -2327,7 +2745,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);
@@ -2392,17 +2810,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));
@@ -2410,6 +2836,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
@@ -2420,23 +2906,102 @@ 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(SNUM(cnum)))
+        {
+          /* Check to see if the only thing in this directory are
+             vetoed files/directories. If so then delete them and
+             retry. If we fail to delete any of them (and we *don't*
+             do a recursive delete) then fail the rmdir. */
+          BOOL all_veto_files = True;
+          char *dname;
+          void *dirptr = OpenDir(cnum, directory, False);
+
+          if(dirptr != NULL)
+            {
+              int dirpos = TellDir(dirptr);
+                 while ((dname = ReadDirName(dirptr)))
+                   {
+                  if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
+                    continue;
+                  if(!IS_VETO_PATH(cnum, dname))
+                    {
+                      all_veto_files = False;
+                      break;
+                    }
+                }
+              if(all_veto_files)
+                {
+                  SeekDir(dirptr,dirpos);
+                  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;
+                          break;
+                        }
+                      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(recursive_rmdir(fullname) != 0)
+                            break;
+                        }
+                        if(sys_rmdir(fullname) != 0)
+                          break;
+                      }
+                      else if(sys_unlink(fullname) != 0)
+                        break;
+                    }
+                  CloseDir(dirptr);
+                  /* Retry the rmdir */
+                  ok = (sys_rmdir(directory) == 0);
+                }
+              else
+                CloseDir(dirptr);
+            }
+          else
+            errno = ENOTEMPTY;
+         }
+          
       if (!ok)
-       DEBUG(3,("couldn't remove directory %s : %s\n",
+        DEBUG(3,("couldn't remove directory %s : %s\n",
                 directory,strerror(errno)));
     }
   
   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));
@@ -2459,21 +3024,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;
@@ -2519,7 +3084,7 @@ static BOOL can_rename(char *fname,int cnum)
   if (!CAN_WRITE(cnum)) return(False);
 
   if (sys_lstat(fname,&sbuf) != 0) return(False);
-  if (!check_file_sharing(cnum,fname)) return(False);
+  if (!check_file_sharing(cnum,fname,True)) return(False);
 
   return(True);
 }
@@ -2540,18 +3105,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
@@ -2648,7 +3215,7 @@ int reply_mv(char *inbuf,char *outbuf)
     pstring destname;
 
     if (check_name(directory,cnum))
-      dirptr = OpenDir(directory);
+      dirptr = OpenDir(cnum, directory, True);
 
     if (dirptr)
       {
@@ -2660,20 +3227,29 @@ 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);
+           if (!can_rename(fname,cnum)) {
+                   DEBUG(6,("rename %s refused\n", fname));
+                   continue;
+           }
+           pstrcpy(destname,newname);
 
-           if (!resolve_wildcards(fname,destname)) continue;
+           if (!resolve_wildcards(fname,destname)) {
+                   DEBUG(6,("resolve_wildcards %s %s failed\n", 
+                            fname, destname));
+                   continue;
+           }
 
            if (file_exist(destname,NULL)) {
-             error = 183;
-             continue;
+                   DEBUG(6,("file_exist %s\n", 
+                            destname));
+                   error = 183;
+                   continue;
            }
            if (!sys_rename(fname,destname)) count++;
            DEBUG(3,("reply_mv : doing rename on %s -> %s\n",fname,destname));
@@ -2686,7 +3262,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);
@@ -2706,7 +3289,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) 
@@ -2722,23 +3305,27 @@ 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);
+  if (!Files[fnum1].open) {
+         Files[fnum1].reserved = False;
+         return(False);
+  }
 
   if (!target_is_directory && count)
     ofun = 1;
 
   fnum2 = find_free_file();
   if (fnum2<0) {
-    close_file(fnum1);
+    close_file(fnum1,False);
     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);
+    close_file(fnum1,False);
+    Files[fnum2].reserved = False;
     return(False);
   }
 
@@ -2749,8 +3336,8 @@ static BOOL copy_file(char *src,char *dest1,int cnum,int ofun,
   if (st.st_size)
     ret = transfer_file(Files[fnum1].fd_ptr->fd,Files[fnum2].fd_ptr->fd,st.st_size,NULL,0,0);
 
-  close_file(fnum1);
-  close_file(fnum2);
+  close_file(fnum1,False);
+  close_file(fnum2,False);
 
   return(ret == st.st_size);
 }
@@ -2776,13 +3363,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));
    
@@ -2792,8 +3381,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);
 
@@ -2839,7 +3428,7 @@ int reply_copy(char *inbuf,char *outbuf)
     pstring destname;
 
     if (check_name(directory,cnum))
-      dirptr = OpenDir(directory);
+      dirptr = OpenDir(cnum, directory, True);
 
     if (dirptr)
       {
@@ -2851,7 +3440,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;
 
@@ -2871,7 +3460,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);
@@ -2898,7 +3494,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)
@@ -2928,7 +3524,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;
@@ -2945,6 +3544,55 @@ 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))
+  {
+    int 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);
+    } else {
+           unlock_share_entry(fsp->cnum, dev, inode, token);
+
+           /* Clear the granted flag and return. */
+           fsp->granted_oplock = False;
+    }
+
+    /* if this is a pure oplock break request then don't send a reply */
+    if (num_locks == 0 && num_ulocks == 0)
+    {
+      /* Sanity check - ensure a pure oplock break is not a
+         chained request. */
+      if(CVAL(inbuf,smb_vwv0) != 0xff)
+        DEBUG(0,("reply_lockingX: Error : pure oplock break is a chained %d request !\n",
+                 (unsigned int)CVAL(inbuf,smb_vwv0) ));
+      return -1;
+    }
+  }
+
   /* Data now points at the beginning of the list
      of smb_unlkrng structs */
   for(i = 0; i < (int)num_ulocks; i++) {
@@ -2979,7 +3627,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;
 
@@ -2996,7 +3644,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;
@@ -3020,7 +3668,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;
 
@@ -3067,7 +3715,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;
   
@@ -3256,11 +3904,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))
+  if(file_utime(cnum, 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);
 }
@@ -3293,7 +3961,7 @@ int reply_getattrE(char *inbuf,char *outbuf)
   /* Convert the times into dos times. Set create
      date to be last modify date as UNIX doesn't save
      this */
-  put_dos_date2(outbuf,smb_vwv0,sbuf.st_mtime);
+  put_dos_date2(outbuf,smb_vwv0,get_create_time(&sbuf));
   put_dos_date2(outbuf,smb_vwv2,sbuf.st_atime);
   put_dos_date2(outbuf,smb_vwv4,sbuf.st_mtime);
   if (mode & aDIR)
@@ -3312,8 +3980,3 @@ int reply_getattrE(char *inbuf,char *outbuf)
   
   return(outsize);
 }
-
-
-
-
-