make sure we don't walk past the end of the current SMB buffer when
[sfrench/samba-autobuild/.git] / source3 / smbd / reply.c
index dbd149afcf5fb20dbe114dd277948c38e4ff85c0..0ccdf7c241b6caad9fae8f70d27b38f6011d4abf 100644 (file)
@@ -1,6 +1,5 @@
 /* 
-   Unix SMB/Netbios implementation.
-   Version 1.9.
+   Unix SMB/CIFS implementation.
    Main SMB reply routines
    Copyright (C) Andrew Tridgell 1992-1998
    Copyright (C) Andrew Bartlett      2001
 
 /* look in server.c for some explanation of these variables */
 extern int Protocol;
-extern int DEBUGLEVEL;
 extern int max_send;
 extern int max_recv;
 extern char magic_char;
 extern BOOL case_sensitive;
 extern BOOL case_preserve;
 extern BOOL short_case_preserve;
-extern userdom_struct current_user_info;
 extern pstring global_myname;
 extern int global_oplock_break;
-uint32 global_client_caps = 0;
 unsigned int smb_echo_count = 0;
 
 extern fstring remote_machine;
 extern BOOL global_encrypted_passwords_negotiated;
 
-/****************************************************************************
-report a possible attack via the password buffer overflow bug
-****************************************************************************/
-
-static void overflow_attack(int len)
-{
-       if( DEBUGLVL( 0 ) ) {
-               dbgtext( "ERROR: Invalid password length %d.\n", len );
-               dbgtext( "Your machine may be under attack by someone " );
-               dbgtext( "attempting to exploit an old bug.\n" );
-               dbgtext( "Attack was from IP = %s.\n", client_addr() );
-       }
-}
-
 
 /****************************************************************************
   reply to an special message 
@@ -83,8 +65,8 @@ int reply_special(char *inbuf,char *outbuf)
        
        switch (msg_type) {
        case 0x81: /* session request */
-               CVAL(outbuf,0) = 0x82;
-               CVAL(outbuf,3) = 0;
+               SCVAL(outbuf,0,0x82);
+               SCVAL(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"));
@@ -117,7 +99,7 @@ int reply_special(char *inbuf,char *outbuf)
                if (name_type == 'R') {
                        /* We are being asked for a pathworks session --- 
                           no thanks! */
-                       CVAL(outbuf, 0) = 0x83;
+                       SCVAL(outbuf, 0,0x83);
                        break;
                }
 
@@ -137,8 +119,8 @@ int reply_special(char *inbuf,char *outbuf)
                
        case 0x89: /* session keepalive request 
                      (some old clients produce this?) */
-               CVAL(outbuf,0) = 0x85;
-               CVAL(outbuf,3) = 0;
+               SCVAL(outbuf,0,SMBkeepalive);
+               SCVAL(outbuf,3,0);
                break;
                
        case 0x82: /* positive session response */
@@ -147,7 +129,7 @@ int reply_special(char *inbuf,char *outbuf)
                DEBUG(0,("Unexpected session response\n"));
                break;
                
-       case 0x85: /* session keepalive */
+       case SMBkeepalive: /* session keepalive */
        default:
                return(0);
        }
@@ -174,22 +156,28 @@ int reply_tcon(connection_struct *conn,
        int pwlen=0;
        NTSTATUS nt_status;
        char *p;
-
+       DATA_BLOB password_blob;
+       
        START_PROFILE(SMBtcon);
 
        *service = *password = *dev = 0;
 
        p = smb_buf(inbuf)+1;
-       p += srvstr_pull(inbuf, service, p, sizeof(service), -1, STR_TERMINATE) + 1;
-       p += srvstr_pull(inbuf, password, p, sizeof(password), -1, STR_TERMINATE) + 1;
-       p += srvstr_pull(inbuf, dev, p, sizeof(dev), -1, STR_TERMINATE) + 1;
+       p += srvstr_pull_buf(inbuf, service, p, sizeof(service), STR_TERMINATE) + 1;
+       pwlen = srvstr_pull_buf(inbuf, password, p, sizeof(password), STR_TERMINATE) + 1;
+       p += pwlen;
+       p += srvstr_pull_buf(inbuf, dev, p, sizeof(dev), STR_TERMINATE) + 1;
 
        p = strrchr_m(service,'\\');
        if (p) {
                pstrcpy(service, p+1);
        }
 
-       conn = make_connection(service,password,pwlen,dev,vuid,&nt_status);
+       password_blob = data_blob(password, pwlen+1);
+
+       conn = make_connection(service,password_blob,dev,vuid,&nt_status);
+
+       data_blob_clear_free(&password_blob);
   
        if (!conn) {
                END_PROFILE(SMBtcon);
@@ -215,16 +203,17 @@ int reply_tcon(connection_struct *conn,
 int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
 {
        fstring service;
-       pstring password;
+       DATA_BLOB password;
        pstring devicename;
        NTSTATUS nt_status;
        uint16 vuid = SVAL(inbuf,smb_uid);
        int passlen = SVAL(inbuf,smb_vwv3);
        pstring path;
        char *p, *q;
-       START_PROFILE(SMBtconX);
-       
-       *service = *password = *devicename = 0;
+       extern BOOL global_encrypted_passwords_negotiated;
+       START_PROFILE(SMBtconX);        
+
+       *service = *devicename = 0;
 
        /* we might have to close an old one */
        if ((SVAL(inbuf,smb_vwv2) & 0x1) && conn) {
@@ -232,21 +221,20 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
        }
 
        if (passlen > MAX_PASS_LEN) {
-               overflow_attack(passlen);
-               return(ERROR_DOS(ERRDOS,ERRbuftoosmall));
+               return ERROR_DOS(ERRDOS,ERRbuftoosmall);
        }
  
-       memcpy(password,smb_buf(inbuf),passlen);
-       password[passlen]=0;    
+       if (global_encrypted_passwords_negotiated) {
+               password = data_blob(smb_buf(inbuf),passlen);
+       } else {
+               password = data_blob(smb_buf(inbuf),passlen+1);
+               /* Ensure correct termination */
+               password.data[passlen]=0;    
+       }
+
        p = smb_buf(inbuf) + passlen;
-       p += srvstr_pull(inbuf, path, p, sizeof(path), -1, STR_TERMINATE);
+       p += srvstr_pull_buf(inbuf, path, p, sizeof(path), STR_TERMINATE);
 
-       if (passlen != 24) {
-               if (strequal(password," "))
-                       *password = 0;
-               passlen = strlen(password);
-       }
-       
        /*
         * the service name can be either: \\server\share
         * or share directly like on the DELL PowerVault 705
@@ -266,8 +254,10 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
 
        DEBUG(4,("Got device type %s\n",devicename));
 
-       conn = make_connection(service,password,passlen,devicename,vuid,&nt_status);
+       conn = make_connection(service,password,devicename,vuid,&nt_status);
        
+       data_blob_clear_free(&password);
+
        if (!conn) {
                END_PROFILE(SMBtconX);
                return ERROR_NT(nt_status);
@@ -295,7 +285,8 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
                
                /* what does setting this bit do? It is set by NT4 and
                   may affect the ability to autorun mounted cdroms */
-               SSVAL(outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS); 
+               SSVAL(outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS|
+                               (lp_csc_policy(SNUM(conn)) << 2));
                
                init_dfsroot(conn, inbuf, outbuf);
        }
@@ -373,334 +364,6 @@ int reply_ioctl(connection_struct *conn,
        return outsize;
 }
 
-/****************************************************************************
-reply to a session setup command
-****************************************************************************/
-
-int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
-{
-  int sess_vuid;
-  gid_t gid;
-  uid_t uid;
-  char* full_name;
-  int   smb_bufsize;    
-  int   smb_apasslen = 0;   
-  pstring smb_apasswd;
-  int   smb_ntpasslen = 0;   
-  pstring smb_ntpasswd;
-  pstring user;
-  pstring orig_user;
-  fstring domain;
-  fstring native_os;
-  fstring native_lanman;
-  BOOL guest=False;
-  static BOOL done_sesssetup = False;
-  BOOL doencrypt = global_encrypted_passwords_negotiated;
-  START_PROFILE(SMBsesssetupX);
-
-  *smb_apasswd = *smb_ntpasswd = 0;
-  
-  smb_bufsize = SVAL(inbuf,smb_vwv2);
-  
-  if (Protocol < PROTOCOL_NT1) {
-    smb_apasslen = SVAL(inbuf,smb_vwv7);
-    if (smb_apasslen > MAX_PASS_LEN) {
-           overflow_attack(smb_apasslen);
-           return(ERROR_DOS(ERRDOS,ERRbuftoosmall));
-    }
-
-    memcpy(smb_apasswd,smb_buf(inbuf),smb_apasslen);
-    srvstr_pull(inbuf, user, smb_buf(inbuf)+smb_apasslen, sizeof(user), -1, STR_TERMINATE);
-    
-    if (!doencrypt && (lp_security() != SEC_SERVER)) {
-      smb_apasslen = strlen(smb_apasswd);
-    }
-  } else {
-    uint16 passlen1 = SVAL(inbuf,smb_vwv7);
-    uint16 passlen2 = SVAL(inbuf,smb_vwv8);
-    enum remote_arch_types ra_type = get_remote_arch();
-    char *p = smb_buf(inbuf);    
-
-    if(global_client_caps == 0)
-      global_client_caps = IVAL(inbuf,smb_vwv11);
-
-    /* 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_WIN2K || ra_type == RA_WIN95) {
-      if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
-        set_remote_arch( RA_WIN95);
-      }
-    }
-
-    if (passlen1 != 24 && passlen2 < 24)
-           doencrypt = False;
-
-    if (passlen1 > MAX_PASS_LEN) {
-           overflow_attack(passlen1);
-           return ERROR_DOS(ERRDOS,ERRbuftoosmall);
-    }
-
-    passlen1 = MIN(passlen1, MAX_PASS_LEN);
-    passlen2 = MIN(passlen2, MAX_PASS_LEN);
-
-    if (!doencrypt) {
-       /* both Win95 and WinNT stuff up the password lengths for
-          non-encrypting systems. Uggh. 
-      
-          if passlen1==24 its a win95 system, and its setting the
-          password length incorrectly. Luckily it still works with the
-          default code because Win95 will null terminate the password
-          anyway 
-
-          if passlen1>0 and passlen2>0 then maybe its a NT box and its
-          setting passlen2 to some random value which really stuffs
-          things up. we need to fix that one.  */
-
-      if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
-        passlen2 = 0;
-    }
-
-    if (lp_restrict_anonymous()) {
-      /* there seems to be no reason behind the differences in MS clients formatting
-       * various info like the domain, NativeOS, and NativeLanMan fields. Win95
-       * in particular seems to have an extra null byte between the username and the
-       * domain, or the password length calculation is wrong, which throws off the
-       * string extraction routines below.  This makes the value of domain be the
-       * empty string, which fails the restrict anonymous check further down.
-       * This compensates for that, and allows browsing to work in mixed NT and
-       * win95 environments even when restrict anonymous is true. AAB
-       */
-      dump_data(100, p, 0x70);
-      DEBUG(9, ("passlen1=%d, passlen2=%d\n", passlen1, passlen2));
-      if (ra_type == RA_WIN95 && !passlen1 && !passlen2 && p[0] == 0 && p[1] == 0) {
-        DEBUG(0, ("restrict anonymous parameter used in a win95 environment!\n"));
-        DEBUG(0, ("client is win95 and broken passlen1 offset -- attempting fix\n"));
-        DEBUG(0, ("if win95 cilents are having difficulty browsing, you will be unable to use restrict anonymous\n"));
-        passlen1 = 1;
-      }
-    }
-
-    /* Save the lanman2 password and the NT md4 password. */
-    smb_apasslen = passlen1;
-    memcpy(smb_apasswd,p,smb_apasslen);
-
-    smb_ntpasslen = passlen2;
-    memcpy(smb_ntpasswd,p+passlen1,smb_ntpasslen);
-
-    if (smb_apasslen != 24 || !doencrypt) {
-           /* trim the password */
-           smb_apasslen = strlen(smb_apasswd);
-           
-           /* wfwg sometimes uses a space instead of a null */
-           if (strequal(smb_apasswd," ")) {
-                   smb_apasslen = 0;
-                   *smb_apasswd = 0;
-           }
-    }
-    
-    p += passlen1 + passlen2;
-    p += srvstr_pull(inbuf, user, p, sizeof(user), -1,
-               STR_TERMINATE);
-    /*
-     * Incoming user and domain are in DOS codepage format. Convert
-     * to UNIX.
-     */
-    p += srvstr_pull(inbuf, domain, p, sizeof(domain), 
-                    -1, STR_TERMINATE);
-    p += srvstr_pull(inbuf, native_os, p, sizeof(native_os), 
-                    -1, STR_TERMINATE);
-    p += srvstr_pull(inbuf, native_lanman, p, sizeof(native_lanman),
-                    -1, STR_TERMINATE);
-    DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s]\n",
-            domain,native_os,native_lanman));
-  }
-  
-  /* don't allow for weird usernames or domains */
-  alpha_strcpy(user, user, ". _-$", sizeof(user));
-  alpha_strcpy(domain, domain, ". _-", sizeof(domain));
-  if (strstr(user, "..") || strstr(domain,"..")) {
-         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
-  }
-
-  if (lp_security() == SEC_SHARE) {
-         /* in share level we should ignore any passwords */
-         smb_ntpasslen = 0;
-         smb_apasslen = 0;
-         guest = True;
-  }
-
-
-  DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",user, domain, remote_machine));
-
-  if (done_sesssetup && lp_restrict_anonymous()) {
-    /* tests show that even if browsing is done over already validated connections
-     * without a username and password the domain is still provided, which it
-     * wouldn't be if it was a purely anonymous connection.  So, in order to
-     * restrict anonymous, we only deny connections that have no session
-     * information.  If a domain has been provided, then it's not a purely
-     * anonymous connection. AAB
-     */
-    if (!*user && !*smb_apasswd && !*domain) {
-      DEBUG(0, ("restrict anonymous is True and anonymous connection attempted. Denying access.\n"));
-      END_PROFILE(SMBsesssetupX);
-      return ERROR_DOS(ERRDOS,ERRnoaccess);
-    }
-  }
-
-  /* If no username is sent use the guest account */
-  if (!*user) {
-         pstrcpy(user,lp_guestaccount(-1));
-         guest = True;
-  }
-
-  pstrcpy(current_user_info.smb_name,user);
-
-  reload_services(True);
-
-  /*
-   * Save the username before mapping. We will use
-   * the original username sent to us for security=server
-   * and security=domain checking.
-   */
-
-  pstrcpy( orig_user, user);
-
-  /*
-   * Always try the "DOMAIN\user" lookup first, as this is the most
-   * specific case. If this fails then try the simple "user" lookup.
-   * But don't do this for guests, as this is always a local user.
-   */
-  if (!guest) {
-    pstring dom_user;
-    /* Work out who's who */
-    slprintf(dom_user, sizeof(dom_user) - 1,"%s%s%s",
-            domain, lp_winbind_separator(), user);
-    if (sys_getpwnam(dom_user) != NULL) {
-      pstrcpy(user, dom_user);
-      DEBUG(3,("Using unix username %s\n", dom_user));
-    }
-
-    /*
-     * Pass the user through the NT -> unix user mapping
-     * function.
-     */
-    
-    (void)map_username(user);
-    
-    /*
-     * Do any UNIX username case mangling.
-     */
-    smb_getpwnam(user, True);
-  }
-  
-  add_session_user(user);
-
-  if (!guest) {
-         NTSTATUS nt_status;
-         nt_status = pass_check_smb(orig_user, user, 
-                                    domain, remote_machine,
-                                    (unsigned char *)smb_apasswd, 
-                                    smb_apasslen, 
-                                    (unsigned char *)smb_ntpasswd,
-                                    smb_ntpasslen);
-         
-         if NT_STATUS_IS_OK(nt_status) {
-
-         } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER) {
-                 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) || 
-                     (lp_map_to_guest() ==  MAP_TO_GUEST_ON_BAD_PASSWORD)) {
-                         DEBUG(3,("No such user %s [%s] - using guest account\n",user, domain));
-                         pstrcpy(user,lp_guestaccount(-1));
-                         guest = True;
-                 } else {
-                         /* Match WinXP and don't give the game away */
-                         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
-                 }
-         } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD) {
-                 if (lp_map_to_guest() ==  MAP_TO_GUEST_ON_BAD_PASSWORD) {
-                         pstrcpy(user,lp_guestaccount(-1));
-                         DEBUG(3,("Registered username %s for guest access\n",user));
-                         guest = True;
-                 } else {
-                         /* Match WinXP and don't give the game away */
-                         return ERROR_NT(NT_STATUS_LOGON_FAILURE);
-                 }
-         } else {
-                 return ERROR_NT(nt_status);
-         }
-  }
-  
-  if (!strequal(user,lp_guestaccount(-1)) &&
-      lp_servicenumber(user) < 0)      
-  {
-       add_home_service(user,get_user_home_dir(user));
-  }
-
-
-  /* it's ok - setup a reply */
-  if (Protocol < PROTOCOL_NT1) {
-    set_message(outbuf,3,0,True);
-  } else {
-    char *p;
-    set_message(outbuf,3,0,True);
-    p = smb_buf(outbuf);
-    p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
-    p += srvstr_push(outbuf, p, "Samba", -1, STR_TERMINATE);
-    p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
-    set_message_end(outbuf,p);
-    /* perhaps grab OS version here?? */
-  }
-
-  /* Set the correct uid in the outgoing and incoming packets
-     We will use this on future requests to determine which
-     user we should become.
-     */
-  {
-    const struct passwd *pw = smb_getpwnam(user,False);
-    if (!pw) {
-      DEBUG(1,("Username %s is invalid on this system\n",user));
-      END_PROFILE(SMBsesssetupX);
-      return ERROR_NT(NT_STATUS_LOGON_FAILURE);
-    }
-    gid = pw->pw_gid;
-    uid = pw->pw_uid;
-    full_name = pw->pw_gecos;
-  }
-
-  if (guest)
-    SSVAL(outbuf,smb_vwv2,1);
-
-  /* register the name and uid as being validated, so further connections
-     to a uid can get through without a password, on the same VC */
-
-  sess_vuid = register_vuid(uid,gid,user,orig_user,domain,guest, full_name);
-  
-  if (sess_vuid == -1) {
-      return ERROR_NT(NT_STATUS_LOGON_FAILURE);
-  }
-
-  SSVAL(outbuf,smb_uid,sess_vuid);
-  SSVAL(inbuf,smb_uid,sess_vuid);
-
-  if (!done_sesssetup)
-    max_send = MIN(max_send,smb_bufsize);
-
-  DEBUG(6,("Client requested max send size of %d\n", max_send));
-
-  done_sesssetup = True;
-
-  END_PROFILE(SMBsesssetupX);
-  return chain_reply(inbuf,outbuf,length,bufsize);
-}
-
 /****************************************************************************
   reply to a chkpth
 ****************************************************************************/
@@ -714,7 +377,7 @@ int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
   SMB_STRUCT_STAT sbuf;
   START_PROFILE(SMBchkpth);
 
-  srvstr_pull(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), -1, STR_TERMINATE);
+  srvstr_pull_buf(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), STR_TERMINATE);
 
   RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
 
@@ -766,7 +429,7 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
   START_PROFILE(SMBgetatr);
 
   p = smb_buf(inbuf) + 1;
-  p += srvstr_pull(inbuf, fname, p, sizeof(fname), -1, STR_TERMINATE);
+  p += srvstr_pull_buf(inbuf, fname, p, sizeof(fname), STR_TERMINATE);
 
   RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
   
@@ -801,12 +464,7 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
   
   if (!ok)
   {
-    if((errno == ENOENT) && bad_path)
-    {
-      unix_ERR_class = ERRDOS;
-      unix_ERR_code = ERRbadpath;
-    }
-
+    set_bad_path_error(errno, bad_path);
     END_PROFILE(SMBgetatr);
     return(UNIXERROR(ERRDOS,ERRbadfile));
   }
@@ -820,9 +478,8 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
     put_dos_date3(outbuf,smb_vwv1,mtime);
   SIVAL(outbuf,smb_vwv3,(uint32)size);
 
-  if (Protocol >= PROTOCOL_NT1) {
-         SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | 0x40); /* IS_LONG_NAME */
-  }
+  if (Protocol >= PROTOCOL_NT1)
+         SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
   
   DEBUG( 3, ( "getatr name=%s mode=%d size=%d\n", fname, mode, (uint32)size ) );
   
@@ -848,7 +505,7 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
   START_PROFILE(SMBsetatr);
 
   p = smb_buf(inbuf) + 1;
-  p += srvstr_pull(inbuf, fname, p, sizeof(fname), -1, STR_TERMINATE);
+  p += srvstr_pull_buf(inbuf, fname, p, sizeof(fname), STR_TERMINATE);
   unix_convert(fname,conn,0,&bad_path,&sbuf);
 
   mode = SVAL(inbuf,smb_vwv0);
@@ -856,6 +513,9 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
   
   if (VALID_STAT_OF_DIR(sbuf))
     mode |= aDIR;
+  else
+    mode &= ~aDIR;
+
   if (check_name(fname,conn))
     ok =  (file_chmod(conn,fname,mode,NULL) == 0);
   if (ok)
@@ -863,12 +523,7 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
   
   if (!ok)
   {
-    if((errno == ENOENT) && bad_path)
-    {
-      unix_ERR_class = ERRDOS;
-      unix_ERR_code = ERRbadpath;
-    }
-
+    set_bad_path_error(errno, bad_path);
     END_PROFILE(SMBsetatr);
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
@@ -887,23 +542,46 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
 ****************************************************************************/
 int reply_dskattr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
-  int outsize = 0;
-  SMB_BIG_UINT dfree,dsize,bsize;
-  START_PROFILE(SMBdskattr);
-  
-  conn->vfs_ops.disk_free(conn,".",True,&bsize,&dfree,&dsize);
-  
-  outsize = set_message(outbuf,5,0,True);
+       int outsize = 0;
+       SMB_BIG_UINT dfree,dsize,bsize;
+       START_PROFILE(SMBdskattr);
+
+       conn->vfs_ops.disk_free(conn,".",True,&bsize,&dfree,&dsize);
   
-  SSVAL(outbuf,smb_vwv0,dsize);
-  SSVAL(outbuf,smb_vwv1,bsize/512);
-  SSVAL(outbuf,smb_vwv2,512);
-  SSVAL(outbuf,smb_vwv3,dfree);
+       outsize = set_message(outbuf,5,0,True);
+       
+       if (Protocol <= PROTOCOL_LANMAN2) {
+               double total_space, free_space;
+               /* we need to scale this to a number that DOS6 can handle. We
+                  use floating point so we can handle large drives on systems
+                  that don't have 64 bit integers 
 
-  DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
+                  we end up displaying a maximum of 2G to DOS systems
+               */
+               total_space = dsize * (double)bsize;
+               free_space = dfree * (double)bsize;
 
-  END_PROFILE(SMBdskattr);
-  return(outsize);
+               dsize = (total_space+63*512) / (64*512);
+               dfree = (free_space+63*512) / (64*512);
+               
+               if (dsize > 0xFFFF) dsize = 0xFFFF;
+               if (dfree > 0xFFFF) dfree = 0xFFFF;
+
+               SSVAL(outbuf,smb_vwv0,dsize);
+               SSVAL(outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
+               SSVAL(outbuf,smb_vwv2,512); /* and this must be 512 */
+               SSVAL(outbuf,smb_vwv3,dfree);
+       } else {
+               SSVAL(outbuf,smb_vwv0,dsize);
+               SSVAL(outbuf,smb_vwv1,bsize/512);
+               SSVAL(outbuf,smb_vwv2,512);
+               SSVAL(outbuf,smb_vwv3,dfree);
+       }
+
+       DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
+
+       END_PROFILE(SMBdskattr);
+       return(outsize);
 }
 
 
@@ -947,7 +625,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
   maxentries = SVAL(inbuf,smb_vwv0); 
   dirtype = SVAL(inbuf,smb_vwv1);
   p = smb_buf(inbuf) + 1;
-  p += srvstr_pull(inbuf, path, p, sizeof(path), -1, STR_TERMINATE);
+  p += srvstr_pull_buf(inbuf, path, p, sizeof(path), STR_TERMINATE);
   p++;
   status_len = SVAL(p, 0);
   p += 2;
@@ -988,7 +666,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
     if (strlen(directory) == 0)
       pstrcpy(directory,"./");
     memset((char *)status,'\0',21);
-    CVAL(status,0) = dirtype;
+    SCVAL(status,0,dirtype);
   }
   else
   {
@@ -1014,12 +692,8 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
       {
         if(dptr_num == -2)
         {
-          if((errno == ENOENT) && bad_path)
-          {
-            unix_ERR_class = ERRDOS;
-            unix_ERR_code = ERRbadpath;
-          }
-                END_PROFILE(SMBsearch);
+          set_bad_path_error(errno, bad_path);
+          END_PROFILE(SMBsearch);
           return (UNIXERROR(ERRDOS,ERRnofids));
         }
                END_PROFILE(SMBsearch);
@@ -1072,7 +746,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
 
   if (numentries == 0 || !ok)
   {
-    CVAL(outbuf,smb_rcls) = ERRDOS;
+    SCVAL(outbuf,smb_rcls,ERRDOS);
     SSVAL(outbuf,smb_err,ERRnofiles);
     dptr_close(&dptr_num);
   }
@@ -1083,7 +757,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
 
   if(ok && expect_close && numentries == 0 && status_len == 0)
   {
-    CVAL(outbuf,smb_rcls) = ERRDOS;
+    SCVAL(outbuf,smb_rcls,ERRDOS);
     SSVAL(outbuf,smb_err,ERRnofiles);
     /* Also close the dptr - we know it's gone */
     dptr_close(&dptr_num);
@@ -1095,12 +769,11 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
 
   SSVAL(outbuf,smb_vwv0,numentries);
   SSVAL(outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
-  CVAL(smb_buf(outbuf),0) = 5;
+  SCVAL(smb_buf(outbuf),0,5);
   SSVAL(smb_buf(outbuf),1,numentries*DIR_STRUCT_SIZE);
 
-  if (Protocol >= PROTOCOL_NT1) {
-    SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | 0x40); /* IS_LONG_NAME */
-  }
+  if (Protocol >= PROTOCOL_NT1)
+    SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
   
   outsize += DIR_STRUCT_SIZE*numentries;
   smb_setlen(outbuf,outsize - 4);
@@ -1133,7 +806,7 @@ int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
 
   outsize = set_message(outbuf,1,0,True);
   p = smb_buf(inbuf) + 1;
-  p += srvstr_pull(inbuf, path, p, sizeof(path), -1, STR_TERMINATE);
+  p += srvstr_pull_buf(inbuf, path, p, sizeof(path), STR_TERMINATE);
   p++;
   status_len = SVAL(p,0);
   p += 2;
@@ -1181,7 +854,7 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
  
   share_mode = SVAL(inbuf,smb_vwv0);
 
-  srvstr_pull(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), -1, STR_TERMINATE);
+  srvstr_pull_buf(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), STR_TERMINATE);
 
   RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
 
@@ -1194,11 +867,7 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
 
   if (!fsp)
   {
-    if((errno == ENOENT) && bad_path)
-    {
-      unix_ERR_class = ERRDOS;
-      unix_ERR_code = ERRbadpath;
-    }
+    set_bad_path_error(errno, bad_path);
     END_PROFILE(SMBopen);
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
@@ -1225,11 +894,11 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
   SSVAL(outbuf,smb_vwv6,rmode);
 
   if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
-    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+    SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
   }
     
   if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
-    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+    SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
   END_PROFILE(SMBopen);
   return(outsize);
 }
@@ -1275,7 +944,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
   }
 
   /* XXXX we need to handle passed times, sattr and flags */
-  srvstr_pull(inbuf, fname, smb_buf(inbuf), sizeof(fname), -1, STR_TERMINATE);
+  srvstr_pull_buf(inbuf, fname, smb_buf(inbuf), sizeof(fname), STR_TERMINATE);
 
   RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
 
@@ -1288,11 +957,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
       
   if (!fsp)
   {
-    if((errno == ENOENT) && bad_path)
-    {
-      unix_ERR_class = ERRDOS;
-      unix_ERR_code = ERRbadpath;
-    }
+    set_bad_path_error(errno, bad_path);
     END_PROFILE(SMBopenX);
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
@@ -1325,11 +990,11 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
    */
 
   if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
-    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+    SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
   }
 
   if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
-    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+    SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
   }
 
   set_message(outbuf,15,0,True);
@@ -1398,7 +1063,7 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
   com = SVAL(inbuf,smb_com);
 
   createmode = SVAL(inbuf,smb_vwv0);
-  srvstr_pull(inbuf, fname, smb_buf(inbuf) + 1, sizeof(fname), -1, STR_TERMINATE);
+  srvstr_pull_buf(inbuf, fname, smb_buf(inbuf) + 1, sizeof(fname), STR_TERMINATE);
 
   RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
 
@@ -1427,11 +1092,7 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
   
   if (!fsp)
   {
-    if((errno == ENOENT) && bad_path) 
-    {
-      unix_ERR_class = ERRDOS;
-      unix_ERR_code = ERRbadpath;
-    }
+    set_bad_path_error(errno, bad_path);
     END_PROFILE(SMBcreate);
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
@@ -1440,11 +1101,11 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
   SSVAL(outbuf,smb_vwv0,fsp->fnum);
 
   if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
-    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+    SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
   }
  
   if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
-    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+    SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
  
   DEBUG( 2, ( "new file %s\n", fname ) );
   DEBUG( 3, ( "mknew %s fd=%d dmode=%d umode=%o\n",
@@ -1474,7 +1135,7 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
   START_PROFILE(SMBctemp);
 
   createmode = SVAL(inbuf,smb_vwv0);
-  srvstr_pull(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), -1, STR_TERMINATE);
+  srvstr_pull_buf(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), STR_TERMINATE);
   pstrcat(fname,"\\TMXXXXXX");
 
   RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
@@ -1501,13 +1162,8 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
   /* close fd from smb_mkstemp() */
   close(tmpfd);
 
-  if (!fsp)
-  {
-    if((errno == ENOENT) && bad_path)
-    {
-      unix_ERR_class = ERRDOS;
-      unix_ERR_code = ERRbadpath;
-    }
+  if (!fsp) {
+    set_bad_path_error(errno, bad_path);
     END_PROFILE(SMBctemp);
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
@@ -1531,11 +1187,11 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
   outsize = set_message_end(outbuf, p);
 
   if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
-         CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+         SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
   }
   
   if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
-         CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+         SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
 
   DEBUG( 2, ( "created temp file %s\n", fname ) );
   DEBUG( 3, ( "ctemp %s fd=%d dmode=%d umode=%o\n",
@@ -1545,29 +1201,85 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
   return(outsize);
 }
 
+/*******************************************************************
+ Check if a user is allowed to rename a file.
+********************************************************************/
+
+static NTSTATUS can_rename(char *fname,connection_struct *conn, SMB_STRUCT_STAT *pst)
+{
+       int smb_action;
+       int access_mode;
+       files_struct *fsp;
+
+       if (!CAN_WRITE(conn))
+               return NT_STATUS_MEDIA_WRITE_PROTECTED;
+       
+       if (S_ISDIR(pst->st_mode))
+               return NT_STATUS_OK;
+
+       /* We need a better way to return NT status codes from open... */
+       unix_ERR_class = 0;
+       unix_ERR_code = 0;
+
+       fsp = open_file_shared1(conn, fname, pst, DELETE_ACCESS, SET_DENY_MODE(DENY_ALL),
+               (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, 0, &access_mode, &smb_action);
+
+       if (!fsp) {
+               NTSTATUS ret = NT_STATUS_ACCESS_DENIED;
+               if (unix_ERR_class == ERRDOS && unix_ERR_code == ERRbadshare)
+                       ret = NT_STATUS_SHARING_VIOLATION;
+               unix_ERR_class = 0;
+               unix_ERR_code = 0;
+               return ret;
+       }
+       close_file(fsp,False);
+       return NT_STATUS_OK;
+}
 
 /*******************************************************************
-check if a user is allowed to delete a file
+ Check if a user is allowed to delete a file.
 ********************************************************************/
+
 static NTSTATUS can_delete(char *fname,connection_struct *conn, int dirtype)
 {
        SMB_STRUCT_STAT sbuf;
        int fmode;
+       int smb_action;
+       int access_mode;
+       files_struct *fsp;
 
-       if (!CAN_WRITE(conn)) return NT_STATUS_MEDIA_WRITE_PROTECTED;
+       if (!CAN_WRITE(conn))
+               return NT_STATUS_MEDIA_WRITE_PROTECTED;
 
-       if (conn->vfs_ops.lstat(conn,fname,&sbuf) != 0) return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+       if (conn->vfs_ops.lstat(conn,fname,&sbuf) != 0)
+               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
 
        fmode = dos_mode(conn,fname,&sbuf);
-       if (fmode & aDIR) return NT_STATUS_FILE_IS_A_DIRECTORY;
+       if (fmode & aDIR)
+               return NT_STATUS_FILE_IS_A_DIRECTORY;
        if (!lp_delete_readonly(SNUM(conn))) {
-               if (fmode & aRONLY) return NT_STATUS_CANNOT_DELETE;
+               if (fmode & aRONLY)
+                       return NT_STATUS_CANNOT_DELETE;
        }
        if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM))
                return NT_STATUS_CANNOT_DELETE;
 
-       if (!check_file_sharing(conn,fname,False)) return NT_STATUS_SHARING_VIOLATION;
+       /* We need a better way to return NT status codes from open... */
+       unix_ERR_class = 0;
+       unix_ERR_code = 0;
+
+       fsp = open_file_shared1(conn, fname, &sbuf, DELETE_ACCESS, SET_DENY_MODE(DENY_ALL),
+               (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, 0, &access_mode, &smb_action);
 
+       if (!fsp) {
+               NTSTATUS ret = NT_STATUS_ACCESS_DENIED;
+               if (unix_ERR_class == ERRDOS && unix_ERR_code == ERRbadshare)
+                       ret = NT_STATUS_SHARING_VIOLATION;
+               unix_ERR_class = 0;
+               unix_ERR_code = 0;
+               return ret;
+       }
+       close_file(fsp,False);
        return NT_STATUS_OK;
 }
 
@@ -1584,7 +1296,6 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
        int count=0;
        NTSTATUS error = NT_STATUS_OK;
        BOOL has_wild;
-       BOOL exists=False;
        BOOL bad_path = False;
        BOOL rc = True;
        SMB_STRUCT_STAT sbuf;
@@ -1595,7 +1306,7 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
        
        p = strrchr_m(name,'/');
        if (!p) {
-               pstrcpy(directory,"./");
+               pstrcpy(directory,".");
                pstrcpy(mask,name);
        } else {
                *p = 0;
@@ -1612,8 +1323,8 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
         * Tine Smukavec <valentin.smukavec@hermes.si>.
         */
        
-       if (!rc && is_mangled(mask))
-               check_mangled_cache( mask );
+       if (!rc && mangle_is_mangled(mask))
+               mangle_check_cache( mask );
        
        has_wild = ms_has_wild(mask);
        
@@ -1626,8 +1337,6 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
                if (vfs_unlink(conn,directory) == 0) {
                        count++;
                }
-               if (!count)
-                       exists = vfs_file_exist(conn,directory,&sbuf);    
        } else {
                void *dirptr = NULL;
                char *dname;
@@ -1684,7 +1393,7 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
        
        dirtype = SVAL(inbuf,smb_vwv0);
        
-       srvstr_pull(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), -1, STR_TERMINATE);
+       srvstr_pull_buf(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), STR_TERMINATE);
        
        RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
        
@@ -1712,7 +1421,7 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
 void fail_readraw(void)
 {
        pstring errstr;
-       slprintf(errstr, sizeof(errstr)-1, "FAIL ! reply_readbraw: socket write fail (%s)\n",
+       slprintf(errstr, sizeof(errstr)-1, "FAIL ! reply_readbraw: socket write fail (%s)",
                strerror(errno) );
        exit_server(errstr);
 }
@@ -1723,7 +1432,7 @@ void fail_readraw(void)
 
 int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_size, int dum_buffsize)
 {
-       size_t maxcount,mincount;
+       ssize_t maxcount,mincount;
        size_t nread = 0;
        SMB_OFF_T startpos;
        char *header = outbuf;
@@ -1879,7 +1588,7 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
         * for a write lock. JRA.
         */
        
-       status = do_lock(fsp, conn, SVAL(inbuf,smb_pid), 
+       status = do_lock_spin(fsp, conn, SVAL(inbuf,smb_pid), 
                         (SMB_BIG_UINT)numtoread, (SMB_BIG_UINT)startpos, WRITE_LOCK);
 
        if (NT_STATUS_V(status)) {
@@ -1958,7 +1667,7 @@ int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int size, int
   outsize += nread;
   SSVAL(outbuf,smb_vwv0,nread);
   SSVAL(outbuf,smb_vwv5,nread+3);
-  CVAL(smb_buf(outbuf),0) = 1;
+  SCVAL(smb_buf(outbuf),0,1);
   SSVAL(smb_buf(outbuf),1,nread);
   
   DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
@@ -2076,8 +1785,8 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
        }
 
        /* force the error type */
-       CVAL(inbuf,smb_com) = SMBwritec;
-       CVAL(outbuf,smb_com) = SMBwritec;
+       SCVAL(inbuf,smb_com,SMBwritec);
+       SCVAL(outbuf,smb_com,SMBwritec);
 
        if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
                END_PROFILE(SMBwritebraw);
@@ -2098,11 +1807,11 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
        total_written = nwritten;
 
        /* Return a message to the redirector to tell it to send more bytes */
-       CVAL(outbuf,smb_com) = SMBwritebraw;
+       SCVAL(outbuf,smb_com,SMBwritebraw);
        SSVALS(outbuf,smb_vwv0,-1);
        outsize = set_message(outbuf,Protocol>PROTOCOL_COREPLUS?1:0,0,True);
        if (!send_smb(smbd_server_fd(),outbuf))
-               exit_server("reply_writebraw: send_smb failed.\n");
+               exit_server("reply_writebraw: send_smb failed.");
   
        /* Now read the raw data into the buffer and write it */
        if (read_smb_length(smbd_server_fd(),inbuf,SMB_SECONDARY_WAIT) == -1) {
@@ -2114,7 +1823,7 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
 
        /* Set up outbuf to return the correct return */
        outsize = set_message(outbuf,1,0,True);
-       CVAL(outbuf,smb_com) = SMBwritec;
+       SCVAL(outbuf,smb_com,SMBwritec);
        SSVAL(outbuf,smb_vwv0,total_written);
 
        if (numtowrite != 0) {
@@ -2139,7 +1848,7 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
                nwritten = write_file(fsp,inbuf+4,startpos+nwritten,numtowrite);
 
                if (nwritten < (ssize_t)numtowrite) {
-                       CVAL(outbuf,smb_rcls) = ERRHRD;
+                       SCVAL(outbuf,smb_rcls,ERRHRD);
                        SSVAL(outbuf,smb_err,ERRdiskfull);      
                }
 
@@ -2156,12 +1865,15 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
        /* we won't return a status if write through is not selected - this follows what WfWg does */
        END_PROFILE(SMBwritebraw);
        if (!write_through && total_written==tcount) {
+
+#if RABBIT_PELLET_FIX
                /*
                 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
                 * sending a SMBkeepalive. Thanks to DaveCB at Sun for this. JRA.
                 */
                if (!send_keepalive(smbd_server_fd()))
                        exit_server("reply_writebraw: send of keepalive failed");
+#endif
                return(-1);
        }
 
@@ -2238,67 +1950,76 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf,
 
 int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int size,int dum_buffsize)
 {
-  size_t numtowrite;
-  ssize_t nwritten = -1;
-  SMB_OFF_T startpos;
-  char *data;
-  files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-  int outsize = 0;
-  START_PROFILE(SMBwrite);
+       size_t numtowrite;
+       ssize_t nwritten = -1;
+       SMB_OFF_T startpos;
+       char *data;
+       files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+       int outsize = 0;
+       START_PROFILE(SMBwrite);
 
-  /* If it's an IPC, pass off the pipe handler. */
-  if (IS_IPC(conn)) {
-    END_PROFILE(SMBwrite);
-    return reply_pipe_write(inbuf,outbuf,size,dum_buffsize);
-  }
+       /* If it's an IPC, pass off the pipe handler. */
+       if (IS_IPC(conn)) {
+               END_PROFILE(SMBwrite);
+               return reply_pipe_write(inbuf,outbuf,size,dum_buffsize);
+       }
 
-  CHECK_FSP(fsp,conn);
-  CHECK_WRITE(fsp);
+       CHECK_FSP(fsp,conn);
+       CHECK_WRITE(fsp);
 
-  numtowrite = SVAL(inbuf,smb_vwv1);
-  startpos = IVAL(inbuf,smb_vwv2);
-  data = smb_buf(inbuf) + 3;
+       numtowrite = SVAL(inbuf,smb_vwv1);
+       startpos = IVAL(inbuf,smb_vwv2);
+       data = smb_buf(inbuf) + 3;
   
-  if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
-    END_PROFILE(SMBwrite);
-    return ERROR_DOS(ERRDOS,ERRlock);
-  }
+       if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
+               END_PROFILE(SMBwrite);
+               return ERROR_DOS(ERRDOS,ERRlock);
+       }
 
-  /* X/Open SMB protocol says that if smb_vwv1 is
-     zero then the file size should be extended or
-     truncated to the size given in smb_vwv[2-3] */
-  if(numtowrite == 0) {
-      /* This is actually an allocate call, not set EOF. JRA */
-      nwritten = vfs_allocate_file_space(fsp, (SMB_OFF_T)startpos);
-      if (nwritten < 0) {
-             END_PROFILE(SMBwrite);
-             return ERROR_NT(NT_STATUS_DISK_FULL);
-      }
-  } else
-    nwritten = write_file(fsp,data,startpos,numtowrite);
+       /*
+        * X/Open SMB protocol says that if smb_vwv1 is
+        * zero then the file size should be extended or
+        * truncated to the size given in smb_vwv[2-3].
+        */
+
+       if(numtowrite == 0) {
+               /*
+                * This is actually an allocate call, and set EOF. JRA.
+                */
+               nwritten = vfs_allocate_file_space(fsp, (SMB_OFF_T)startpos);
+               if (nwritten < 0) {
+                       END_PROFILE(SMBwrite);
+                       return ERROR_NT(NT_STATUS_DISK_FULL);
+               }
+               nwritten = vfs_set_filelen(fsp, (SMB_OFF_T)startpos);
+               if (nwritten < 0) {
+                       END_PROFILE(SMBwrite);
+                       return ERROR_NT(NT_STATUS_DISK_FULL);
+               }
+       } else
+               nwritten = write_file(fsp,data,startpos,numtowrite);
   
-  if (lp_syncalways(SNUM(conn)))
-    sync_file(conn,fsp);
+       if (lp_syncalways(SNUM(conn)))
+               sync_file(conn,fsp);
 
-  if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
-    END_PROFILE(SMBwrite);
-    return(UNIXERROR(ERRDOS,ERRnoaccess));
-  }
+       if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
+               END_PROFILE(SMBwrite);
+               return(UNIXERROR(ERRDOS,ERRnoaccess));
+       }
 
-  outsize = set_message(outbuf,1,0,True);
+       outsize = set_message(outbuf,1,0,True);
   
-  SSVAL(outbuf,smb_vwv0,nwritten);
+       SSVAL(outbuf,smb_vwv0,nwritten);
 
-  if (nwritten < (ssize_t)numtowrite) {
-    CVAL(outbuf,smb_rcls) = ERRHRD;
-    SSVAL(outbuf,smb_err,ERRdiskfull);      
-  }
+       if (nwritten < (ssize_t)numtowrite) {
+               SCVAL(outbuf,smb_rcls,ERRHRD);
+               SSVAL(outbuf,smb_err,ERRdiskfull);      
+       }
   
-  DEBUG(3,("write fnum=%d num=%d wrote=%d\n",
-          fsp->fnum, (int)numtowrite, (int)nwritten));
+       DEBUG(3,("write fnum=%d num=%d wrote=%d\n", fsp->fnum, (int)numtowrite, (int)nwritten));
 
-  END_PROFILE(SMBwrite);
-  return(outsize);
+       END_PROFILE(SMBwrite);
+       return(outsize);
 }
 
 
@@ -2387,7 +2108,7 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
     SSVAL(outbuf,smb_vwv4,(nwritten>>16)&1);
 
   if (nwritten < (ssize_t)numtowrite) {
-    CVAL(outbuf,smb_rcls) = ERRHRD;
+    SCVAL(outbuf,smb_rcls,ERRHRD);
     SSVAL(outbuf,smb_err,ERRdiskfull);      
   }
 
@@ -2555,10 +2276,9 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
                return ERROR_DOS(ERRDOS,ERRbadfid);
        }
 
-       if(fsp->is_directory || fsp->stat_open) {
+       if(fsp->is_directory) {
                /*
-                * Special case - close NT SMB directory or stat file
-                * handle.
+                * Special case - close NT SMB directory handle.
                 */
                DEBUG(3,("close %s fnum=%d\n", fsp->is_directory ? "directory" : "stat file open", fsp->fnum));
                close_file(fsp,True);
@@ -2567,21 +2287,10 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
                 * Close ordinary file.
                 */
                int close_err;
+               pstring file_name;
 
-               /*
-                * If there was a modify time outstanding,
-                * try and set it here.
-                */
-               if(fsp->pending_modtime)
-                       set_filetime(conn, fsp->fsp_name, fsp->pending_modtime);
-
-               /*
-                * Now take care of any time sent in the close.
-                */
-               mtime = make_unix_date3(inbuf+smb_vwv1);
-               
-               /* try and set the date */
-               set_filetime(conn, fsp->fsp_name,mtime);
+               /* Save the name for time set in close. */
+               pstrcpy( file_name, fsp->fsp_name);
 
                DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
                         fsp->fd, fsp->fnum,
@@ -2598,6 +2307,16 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
                        END_PROFILE(SMBclose);
                        return (UNIXERROR(ERRHRD,ERRgeneral));
                }
+
+               /*
+                * Now take care of any time sent in the close.
+                */
+
+               mtime = make_unix_date3(inbuf+smb_vwv1);
+               
+               /* try and set the date */
+               set_filetime(conn, file_name, mtime);
+
        }  
 
        /* We have a cached error */
@@ -2692,7 +2411,7 @@ int reply_lock(connection_struct *conn,
        DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
                 fsp->fd, fsp->fnum, (double)offset, (double)count));
 
-       status = do_lock(fsp, conn, SVAL(inbuf,smb_pid), count, offset, WRITE_LOCK);
+       status = do_lock_spin(fsp, conn, SVAL(inbuf,smb_pid), count, offset, WRITE_LOCK);
        if (NT_STATUS_V(status)) {
                if (lp_blocking_locks(SNUM(conn))) {
                        /*
@@ -2802,7 +2521,7 @@ int reply_echo(connection_struct *conn,
                smb_setlen(outbuf,outsize - 4);
 
                if (!send_smb(smbd_server_fd(),outbuf))
-                       exit_server("reply_echo: send_smb failed.\n");
+                       exit_server("reply_echo: send_smb failed.");
        }
 
        DEBUG(3,("echo %d times\n", smb_reverb));
@@ -2830,7 +2549,7 @@ int reply_printopen(connection_struct *conn,
        }
 
        /* Open for exclusive use, write only. */
-       fsp = print_fsp_open(conn);
+       fsp = print_fsp_open(conn, NULL);
 
        if (!fsp) {
                END_PROFILE(SMBsplopen);
@@ -2904,7 +2623,7 @@ int reply_printqueue(connection_struct *conn,
 
        SSVAL(outbuf,smb_vwv0,0);
        SSVAL(outbuf,smb_vwv1,0);
-       CVAL(smb_buf(outbuf),0) = 1;
+       SCVAL(smb_buf(outbuf),0,1);
        SSVAL(smb_buf(outbuf),1,0);
   
        DEBUG(3,("printqueue start_index=%d max_count=%d\n",
@@ -2912,8 +2631,9 @@ int reply_printqueue(connection_struct *conn,
 
        {
                print_queue_struct *queue = NULL;
+               print_status_struct status;
                char *p = smb_buf(outbuf) + 3;
-               int count = print_queue_status(SNUM(conn), &queue,NULL);
+               int count = print_queue_status(SNUM(conn), &queue, &status);
                int num_to_get = ABS(max_count);
                int first = (max_count>0?start_index:start_index+max_count+1);
                int i;
@@ -2926,11 +2646,11 @@ int reply_printqueue(connection_struct *conn,
 
                for (i=first;i<first+num_to_get;i++) {
                        put_dos_date2(p,0,queue[i].time);
-                       CVAL(p,4) = (queue[i].status==LPQ_PRINTING?2:3);
+                       SCVAL(p,4,(queue[i].status==LPQ_PRINTING?2:3));
                        SSVAL(p,5, queue[i].job);
                        SIVAL(p,7,queue[i].size);
-                       CVAL(p,11) = 0;
-                       srvstr_push(outbuf, p+12, queue[i].user, 16, STR_ASCII);
+                       SCVAL(p,11,0);
+                       srvstr_push(outbuf, p+12, queue[i].fs_user, 16, STR_ASCII);
                        p += 28;
                }
 
@@ -2938,7 +2658,7 @@ int reply_printqueue(connection_struct *conn,
                        outsize = set_message(outbuf,2,28*count+3,False); 
                        SSVAL(outbuf,smb_vwv0,count);
                        SSVAL(outbuf,smb_vwv1,(max_count>0?first+count:first-1));
-                       CVAL(smb_buf(outbuf),0) = 1;
+                       SCVAL(smb_buf(outbuf),0,1);
                        SSVAL(smb_buf(outbuf),1,28*count);
                }
 
@@ -3002,6 +2722,9 @@ NTSTATUS mkdir_internal(connection_struct *conn, pstring directory)
                ret = vfs_mkdir(conn,directory,unix_mode(conn,aDIR,directory));
        
        if (ret == -1) {
+               NTSTATUS nterr = set_bad_path_error(errno, bad_path);
+               if (!NT_STATUS_IS_OK(nterr))
+                       return nterr;
                return map_nt_error_from_unix(errno);
        }
        
@@ -3019,10 +2742,11 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
        NTSTATUS status;
        START_PROFILE(SMBmkdir);
  
-       srvstr_pull(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), -1, STR_TERMINATE);
+       srvstr_pull_buf(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), STR_TERMINATE);
 
        status = mkdir_internal(conn, directory);
-       if (!NT_STATUS_IS_OK(status)) return ERROR_NT(status);
+       if (!NT_STATUS_IS_OK(status))
+               return ERROR_NT(status);
 
        outsize = set_message(outbuf,0,0,True);
 
@@ -3179,7 +2903,7 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
   SMB_STRUCT_STAT sbuf;
   START_PROFILE(SMBrmdir);
 
-  srvstr_pull(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), -1, STR_TERMINATE);
+  srvstr_pull_buf(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), STR_TERMINATE);
 
   RESOLVE_DFSPATH(directory, conn, inbuf, outbuf)
 
@@ -3193,11 +2917,7 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
   
   if (!ok)
   {
-    if((errno == ENOENT) && bad_path)
-    {
-      unix_ERR_class = ERRDOS;
-      unix_ERR_code = ERRbadpath;
-    }
+    set_bad_path_error(errno, bad_path);
     END_PROFILE(SMBrmdir);
     return(UNIXERROR(ERRDOS,ERRbadpath));
   }
@@ -3275,27 +2995,12 @@ static BOOL resolve_wildcards(char *name1,char *name2)
   return(True);
 }
 
-/*******************************************************************
-check if a user is allowed to rename a file
-********************************************************************/
-static BOOL can_rename(char *fname,connection_struct *conn)
-{
-  SMB_STRUCT_STAT sbuf;
-
-  if (!CAN_WRITE(conn)) return(False);
-
-  if (conn->vfs_ops.lstat(conn,fname,&sbuf) != 0) return(False);
-  if (!check_file_sharing(conn,fname,True)) return(False);
-  return(True);
-}
-
 /****************************************************************************
  The guts of the rename command, split out so it may be called by the NT SMB
  code. 
 ****************************************************************************/
-NTSTATUS rename_internals(connection_struct *conn, 
-                         char *name, 
-                         char *newname, BOOL replace_if_exists)
+
+NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, BOOL replace_if_exists)
 {
        pstring directory;
        pstring mask;
@@ -3306,7 +3011,6 @@ NTSTATUS rename_internals(connection_struct *conn,
        BOOL bad_path2 = False;
        int count=0;
        NTSTATUS error = NT_STATUS_OK;
-       BOOL exists=False;
        BOOL rc = True;
        SMB_STRUCT_STAT sbuf1, sbuf2;
 
@@ -3344,8 +3048,8 @@ NTSTATUS rename_internals(connection_struct *conn,
         * Tine Smukavec <valentin.smukavec@hermes.si>.
         */
 
-       if (!rc && is_mangled(mask))
-               check_mangled_cache( mask );
+       if (!rc && mangle_is_mangled(mask))
+               mangle_check_cache( mask );
 
        has_wild = ms_has_wild(mask);
 
@@ -3353,7 +3057,7 @@ NTSTATUS rename_internals(connection_struct *conn,
                /*
                 * No wildcards - just process the one file.
                 */
-               BOOL is_short_name = is_8_3(name, True);
+               BOOL is_short_name = mangle_is_8_3(name, True);
 
                /* Add a terminating '/' to the directory name. */
                pstrcat(directory,"/");
@@ -3368,7 +3072,8 @@ NTSTATUS rename_internals(connection_struct *conn,
                        pstrcpy(newname, tmpstr);
                }
                
-               DEBUG(3,("rename_internals: case_sensitive = %d, case_preserve = %d, short case preserve = %d, directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", 
+               DEBUG(3,("rename_internals: case_sensitive = %d, case_preserve = %d, short case preserve = %d, \
+directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", 
                         case_sensitive, case_preserve, short_case_preserve, directory, 
                         newname, newname_last_component, is_short_name));
 
@@ -3405,34 +3110,77 @@ NTSTATUS rename_internals(connection_struct *conn,
                                pstrcpy(p+1, newname_last_component);
                        }
                }
-               
-               if(replace_if_exists) {
-                       /*
-                        * NT SMB specific flag - rename can overwrite
-                        * file with the same name so don't check for
-                        * vfs_file_exist().
-                        */
+       
+               resolve_wildcards(directory,newname);
+       
+               /*
+                * The source object must exist.
+                */
 
-                       if(resolve_wildcards(directory,newname) &&
-                          can_rename(directory,conn) &&
-                          conn->vfs_ops.rename(conn,directory,newname) == 0)
-                               count++;
-               } else {
-                       if (resolve_wildcards(directory,newname) && 
-                           can_rename(directory,conn) && 
-                           !vfs_file_exist(conn,newname,NULL) &&
-                           conn->vfs_ops.rename(conn,directory,newname) == 0)
-                               count++;
+               if (!vfs_object_exist(conn, directory, &sbuf1)) {
+                       DEBUG(3,("rename_internals: source doesn't exist doing rename %s -> %s\n",
+                               directory,newname));
+
+                       if (errno == ENOTDIR || errno == EISDIR || errno == ENOENT) {
+                               /*
+                                * Must return different errors depending on whether the parent
+                                * directory existed or not.
+                                */
+
+                               p = strrchr_m(directory, '/');
+                               if (!p)
+                                       return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+                               *p = '\0';
+                               if (vfs_object_exist(conn, directory, NULL))
+                                       return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+                               return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+                       }
+                       error = map_nt_error_from_unix(errno);
+                       DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
+                               nt_errstr(error), directory,newname));
+
+                       return error;
                }
 
-               DEBUG(3,("rename_internals: %s doing rename on %s -> %s\n",(count != 0) ? "succeeded" : "failed",
-                         directory,newname));
-               
-               if (!count) exists = vfs_file_exist(conn,directory,NULL);
-               if (!count && exists && vfs_file_exist(conn,newname,NULL)) {
-                       exists = True;
-                       error = NT_STATUS_OBJECT_NAME_COLLISION;
+               error = can_rename(directory,conn,&sbuf1);
+
+               if (!NT_STATUS_IS_OK(error)) {
+                       DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
+                               nt_errstr(error), directory,newname));
+                       return error;
+               }
+
+               /*
+                * If the src and dest names are identical - including case,
+                * don't do the rename, just return success.
+                */
+
+               if (strcsequal(directory, newname)) {
+                       DEBUG(3,("rename_internals: identical names in rename %s - returning success\n", directory));
+                       return NT_STATUS_OK;
+               }
+
+               if(!replace_if_exists && vfs_object_exist(conn,newname,NULL)) {
+                       DEBUG(3,("rename_internals: dest exists doing rename %s -> %s\n",
+                               directory,newname));
+                       return NT_STATUS_OBJECT_NAME_COLLISION;
+               }
+
+               if(conn->vfs_ops.rename(conn,directory, newname) == 0) {
+                       DEBUG(3,("rename_internals: succeeded doing rename on %s -> %s\n",
+                               directory,newname));
+                       return NT_STATUS_OK;    
                }
+
+               if (errno == ENOTDIR || errno == EISDIR)
+                       error = NT_STATUS_OBJECT_NAME_COLLISION;
+               else
+                       error = map_nt_error_from_unix(errno);
+               
+               DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
+                       nt_errstr(error), directory,newname));
+
+               return error;
        } else {
                /*
                 * Wildcards - process each file that matches.
@@ -3460,7 +3208,13 @@ NTSTATUS rename_internals(connection_struct *conn,
                                
                                error = NT_STATUS_ACCESS_DENIED;
                                slprintf(fname,sizeof(fname)-1,"%s/%s",directory,dname);
-                               if (!can_rename(fname,conn)) {
+                               if (!vfs_object_exist(conn, fname, &sbuf1)) {
+                                       error = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+                                       DEBUG(6,("rename %s failed. Error %s\n", fname, nt_errstr(error)));
+                                       continue;
+                               }
+                               error = can_rename(fname,conn,&sbuf1);
+                               if (!NT_STATUS_IS_OK(error)) {
                                        DEBUG(6,("rename %s refused\n", fname));
                                        continue;
                                }
@@ -3510,9 +3264,9 @@ int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
        START_PROFILE(SMBmv);
 
        p = smb_buf(inbuf) + 1;
-       p += srvstr_pull(inbuf, name, p, sizeof(name), -1, STR_TERMINATE);
+       p += srvstr_pull_buf(inbuf, name, p, sizeof(name), STR_TERMINATE);
        p++;
-       p += srvstr_pull(inbuf, newname, p, sizeof(newname), -1, STR_TERMINATE);
+       p += srvstr_pull_buf(inbuf, newname, p, sizeof(newname), STR_TERMINATE);
        
        RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
        RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
@@ -3599,6 +3353,10 @@ static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
                ret = vfs_transfer_file(fsp1, fsp2, src_sbuf.st_size);
 
        close_file(fsp1,False);
+
+       /* Ensure the modtime is set correctly on the destination file. */
+       fsp2->pending_modtime = src_sbuf.st_mtime;
+
        /*
         * As we are opening fsp1 read-only we only expect
         * an error on close on fsp2 if we are out of space.
@@ -3638,8 +3396,8 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
   *directory = *mask = 0;
 
   p = smb_buf(inbuf);
-  p += srvstr_pull(inbuf, name, p, sizeof(name), -1, STR_TERMINATE);
-  p += srvstr_pull(inbuf, newname, p, sizeof(newname), -1, STR_TERMINATE);
+  p += srvstr_pull_buf(inbuf, name, p, sizeof(name), STR_TERMINATE);
+  p += srvstr_pull_buf(inbuf, newname, p, sizeof(newname), STR_TERMINATE);
    
   DEBUG(3,("reply_copy : %s -> %s\n",name,newname));
    
@@ -3694,8 +3452,8 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
    * Tine Smukavec <valentin.smukavec@hermes.si>.
    */
 
-  if (!rc && is_mangled(mask))
-    check_mangled_cache( mask );
+  if (!rc && mangle_is_mangled(mask))
+         mangle_check_cache( mask );
 
   has_wild = ms_has_wild(mask);
 
@@ -3791,7 +3549,7 @@ int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
     return ERROR_DOS(ERRDOS,ERRnoaccess);
   }
 
-  srvstr_pull(inbuf, newdir, smb_buf(inbuf) + 1, sizeof(newdir), -1, STR_TERMINATE);
+  srvstr_pull_buf(inbuf, newdir, smb_buf(inbuf) + 1, sizeof(newdir), STR_TERMINATE);
   
   if (strlen(newdir) == 0) {
          ok = True;
@@ -3808,7 +3566,7 @@ int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
   }
   
   outsize = set_message(outbuf,0,0,True);
-  CVAL(outbuf,smb_reh) = CVAL(inbuf,smb_reh);
+  SCVAL(outbuf,smb_reh,CVAL(inbuf,smb_reh));
   
   DEBUG(3,("setdir %s\n", newdir));
 
@@ -3825,7 +3583,7 @@ uint16 get_lock_pid( char *data, int data_offset, BOOL large_file_format)
        if(!large_file_format)
                return SVAL(data,SMB_LPID_OFFSET(data_offset));
        else
-               return SVAL(data,SMB_LARGE__LPID_OFFSET(data_offset));
+               return SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
 }
 
 /****************************************************************************
@@ -3973,6 +3731,13 @@ int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,
        CHECK_FSP(fsp,conn);
        
        data = smb_buf(inbuf);
+
+       if (locktype & (LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_CHANGE_LOCKTYPE)) {
+               /* we don't support these - and CANCEL_LOCK makes w2k
+                  and XP reboot so I don't really want to be
+                  compatible! (tridge) */
+               return ERROR_NT(NT_STATUS_NOT_SUPPORTED);
+       }
        
        /* Check if this is an oplock break on a file
           we have granted an oplock on.
@@ -4052,6 +3817,7 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
        }
 
        /* Setup the timeout in seconds. */
+
        lock_timeout = ((lock_timeout == -1) ? -1 : lock_timeout/1000);
        
        /* Now do any requested locks */
@@ -4073,10 +3839,11 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
                        return ERROR_DOS(ERRDOS,ERRnoaccess);
                }
                
-               DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for pid %u, file %s\n",
-                         (double)offset, (double)count, (unsigned int)lock_pid, fsp->fsp_name ));
+               DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for pid %u, file %s timeout = %d\n",
+                       (double)offset, (double)count, (unsigned int)lock_pid,
+                       fsp->fsp_name, (int)lock_timeout ));
                
-               status = do_lock(fsp,conn,lock_pid, count,offset, 
+               status = do_lock_spin(fsp,conn,lock_pid, count,offset, 
                                 ((locktype & 1) ? READ_LOCK : WRITE_LOCK));
                if (NT_STATUS_V(status)) {
                        if ((lock_timeout != 0) && lp_blocking_locks(SNUM(conn))) {
@@ -4130,183 +3897,378 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
        return chain_reply(inbuf,outbuf,length,bufsize);
 }
 
-
 /****************************************************************************
-  reply to a SMBreadbmpx (read block multiplex) request
+ Reply to a SMBreadbmpx (read block multiplex) request.
 ****************************************************************************/
+
 int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
 {
-  ssize_t nread = -1;
-  ssize_t total_read;
-  char *data;
-  SMB_OFF_T startpos;
-  int outsize;
-  size_t maxcount;
-  int max_per_packet;
-  size_t tcount;
-  int pad;
-  files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-  START_PROFILE(SMBreadBmpx);
+       ssize_t nread = -1;
+       ssize_t total_read;
+       char *data;
+       SMB_OFF_T startpos;
+       int outsize;
+       size_t maxcount;
+       int max_per_packet;
+       size_t tcount;
+       int pad;
+       files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+       START_PROFILE(SMBreadBmpx);
 
-  /* this function doesn't seem to work - disable by default */
-  if (!lp_readbmpx()) {
-    END_PROFILE(SMBreadBmpx);
-    return ERROR_DOS(ERRSRV,ERRuseSTD);
-  }
+       /* this function doesn't seem to work - disable by default */
+       if (!lp_readbmpx()) {
+               END_PROFILE(SMBreadBmpx);
+               return ERROR_DOS(ERRSRV,ERRuseSTD);
+       }
 
-  outsize = set_message(outbuf,8,0,True);
+       outsize = set_message(outbuf,8,0,True);
 
-  CHECK_FSP(fsp,conn);
-  CHECK_READ(fsp);
+       CHECK_FSP(fsp,conn);
+       CHECK_READ(fsp);
 
-  startpos = IVAL(inbuf,smb_vwv1);
-  maxcount = SVAL(inbuf,smb_vwv3);
+       startpos = IVAL(inbuf,smb_vwv1);
+       maxcount = SVAL(inbuf,smb_vwv3);
 
-  data = smb_buf(outbuf);
-  pad = ((long)data)%4;
-  if (pad) pad = 4 - pad;
-  data += pad;
+       data = smb_buf(outbuf);
+       pad = ((long)data)%4;
+       if (pad)
+               pad = 4 - pad;
+       data += pad;
 
-  max_per_packet = bufsize-(outsize+pad);
-  tcount = maxcount;
-  total_read = 0;
+       max_per_packet = bufsize-(outsize+pad);
+       tcount = maxcount;
+       total_read = 0;
 
-  if (is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
-    END_PROFILE(SMBreadBmpx);
-    return ERROR_DOS(ERRDOS,ERRlock);
-  }
+       if (is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
+               END_PROFILE(SMBreadBmpx);
+               return ERROR_DOS(ERRDOS,ERRlock);
+       }
 
-  do
-    {
-      size_t N = MIN(max_per_packet,tcount-total_read);
+       do {
+               size_t N = MIN(max_per_packet,tcount-total_read);
   
-      nread = read_file(fsp,data,startpos,N);
+               nread = read_file(fsp,data,startpos,N);
 
-      if (nread <= 0) nread = 0;
+               if (nread <= 0)
+                       nread = 0;
 
-      if (nread < (ssize_t)N)
-        tcount = total_read + nread;
+               if (nread < (ssize_t)N)
+                       tcount = total_read + nread;
 
-      set_message(outbuf,8,nread,False);
-      SIVAL(outbuf,smb_vwv0,startpos);
-      SSVAL(outbuf,smb_vwv2,tcount);
-      SSVAL(outbuf,smb_vwv6,nread);
-      SSVAL(outbuf,smb_vwv7,smb_offset(data,outbuf));
+               set_message(outbuf,8,nread,False);
+               SIVAL(outbuf,smb_vwv0,startpos);
+               SSVAL(outbuf,smb_vwv2,tcount);
+               SSVAL(outbuf,smb_vwv6,nread);
+               SSVAL(outbuf,smb_vwv7,smb_offset(data,outbuf));
 
-      if (!send_smb(smbd_server_fd(),outbuf))
-        exit_server("reply_readbmpx: send_smb failed.\n");
+               if (!send_smb(smbd_server_fd(),outbuf))
+                       exit_server("reply_readbmpx: send_smb failed.");
 
-      total_read += nread;
-      startpos += nread;
-    }
-  while (total_read < (ssize_t)tcount);
+               total_read += nread;
+               startpos += nread;
+       } while (total_read < (ssize_t)tcount);
 
-  END_PROFILE(SMBreadBmpx);
-  return(-1);
+       END_PROFILE(SMBreadBmpx);
+       return(-1);
 }
 
-
 /****************************************************************************
-  reply to a SMBsetattrE
+ Reply to a SMBsetattrE.
 ****************************************************************************/
 
 int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
 {
-  struct utimbuf unix_times;
-  int outsize = 0;
-  files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-  START_PROFILE(SMBsetattrE);
+       struct utimbuf unix_times;
+       int outsize = 0;
+       files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+       START_PROFILE(SMBsetattrE);
 
-  outsize = set_message(outbuf,0,0,True);
+       outsize = set_message(outbuf,0,0,True);
 
-  CHECK_FSP(fsp,conn);
+       if(!fsp || (fsp->conn != conn)) {
+               END_PROFILE(SMBgetattrE);
+               return ERROR_DOS(ERRDOS,ERRbadfid);
+       }
 
-  /* Convert the DOS times into unix times. Ignore create
-     time as UNIX can't set this.
-     */
-  unix_times.actime = make_unix_date2(inbuf+smb_vwv3);
-  unix_times.modtime = make_unix_date2(inbuf+smb_vwv5);
+       /*
+        * Convert the DOS times into unix times. Ignore create
+        * time as UNIX can't set this.
+        */
+
+       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.
-   */
+       /* 
+        * 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 */
-    if( DEBUGLVL( 3 ) )
-      {
-      dbgtext( "reply_setattrE fnum=%d ", fsp->fnum);
-      dbgtext( "ignoring zero request - not setting timestamps of 0\n" );
-      }
-    END_PROFILE(SMBsetattrE);
-    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;
-  }
+       if ((unix_times.actime == 0) && (unix_times.modtime == 0)) {
+               /* Ignore request */
+               if( DEBUGLVL( 3 ) ) {
+                       dbgtext( "reply_setattrE fnum=%d ", fsp->fnum);
+                       dbgtext( "ignoring zero request - not setting timestamps of 0\n" );
+               }
+               END_PROFILE(SMBsetattrE);
+               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(file_utime(conn, fsp->fsp_name, &unix_times)) {
-    END_PROFILE(SMBsetattrE);
-    return ERROR_DOS(ERRDOS,ERRnoaccess);
-  }
+       /* Set the date on this file */
+       if(file_utime(conn, fsp->fsp_name, &unix_times)) {
+               END_PROFILE(SMBsetattrE);
+               return ERROR_DOS(ERRDOS,ERRnoaccess);
+       }
   
-  DEBUG( 3, ( "reply_setattrE fnum=%d actime=%d modtime=%d\n",
-            fsp->fnum, (int)unix_times.actime, (int)unix_times.modtime ) );
+       DEBUG( 3, ( "reply_setattrE fnum=%d actime=%d modtime=%d\n",
+               fsp->fnum, (int)unix_times.actime, (int)unix_times.modtime ) );
 
-  END_PROFILE(SMBsetattrE);
-  return(outsize);
+       END_PROFILE(SMBsetattrE);
+       return(outsize);
 }
 
 
+/* Back from the dead for OS/2..... JRA. */
+
+/****************************************************************************
+ Reply to a SMBwritebmpx (write block multiplex primary) request.
+****************************************************************************/
+
+int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
+{
+       size_t numtowrite;
+       ssize_t nwritten = -1;
+       int outsize = 0;
+       SMB_OFF_T startpos;
+       size_t tcount;
+       BOOL write_through;
+       int smb_doff;
+       char *data;
+       files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+       START_PROFILE(SMBwriteBmpx);
+
+       CHECK_FSP(fsp,conn);
+       CHECK_WRITE(fsp);
+       CHECK_ERROR(fsp);
+
+       tcount = SVAL(inbuf,smb_vwv1);
+       startpos = IVAL(inbuf,smb_vwv3);
+       write_through = BITSETW(inbuf+smb_vwv7,0);
+       numtowrite = SVAL(inbuf,smb_vwv10);
+       smb_doff = SVAL(inbuf,smb_vwv11);
+
+       data = smb_base(inbuf) + smb_doff;
+
+       /* If this fails we need to send an SMBwriteC response,
+               not an SMBwritebmpx - set this up now so we don't forget */
+       SCVAL(outbuf,smb_com,SMBwritec);
+
+       if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos,WRITE_LOCK,False)) {
+               END_PROFILE(SMBwriteBmpx);
+               return(ERROR_DOS(ERRDOS,ERRlock));
+       }
+
+       nwritten = write_file(fsp,data,startpos,numtowrite);
+
+       if(lp_syncalways(SNUM(conn)) || write_through)
+               sync_file(conn,fsp);
+  
+       if(nwritten < (ssize_t)numtowrite) {
+               END_PROFILE(SMBwriteBmpx);
+               return(UNIXERROR(ERRHRD,ERRdiskfull));
+       }
+
+       /* If the maximum to be written to this file
+               is greater than what we just wrote then set
+               up a secondary struct to be attached to this
+               fd, we will use this to cache error messages etc. */
+
+       if((ssize_t)tcount > nwritten) {
+               write_bmpx_struct *wbms;
+               if(fsp->wbmpx_ptr != NULL)
+                       wbms = fsp->wbmpx_ptr; /* Use an existing struct */
+               else
+                       wbms = (write_bmpx_struct *)malloc(sizeof(write_bmpx_struct));
+               if(!wbms) {
+                       DEBUG(0,("Out of memory in reply_readmpx\n"));
+                       END_PROFILE(SMBwriteBmpx);
+                       return(ERROR_DOS(ERRSRV,ERRnoresource));
+               }
+               wbms->wr_mode = write_through;
+               wbms->wr_discard = False; /* No errors yet */
+               wbms->wr_total_written = nwritten;
+               wbms->wr_errclass = 0;
+               wbms->wr_error = 0;
+               fsp->wbmpx_ptr = wbms;
+       }
+
+       /* We are returning successfully, set the message type back to
+               SMBwritebmpx */
+       SCVAL(outbuf,smb_com,SMBwriteBmpx);
+  
+       outsize = set_message(outbuf,1,0,True);
+  
+       SSVALS(outbuf,smb_vwv0,-1); /* We don't support smb_remaining */
+  
+       DEBUG( 3, ( "writebmpx fnum=%d num=%d wrote=%d\n",
+                       fsp->fnum, (int)numtowrite, (int)nwritten ) );
+
+       if (write_through && tcount==nwritten) {
+               /* We need to send both a primary and a secondary response */
+               smb_setlen(outbuf,outsize - 4);
+               if (!send_smb(smbd_server_fd(),outbuf))
+                       exit_server("reply_writebmpx: send_smb failed.");
+
+               /* Now the secondary */
+               outsize = set_message(outbuf,1,0,True);
+               SCVAL(outbuf,smb_com,SMBwritec);
+               SSVAL(outbuf,smb_vwv0,nwritten);
+       }
+
+       END_PROFILE(SMBwriteBmpx);
+       return(outsize);
+}
+
+/****************************************************************************
+ Reply to a SMBwritebs (write block multiplex secondary) request.
+****************************************************************************/
+
+int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+{
+       size_t numtowrite;
+       ssize_t nwritten = -1;
+       int outsize = 0;
+       SMB_OFF_T startpos;
+       size_t tcount;
+       BOOL write_through;
+       int smb_doff;
+       char *data;
+       write_bmpx_struct *wbms;
+       BOOL send_response = False; 
+       files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+       START_PROFILE(SMBwriteBs);
+
+       CHECK_FSP(fsp,conn);
+       CHECK_WRITE(fsp);
+
+       tcount = SVAL(inbuf,smb_vwv1);
+       startpos = IVAL(inbuf,smb_vwv2);
+       numtowrite = SVAL(inbuf,smb_vwv6);
+       smb_doff = SVAL(inbuf,smb_vwv7);
+
+       data = smb_base(inbuf) + smb_doff;
+
+       /* We need to send an SMBwriteC response, not an SMBwritebs */
+       SCVAL(outbuf,smb_com,SMBwritec);
+
+       /* This fd should have an auxiliary struct attached,
+               check that it does */
+       wbms = fsp->wbmpx_ptr;
+       if(!wbms) {
+               END_PROFILE(SMBwriteBs);
+               return(-1);
+       }
+
+       /* If write through is set we can return errors, else we must cache them */
+       write_through = wbms->wr_mode;
+
+       /* Check for an earlier error */
+       if(wbms->wr_discard) {
+               END_PROFILE(SMBwriteBs);
+               return -1; /* Just discard the packet */
+       }
+
+       nwritten = write_file(fsp,data,startpos,numtowrite);
+
+       if(lp_syncalways(SNUM(conn)) || write_through)
+               sync_file(conn,fsp);
+  
+       if (nwritten < (ssize_t)numtowrite) {
+               if(write_through) {
+                       /* We are returning an error - we can delete the aux struct */
+                       if (wbms)
+                               free((char *)wbms);
+                       fsp->wbmpx_ptr = NULL;
+                       END_PROFILE(SMBwriteBs);
+                       return(ERROR_DOS(ERRHRD,ERRdiskfull));
+               }
+               END_PROFILE(SMBwriteBs);
+               return(CACHE_ERROR(wbms,ERRHRD,ERRdiskfull));
+       }
+
+       /* Increment the total written, if this matches tcount
+               we can discard the auxiliary struct (hurrah !) and return a writeC */
+       wbms->wr_total_written += nwritten;
+       if(wbms->wr_total_written >= tcount) {
+               if (write_through) {
+                       outsize = set_message(outbuf,1,0,True);
+                       SSVAL(outbuf,smb_vwv0,wbms->wr_total_written);    
+                       send_response = True;
+               }
+
+               free((char *)wbms);
+               fsp->wbmpx_ptr = NULL;
+       }
+
+       if(send_response) {
+               END_PROFILE(SMBwriteBs);
+               return(outsize);
+       }
+
+       END_PROFILE(SMBwriteBs);
+       return(-1);
+}
+
 /****************************************************************************
-  reply to a SMBgetattrE
+ Reply to a SMBgetattrE.
 ****************************************************************************/
 
 int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
 {
-  SMB_STRUCT_STAT sbuf;
-  int outsize = 0;
-  int mode;
-  files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-  START_PROFILE(SMBgetattrE);
+       SMB_STRUCT_STAT sbuf;
+       int outsize = 0;
+       int mode;
+       files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+       START_PROFILE(SMBgetattrE);
 
-  outsize = set_message(outbuf,11,0,True);
+       outsize = set_message(outbuf,11,0,True);
 
-  CHECK_FSP(fsp,conn);
+       if(!fsp || (fsp->conn != conn)) {
+               END_PROFILE(SMBgetattrE);
+               return ERROR_DOS(ERRDOS,ERRbadfid);
+       }
 
-  /* Do an fstat on this file */
-  if(vfs_fstat(fsp,fsp->fd, &sbuf)) {
-    END_PROFILE(SMBgetattrE);
-    return(UNIXERROR(ERRDOS,ERRnoaccess));
-  }
+       /* Do an fstat on this file */
+       if(fsp_stat(fsp, &sbuf)) {
+               END_PROFILE(SMBgetattrE);
+               return(UNIXERROR(ERRDOS,ERRnoaccess));
+       }
   
-  mode = dos_mode(conn,fsp->fsp_name,&sbuf);
+       mode = dos_mode(conn,fsp->fsp_name,&sbuf);
   
-  /* 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,get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))));
-  put_dos_date2(outbuf,smb_vwv2,sbuf.st_atime);
-  put_dos_date2(outbuf,smb_vwv4,sbuf.st_mtime);
-  if (mode & aDIR)
-    {
-      SIVAL(outbuf,smb_vwv6,0);
-      SIVAL(outbuf,smb_vwv8,0);
-    }
-  else
-    {
-      SIVAL(outbuf,smb_vwv6,(uint32)sbuf.st_size);
-      SIVAL(outbuf,smb_vwv8,SMB_ROUNDUP(sbuf.st_size,1024));
-    }
-  SSVAL(outbuf,smb_vwv10, mode);
+       /*
+        * 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,get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))));
+       put_dos_date2(outbuf,smb_vwv2,sbuf.st_atime);
+       put_dos_date2(outbuf,smb_vwv4,sbuf.st_mtime);
+
+       if (mode & aDIR) {
+               SIVAL(outbuf,smb_vwv6,0);
+               SIVAL(outbuf,smb_vwv8,0);
+       } else {
+               SIVAL(outbuf,smb_vwv6,(uint32)sbuf.st_size);
+               SIVAL(outbuf,smb_vwv8,SMB_ROUNDUP(sbuf.st_size,1024));
+       }
+       SSVAL(outbuf,smb_vwv10, mode);
   
-  DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum));
+       DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum));
   
-  END_PROFILE(SMBgetattrE);
-  return(outsize);
+       END_PROFILE(SMBgetattrE);
+       return(outsize);
 }