Removed version number from file header.
[kai/samba.git] / source3 / smbd / reply.c
index 236bb48ce904670ac28abdb3aa559c8e50244e00..c7f805122db4d1d2db24d3b3ea1875c2544a457b 100644 (file)
@@ -1,9 +1,9 @@
 /* 
-   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
+
    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
    the Free Software Foundation; either version 2 of the License, or
 
 /* 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;
 
-/****************************************************************************
-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() );
-       }
-}
+extern fstring remote_machine;
+extern BOOL global_encrypted_passwords_negotiated;
 
 
 /****************************************************************************
@@ -66,7 +52,7 @@ int reply_special(char *inbuf,char *outbuf)
        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;
@@ -79,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"));
@@ -113,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;
                }
 
@@ -133,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 */
@@ -143,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);
        }
@@ -155,19 +141,6 @@ int reply_special(char *inbuf,char *outbuf)
 }
 
 
-/*******************************************************************
-work out what error to give to a failed connection
-********************************************************************/
-
-static int connection_error(char *inbuf,char *outbuf,int ecode)
-{
-       if (ecode == ERRnoipc || ecode == ERRnosuchshare)
-               return(ERROR_DOS(ERRDOS,ecode));
-
-       return(ERROR_DOS(ERRSRV,ecode));
-}
-
-
 /****************************************************************************
  Reply to a tcon.
 ****************************************************************************/
@@ -176,62 +149,39 @@ int reply_tcon(connection_struct *conn,
               char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
        pstring service;
-       pstring user;
        pstring password;
        pstring dev;
        int outsize = 0;
        uint16 vuid = SVAL(inbuf,smb_uid);
        int pwlen=0;
-       int ecode = -1;
+       NTSTATUS nt_status;
        char *p;
-
+       DATA_BLOB password_blob;
+       
        START_PROFILE(SMBtcon);
 
-       *service = *user = *password = *dev = 0;
+       *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;
+       pwlen = srvstr_pull(inbuf, password, p, sizeof(password), -1, STR_TERMINATE) + 1;
+       p += pwlen;
        p += srvstr_pull(inbuf, dev, p, sizeof(dev), -1, STR_TERMINATE) + 1;
 
-       *user = 0;
-       p = strchr_m(service,'%');
-       if (p != NULL) {
-               *p = 0;
-               fstrcpy(user,p+1);
-       }
-
        p = strrchr_m(service,'\\');
        if (p) {
                pstrcpy(service, p+1);
        }
 
-    /*
-        * If the vuid is valid, we should be using that....
-        */
+       password_blob = data_blob(password, pwlen+1);
 
-       if (*user == '\0' && (lp_security() != SEC_SHARE) && validated_username(vuid)) {
-               pstrcpy(user,validated_username(vuid));
-       } else {
-               
-               /*
-                * Pass the user through the NT -> unix user mapping
-                * function.
-                */
-               
-               (void)map_username(user);
-               
-               /*
-                * Do any UNIX username case mangling.
-                */
-               (void)Get_Pwnam( user, True);
-       }
+       conn = make_connection(service,password_blob,dev,vuid,&nt_status);
 
-       conn = make_connection(service,user,password,pwlen,dev,vuid,&ecode);
+       data_blob_clear_free(&password_blob);
   
        if (!conn) {
                END_PROFILE(SMBtcon);
-               return(connection_error(inbuf,outbuf,ecode));
+               return ERROR_NT(nt_status);
        }
   
        outsize = set_message(outbuf,2,0,True);
@@ -239,8 +189,8 @@ int reply_tcon(connection_struct *conn,
        SSVAL(outbuf,smb_vwv1,conn->cnum);
        SSVAL(outbuf,smb_tid,conn->cnum);
   
-       DEBUG(3,("tcon service=%s user=%s cnum=%d\n", 
-                service, user, conn->cnum));
+       DEBUG(3,("tcon service=%s cnum=%d\n", 
+                service, conn->cnum));
   
        END_PROFILE(SMBtcon);
        return(outsize);
@@ -253,17 +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 user;
-       pstring password;
+       DATA_BLOB password;
        pstring devicename;
-       int ecode = -1;
+       NTSTATUS nt_status;
        uint16 vuid = SVAL(inbuf,smb_uid);
        int passlen = SVAL(inbuf,smb_vwv3);
        pstring path;
        char *p, *q;
-       START_PROFILE(SMBtconX);
-       
-       *service = *user = *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) {
@@ -271,22 +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);
 
-       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
@@ -302,42 +250,17 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
        else
                fstrcpy(service,path);
                
-       q = strchr_m(service,'%');
-       if (q) {
-               *q++ = 0;
-               fstrcpy(user,q);
-       }
        p += srvstr_pull(inbuf, devicename, p, sizeof(devicename), 6, STR_ASCII);
 
        DEBUG(4,("Got device type %s\n",devicename));
 
-    /*
-        * If the vuid is valid, we should be using that....
-        */
-
-       if (*user == '\0' && (lp_security() != SEC_SHARE) && validated_username(vuid)) {
-               pstrcpy(user,validated_username(vuid));
-       } else {
-
-               /*
-                * Pass the user through the NT -> unix user mapping
-                * function.
-                */
-               
-               (void)map_username(user);
-               
-               /*
-                * Do any UNIX username case mangling.
-                */
-               (void)Get_Pwnam(user, True);
-               
-       }
-
-       conn = make_connection(service,user,password,passlen,devicename,vuid,&ecode);
+       conn = make_connection(service,password,devicename,vuid,&nt_status);
        
+       data_blob_clear_free(&password);
+
        if (!conn) {
                END_PROFILE(SMBtconX);
-               return(connection_error(inbuf,outbuf,ecode));
+               return ERROR_NT(nt_status);
        }
 
        if (Protocol < PROTOCOL_NT1) {
@@ -368,8 +291,8 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
        }
 
   
-       DEBUG(3,("tconX service=%s user=%s\n",
-                service, user));
+       DEBUG(3,("tconX service=%s \n",
+                service));
   
        /* set the incoming and outgoing tid to the just created one */
        SSVAL(inbuf,smb_tid,conn->cnum);
@@ -440,467 +363,6 @@ int reply_ioctl(connection_struct *conn,
        return outsize;
 }
 
-/****************************************************************************
- This function breaks the authentication split.  It needs sorting out.
- I can't see why we can't hadle this INSIDE the check_password, as in then
- end all it does it spit out an nt_status code.
- ****************************************************************************/
-/****************************************************************************
- always return an error: it's just a matter of which one...
- ****************************************************************************/
-static int session_trust_account(connection_struct *conn, char *inbuf, char *outbuf, char *user,
-                                char *smb_passwd, int smb_passlen,
-                                char *smb_nt_passwd, int smb_nt_passlen)
-{
-  /* check if trust account exists */
-  SAM_ACCOUNT  *sam_trust_acct = NULL; 
-  uint16       acct_ctrl;
-  BOOL ret;
-       auth_usersupplied_info user_info;
-       auth_serversupplied_info server_info;
-       AUTH_STR domain, smb_username, wksta_name;
-               
-       ZERO_STRUCT(user_info);
-       ZERO_STRUCT(server_info);
-       ZERO_STRUCT(domain);
-       ZERO_STRUCT(smb_username);
-       ZERO_STRUCT(wksta_name);
-       
-       domain.str = lp_workgroup();
-       domain.len = strlen(domain.str);
-
-       user_info.requested_domain = domain;
-       user_info.domain = domain;
-
-       smb_username.str = user;
-       smb_username.len = strlen(smb_username.str);
-
-       user_info.requested_username = smb_username;  /* For the time-being */
-       user_info.smb_username = smb_username;
-       
-       user_info.wksta_name = wksta_name;
-
-       user_info.lm_resp.buffer = (uint8 *)smb_passwd;
-       user_info.lm_resp.len = smb_passlen;
-       user_info.nt_resp.buffer = (uint8 *)smb_nt_passwd;
-       user_info.nt_resp.len = smb_nt_passlen;
-       
-       if (!last_challenge(user_info.chal)) {
-               DEBUG(1,("smb_password_ok: no challenge done - password failed\n"));
-               return NT_STATUS_LOGON_FAILURE;
-       }
-
-  pdb_init_sam(&sam_trust_acct);
-
-  if (lp_security() == SEC_USER) {
-    ret = pdb_getsampwnam(sam_trust_acct, user);
-  } else {
-    DEBUG(0,("session_trust_account: Trust account %s only supported with security = user\n", user));
-    pdb_free_sam(sam_trust_acct);
-    return(ERROR_NT(NT_STATUS_LOGON_FAILURE));
-  }
-
-  if (ret == False) {
-    /* lkclXXXX: workstation entry doesn't exist */
-    DEBUG(0,("session_trust_account: Trust account %s user doesn't exist\n",user));
-    pdb_free_sam(sam_trust_acct);
-    return(ERROR_NT(NT_STATUS_NO_SUCH_USER));
-  } else {
-    if ((smb_passlen != 24) || (smb_nt_passlen != 24)) {
-      DEBUG(0,("session_trust_account: Trust account %s - password length wrong.\n", user));
-     pdb_free_sam(sam_trust_acct);
-     return(ERROR_NT(NT_STATUS_LOGON_FAILURE));
-    }
-
-    if (!smb_password_ok(sam_trust_acct, &user_info, &server_info)) {
-      DEBUG(0,("session_trust_account: Trust Account %s - password failed\n", user));
-      pdb_free_sam(sam_trust_acct);
-      return(ERROR_NT(NT_STATUS_LOGON_FAILURE));
-    }
-
-    acct_ctrl = pdb_get_acct_ctrl(sam_trust_acct);
-    pdb_free_sam(sam_trust_acct);
-    if (acct_ctrl & ACB_DOMTRUST) {
-      DEBUG(0,("session_trust_account: Domain trust account %s denied by server\n",user));
-      return(ERROR_NT(NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT));
-    }
-
-    if (acct_ctrl & ACB_SVRTRUST) {
-      DEBUG(0,("session_trust_account: Server trust account %s denied by server\n",user));
-      return(ERROR_NT(NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT));
-    }
-
-    if (acct_ctrl & ACB_WSTRUST) {
-      DEBUG(4,("session_trust_account: Wksta trust account %s denied by server\n", user));
-      return(ERROR_NT(NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT));
-    }
-  }
-
-  /* don't know what to do: indicate logon failure */
-  return(ERROR_NT(NT_STATUS_LOGON_FAILURE));
-}
-
-
-/****************************************************************************
-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;
-  BOOL valid_password = False;
-  pstring user;
-  pstring orig_user;
-  fstring domain;
-  fstring native_os;
-  fstring native_lanman;
-  BOOL guest=False;
-  static BOOL done_sesssetup = False;
-  BOOL doencrypt = SMBENCRYPT();
-  START_PROFILE(SMBsesssetupX);
-
-  *smb_apasswd = 0;
-  *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;
-      }
-    }
-
-    if(doencrypt || ((lp_security() == SEC_SERVER) || (lp_security() == SEC_DOMAIN))) {
-      /* 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 {
-      /* we use the first password that they gave */
-      smb_apasslen = passlen1;
-      StrnCpy(smb_apasswd,p,smb_apasslen);      
-      
-      /* 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]\n",user));
-
-  /* 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 && (user[strlen(user) - 1] == '$') && (smb_apasslen == 24) && (smb_ntpasslen == 24)) {
-    END_PROFILE(SMBsesssetupX);
-    return session_trust_account(conn, inbuf, outbuf, user, 
-                                 smb_apasswd, smb_apasslen,
-                                 smb_ntpasswd, smb_ntpasslen);
-  }
-
-  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) {
-         valid_password = (pass_check_smb(user, domain, 
-                                          (unsigned char *)smb_apasswd, smb_apasslen, 
-                                          (unsigned char *)smb_ntpasswd, smb_ntpasslen) == NT_STATUS_NOPROBLEMO);
-
-    /* The true branch will be executed if 
-       (1) the NT password failed (or was not tried), and 
-       (2) LanMan authentication failed (or was disabled) 
-     */
-    if (!valid_password)
-    {
-      if (lp_security() >= SEC_USER) 
-      {
-        if (lp_map_to_guest() == NEVER_MAP_TO_GUEST)
-        {
-               DEBUG(1,("Rejecting user '%s': authentication failed\n", user));
-               END_PROFILE(SMBsesssetupX);
-               return ERROR_NT(NT_STATUS_LOGON_FAILURE);
-        }
-
-        if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER)
-        {
-          if (smb_getpwnam(user,True))
-          {
-            DEBUG(1,("Rejecting user '%s': bad password\n", user));
-               END_PROFILE(SMBsesssetupX);
-            return ERROR_NT(NT_STATUS_LOGON_FAILURE);
-          }
-        }
-
-        /*
-         * ..else if lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD
-         * Then always map to guest account - as done below.
-         */
-      }
-
-      if (*smb_apasswd || !smb_getpwnam(user,True))
-         pstrcpy(user,lp_guestaccount(-1));
-      DEBUG(3,("Registered username %s for guest access\n",user));
-      guest = True;
-    }
-  }
-
-  if (!smb_getpwnam(user,True)) {
-    DEBUG(3,("No such user %s [%s] - using guest account\n",user, domain));
-    pstrcpy(user,lp_guestaccount(-1));
-    guest = True;
-  }
-
-  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,current_user_info.smb_name,domain,guest, full_name);
-  
-  if (sess_vuid == -1) {
-         return ERROR_DOS(ERRDOS,ERRnoaccess);
-  }
-
-  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
 ****************************************************************************/
@@ -1188,7 +650,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
   {
@@ -1272,7 +734,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);
   }
@@ -1283,7 +745,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);
@@ -1295,7 +757,7 @@ 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) {
@@ -1425,11 +887,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);
 }
@@ -1525,11 +987,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);
@@ -1640,11 +1102,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",
@@ -1669,13 +1131,13 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
   int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
   int tmpfd;
   SMB_STRUCT_STAT sbuf;
-  char *p;
+  char *p, *s;
 
   START_PROFILE(SMBctemp);
 
   createmode = SVAL(inbuf,smb_vwv0);
   srvstr_pull(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), -1, STR_TERMINATE);
-  pstrcat(fname,"/TMXXXXXX");
+  pstrcat(fname,"\\TMXXXXXX");
 
   RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
 
@@ -1701,10 +1163,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)
-    {
+       if (!fsp) {
+               if((errno == ENOENT) && bad_path) {
       unix_ERR_class = ERRDOS;
       unix_ERR_code = ERRbadpath;
     }
@@ -1714,17 +1174,28 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
 
   outsize = set_message(outbuf,1,0,True);
   SSVAL(outbuf,smb_vwv0,fsp->fnum);
-  CVAL(smb_buf(outbuf),0) = 4;
-  p = smb_buf(outbuf) + 1;
-  p += srvstr_push(outbuf, p, fname, -1, STR_TERMINATE);
-  set_message_end(outbuf, p);
+
+  /* the returned filename is relative to the directory */
+  s = strrchr_m(fname, '/');
+  if (!s) {
+         s = fname;
+  } else {
+         s++;
+  }
+
+  p = smb_buf(outbuf);
+  SSVALS(p, 0, -1); /* what is this? not in spec */
+  SSVAL(p, 2, strlen(s));
+  p += 4;
+  p += srvstr_push(outbuf, p, s, -1, STR_ASCII);
+  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;
+  if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
+         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",
@@ -1734,27 +1205,35 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
   return(outsize);
 }
 
-
 /*******************************************************************
-check if a user is allowed to delete a file
+ Check if a user is allowed to delete a file.
 ********************************************************************/
-static BOOL can_delete(char *fname,connection_struct *conn, int dirtype)
+
+static NTSTATUS can_delete(char *fname,connection_struct *conn, int dirtype)
 {
-  SMB_STRUCT_STAT sbuf;
-  int fmode;
+       SMB_STRUCT_STAT sbuf;
+       int fmode;
 
-  if (!CAN_WRITE(conn)) return(False);
+       if (!CAN_WRITE(conn))
+               return NT_STATUS_MEDIA_WRITE_PROTECTED;
 
-  if (conn->vfs_ops.lstat(conn,fname,&sbuf) != 0) return(False);
-  fmode = dos_mode(conn,fname,&sbuf);
-  if (fmode & aDIR) return(False);
-  if (!lp_delete_readonly(SNUM(conn))) {
-    if (fmode & aRONLY) return(False);
-  }
-  if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM))
-    return(False);
-  if (!check_file_sharing(conn,fname,False)) return(False);
-  return(True);
+       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 (!lp_delete_readonly(SNUM(conn))) {
+               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;
+
+       return NT_STATUS_OK;
 }
 
 /****************************************************************************
@@ -1762,14 +1241,13 @@ static BOOL can_delete(char *fname,connection_struct *conn, int dirtype)
  code.
 ****************************************************************************/
 
-int unlink_internals(connection_struct *conn, char *inbuf,char *outbuf,
-                    int dirtype, char *name)
+NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
 {
        pstring directory;
        pstring mask;
        char *p;
        int count=0;
-       int error = ERRnoaccess;
+       NTSTATUS error = NT_STATUS_OK;
        BOOL has_wild;
        BOOL exists=False;
        BOOL bad_path = False;
@@ -1807,9 +1285,9 @@ int unlink_internals(connection_struct *conn, char *inbuf,char *outbuf,
        if (!has_wild) {
                pstrcat(directory,"/");
                pstrcat(directory,mask);
-               if (!can_delete(directory,conn,dirtype)) {
-                       return ERROR_NT(NT_STATUS_SHARING_VIOLATION);
-               }
+               error = can_delete(directory,conn,dirtype);
+               if (!NT_STATUS_IS_OK(error)) return error;
+
                if (vfs_unlink(conn,directory) == 0) {
                        count++;
                }
@@ -1828,7 +1306,7 @@ int unlink_internals(connection_struct *conn, char *inbuf,char *outbuf,
                */
                
                if (dirptr) {
-                       error = ERRbadfile;
+                       error = NT_STATUS_OBJECT_NAME_NOT_FOUND;
                        
                        if (strequal(mask,"????????.???"))
                                pstrcpy(mask,"*");
@@ -1839,9 +1317,9 @@ int unlink_internals(connection_struct *conn, char *inbuf,char *outbuf,
                                
                                if(!mask_match(fname, mask, case_sensitive)) continue;
                                
-                               error = ERRnoaccess;
                                slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
-                               if (!can_delete(fname,conn,dirtype)) continue;
+                               error = can_delete(fname,conn,dirtype);
+                               if (!NT_STATUS_IS_OK(error)) continue;
                                if (vfs_unlink(conn,fname) == 0) count++;
                                DEBUG(3,("unlink_internals: succesful unlink [%s]\n",fname));
                        }
@@ -1849,19 +1327,11 @@ int unlink_internals(connection_struct *conn, char *inbuf,char *outbuf,
                }
        }
        
-       if (count == 0) {
-               if (exists)
-                       return ERROR_DOS(ERRDOS,error);
-               else {
-                       if((errno == ENOENT) && bad_path) {
-                               unix_ERR_class = ERRDOS;
-                               unix_ERR_code = ERRbadpath;
-                       }
-                       return(UNIXERROR(ERRDOS,error));
-               }
+       if (count == 0 && NT_STATUS_IS_OK(error)) {
+               error = map_nt_error_from_unix(errno);
        }
-       
-       return 0;
+
+       return error;
 }
 
 /****************************************************************************
@@ -1874,6 +1344,7 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
        int outsize = 0;
        pstring name;
        int dirtype;
+       NTSTATUS status;
        START_PROFILE(SMBunlink);
        
        dirtype = SVAL(inbuf,smb_vwv0);
@@ -1884,172 +1355,162 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
        
        DEBUG(3,("reply_unlink : %s\n",name));
        
-       outsize = unlink_internals(conn, inbuf, outbuf, dirtype, name);
-       if(outsize == 0) {
-               /*
-                * Win2k needs a changenotify request response before it will
-                * update after a rename..
-                */
-               process_pending_change_notify_queue((time_t)0);
-               
-               outsize = set_message(outbuf,0,0,True);
-       }
+       status = unlink_internals(conn, dirtype, name);
+       if (!NT_STATUS_IS_OK(status)) return ERROR_NT(status);
+
+       /*
+        * Win2k needs a changenotify request response before it will
+        * update after a rename..
+        */
+       process_pending_change_notify_queue((time_t)0);
+       
+       outsize = set_message(outbuf,0,0,True);
   
        END_PROFILE(SMBunlink);
        return outsize;
 }
 
+/****************************************************************************
+ Fail for readbraw.
+****************************************************************************/
+
+void fail_readraw(void)
+{
+       pstring errstr;
+       slprintf(errstr, sizeof(errstr)-1, "FAIL ! reply_readbraw: socket write fail (%s)",
+               strerror(errno) );
+       exit_server(errstr);
+}
 
 /****************************************************************************
-   reply to a readbraw (core+ protocol)
+ Reply to a readbraw (core+ protocol).
 ****************************************************************************/
 
 int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_size, int dum_buffsize)
 {
-  size_t maxcount,mincount;
-  size_t nread = 0;
-  SMB_OFF_T startpos;
-  char *header = outbuf;
-  ssize_t ret=0;
-  files_struct *fsp;
-  START_PROFILE(SMBreadbraw);
+       ssize_t maxcount,mincount;
+       size_t nread = 0;
+       SMB_OFF_T startpos;
+       char *header = outbuf;
+       ssize_t ret=0;
+       files_struct *fsp;
+       START_PROFILE(SMBreadbraw);
 
-  /*
-   * 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.
-   */
+       /*
+        * 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,smbd_server_fd(),(SMB_OFF_T)0,header,4,0);
-    DEBUG(5,("readbraw - oplock break finished\n"));
-    END_PROFILE(SMBreadbraw);
-    return -1;
-  }
+       if(global_oplock_break) {
+               _smb_setlen(header,0);
+               if (write_data(smbd_server_fd(),header,4) != 4)
+                       fail_readraw();
+               DEBUG(5,("readbraw - oplock break finished\n"));
+               END_PROFILE(SMBreadbraw);
+               return -1;
+       }
 
-  fsp = file_fsp(inbuf,smb_vwv0);
-
-  if (!FNUM_OK(fsp,conn) || !fsp->can_read) {
-         /*
-          * fsp could be NULL here so use the value from the packet. JRA.
-          */
-         DEBUG(3,("fnum %d not open in readbraw - cache prime?\n",(int)SVAL(inbuf,smb_vwv0)));
-         _smb_setlen(header,0);
-         transfer_file(0,smbd_server_fd(),(SMB_OFF_T)0,header,4,0);
-         END_PROFILE(SMBreadbraw);
-         return(-1);
-  }
+       fsp = file_fsp(inbuf,smb_vwv0);
 
-  CHECK_FSP(fsp,conn);
+       if (!FNUM_OK(fsp,conn) || !fsp->can_read) {
+               /*
+                * fsp could be NULL here so use the value from the packet. JRA.
+                */
+               DEBUG(3,("fnum %d not open in readbraw - cache prime?\n",(int)SVAL(inbuf,smb_vwv0)));
+               _smb_setlen(header,0);
+               if (write_data(smbd_server_fd(),header,4) != 4)
+                       fail_readraw();
+               END_PROFILE(SMBreadbraw);
+               return(-1);
+       }
 
-  flush_write_cache(fsp, READRAW_FLUSH);
+       CHECK_FSP(fsp,conn);
 
-  startpos = IVAL(inbuf,smb_vwv1);
-  if(CVAL(inbuf,smb_wct) == 10) {
-    /*
-     * This is a large offset (64 bit) read.
-     */
+       flush_write_cache(fsp, READRAW_FLUSH);
+
+       startpos = IVAL(inbuf,smb_vwv1);
+       if(CVAL(inbuf,smb_wct) == 10) {
+               /*
+                * This is a large offset (64 bit) read.
+                */
 #ifdef LARGE_SMB_OFF_T
 
-    startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv8)) << 32);
+               startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv8)) << 32);
 
 #else /* !LARGE_SMB_OFF_T */
 
-    /*
-     * Ensure we haven't been sent a >32 bit offset.
-     */
+               /*
+                * Ensure we haven't been sent a >32 bit offset.
+                */
 
-    if(IVAL(inbuf,smb_vwv8) != 0) {
-      DEBUG(0,("readbraw - large offset (%x << 32) used and we don't support \
+               if(IVAL(inbuf,smb_vwv8) != 0) {
+                       DEBUG(0,("readbraw - large offset (%x << 32) used and we don't support \
 64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv8) ));
-      _smb_setlen(header,0);
-      transfer_file(0,smbd_server_fd(),(SMB_OFF_T)0,header,4,0);
-      END_PROFILE(SMBreadbraw);
-      return(-1);
-    }
+                       _smb_setlen(header,0);
+                       if (write_data(smbd_server_fd(),header,4) != 4)
+                               fail_readraw();
+                       END_PROFILE(SMBreadbraw);
+                       return(-1);
+               }
 
 #endif /* LARGE_SMB_OFF_T */
 
-    if(startpos < 0) {
-      DEBUG(0,("readbraw - negative 64 bit readraw offset (%.0f) !\n",
-            (double)startpos ));
-         _smb_setlen(header,0);
-         transfer_file(0,smbd_server_fd(),(SMB_OFF_T)0,header,4,0);
-         END_PROFILE(SMBreadbraw);
-         return(-1);
-    }      
-  }
-  maxcount = (SVAL(inbuf,smb_vwv3) & 0xFFFF);
-  mincount = (SVAL(inbuf,smb_vwv4) & 0xFFFF);
+               if(startpos < 0) {
+                       DEBUG(0,("readbraw - negative 64 bit readraw offset (%.0f) !\n", (double)startpos ));
+                       _smb_setlen(header,0);
+                       if (write_data(smbd_server_fd(),header,4) != 4)
+                               fail_readraw();
+                       END_PROFILE(SMBreadbraw);
+                       return(-1);
+               }      
+       }
+       maxcount = (SVAL(inbuf,smb_vwv3) & 0xFFFF);
+       mincount = (SVAL(inbuf,smb_vwv4) & 0xFFFF);
 
-  /* ensure we don't overrun the packet size */
-  maxcount = MIN(65535,maxcount);
-  maxcount = MAX(mincount,maxcount);
+       /* ensure we don't overrun the packet size */
+       maxcount = MIN(65535,maxcount);
+       maxcount = MAX(mincount,maxcount);
 
-  if (!is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK,False))
-  {
-    SMB_OFF_T size = fsp->size;
-    SMB_OFF_T sizeneeded = startpos + maxcount;
-           
-    if (size < sizeneeded)
-    {
-      SMB_STRUCT_STAT st;
-      if (vfs_fstat(fsp,fsp->fd,&st) == 0)
-        size = st.st_size;
-      if (!fsp->can_write) 
-        fsp->size = size;
-    }
+       if (!is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
+               SMB_OFF_T size = fsp->size;
+               SMB_OFF_T sizeneeded = startpos + maxcount;
+  
+               if (size < sizeneeded) {
+                       SMB_STRUCT_STAT st;
+                       if (vfs_fstat(fsp,fsp->fd,&st) == 0)
+                               size = st.st_size;
+                       if (!fsp->can_write) 
+                               fsp->size = size;
+               }
 
-    nread = MIN(maxcount,(size - startpos));     
-  }
+               if (startpos >= size)
+                       nread = 0;
+               else
+                       nread = MIN(maxcount,(size - startpos));          
+       }
 
-  if (nread < mincount)
-    nread = 0;
+       if (nread < mincount)
+               nread = 0;
   
-  DEBUG( 3, ( "readbraw fnum=%d start=%.0f max=%d min=%d nread=%d\n",
-             fsp->fnum, (double)startpos,
-             (int)maxcount, (int)mincount, (int)nread ) );
+       DEBUG( 3, ( "readbraw fnum=%d start=%.0f max=%d min=%d nread=%d\n", fsp->fnum, (double)startpos,
+                               (int)maxcount, (int)mincount, (int)nread ) );
   
-#if UNSAFE_READRAW
-  {
-    BOOL seek_fail = False;
-    int predict=0;
-    _smb_setlen(header,nread);
-
-    if ((nread-predict) > 0) {
-      if(conn->vfs_ops.seek(fsp,fsp->fd,startpos + predict) == -1) {
-        DEBUG(0,("reply_readbraw: ERROR: seek_file failed.\n"));
-        ret = 0;
-        seek_fail = True;
-      } 
-    }
-
-    if(!seek_fail)
-      ret = (ssize_t)vfs_transfer_file(-1, fsp, fsp->fd, Client, NULL,
-                                   (SMB_OFF_T)(nread-predict),header,4+predict, 
-                                   startpos+predict);
-  }
-
-  if (ret != nread+4)
-    DEBUG(0,("ERROR: file read failure on %s at %d for %d bytes (%d)\n",
-            fsp->fsp_name,startpos,nread,ret));
-
-#else /* UNSAFE_READRAW */
-  ret = read_file(fsp,header+4,startpos,nread);
-  if (ret < mincount) ret = 0;
+       if (nread > 0) {
+               ret = read_file(fsp,header+4,startpos,nread);
+               if (ret < mincount)
+                       ret = 0;
+       }
 
-  _smb_setlen(header,ret);
-  transfer_file(0,smbd_server_fd(),0,header,4+ret,0);
-#endif /* UNSAFE_READRAW */
+       _smb_setlen(header,ret);
+       if (write_data(smbd_server_fd(),header,4+ret) != 4+ret)
+               fail_readraw();
 
-  DEBUG(5,("readbraw finished\n"));
-  END_PROFILE(SMBreadbraw);
-  return -1;
+       DEBUG(5,("readbraw finished\n"));
+       END_PROFILE(SMBreadbraw);
+       return -1;
 }
 
-
 /****************************************************************************
   reply to a lockread (core+ protocol)
 ****************************************************************************/
@@ -2086,7 +1547,7 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
        status = do_lock(fsp, conn, SVAL(inbuf,smb_pid), 
                         (SMB_BIG_UINT)numtoread, (SMB_BIG_UINT)startpos, WRITE_LOCK);
 
-       if (status != NT_STATUS_NOPROBLEMO) {
+       if (NT_STATUS_V(status)) {
                if (lp_blocking_locks(SNUM(conn))) {
                        /*
                         * A blocking lock was requested. Package up
@@ -2162,7 +1623,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",
@@ -2250,114 +1711,126 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
 
 int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
 {
-  ssize_t nwritten=0;
-  ssize_t total_written=0;
-  size_t numtowrite=0;
-  size_t tcount;
-  SMB_OFF_T startpos;
-  char *data=NULL;
-  BOOL write_through;
-  files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-  int outsize = 0;
-  START_PROFILE(SMBwritebraw);
+       ssize_t nwritten=0;
+       ssize_t total_written=0;
+       size_t numtowrite=0;
+       size_t tcount;
+       SMB_OFF_T startpos;
+       char *data=NULL;
+       BOOL write_through;
+       files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+       int outsize = 0;
+       START_PROFILE(SMBwritebraw);
 
-  CHECK_FSP(fsp,conn);
-  CHECK_WRITE(fsp);
+       CHECK_FSP(fsp,conn);
+       CHECK_WRITE(fsp);
   
-  tcount = IVAL(inbuf,smb_vwv1);
-  startpos = IVAL(inbuf,smb_vwv3);
-  write_through = BITSETW(inbuf+smb_vwv7,0);
-
-  /* We have to deal with slightly different formats depending
-     on whether we are using the core+ or lanman1.0 protocol */
-  if(Protocol <= PROTOCOL_COREPLUS) {
-    numtowrite = SVAL(smb_buf(inbuf),-2);
-    data = smb_buf(inbuf);
-  } else {
-    numtowrite = SVAL(inbuf,smb_vwv10);
-    data = smb_base(inbuf) + SVAL(inbuf, smb_vwv11);
-  }
+       tcount = IVAL(inbuf,smb_vwv1);
+       startpos = IVAL(inbuf,smb_vwv3);
+       write_through = BITSETW(inbuf+smb_vwv7,0);
 
-  /* force the error type */
-  CVAL(inbuf,smb_com) = SMBwritec;
-  CVAL(outbuf,smb_com) = SMBwritec;
+       /* We have to deal with slightly different formats depending
+               on whether we are using the core+ or lanman1.0 protocol */
 
-  if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
-    END_PROFILE(SMBwritebraw);
-    return ERROR_DOS(ERRDOS,ERRlock);
-  }
+       if(Protocol <= PROTOCOL_COREPLUS) {
+               numtowrite = SVAL(smb_buf(inbuf),-2);
+               data = smb_buf(inbuf);
+       } else {
+               numtowrite = SVAL(inbuf,smb_vwv10);
+               data = smb_base(inbuf) + SVAL(inbuf, smb_vwv11);
+       }
 
-  if (numtowrite>0)
-    nwritten = write_file(fsp,data,startpos,numtowrite);
+       /* force the error type */
+       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);
+               return(ERROR_DOS(ERRDOS,ERRlock));
+       }
+
+       if (numtowrite>0)
+               nwritten = write_file(fsp,data,startpos,numtowrite);
   
-  DEBUG(3,("writebraw1 fnum=%d start=%.0f num=%d wrote=%d sync=%d\n",
-          fsp->fnum, (double)startpos, (int)numtowrite, (int)nwritten, (int)write_through));
+       DEBUG(3,("writebraw1 fnum=%d start=%.0f num=%d wrote=%d sync=%d\n",
+               fsp->fnum, (double)startpos, (int)numtowrite, (int)nwritten, (int)write_through));
 
-  if (nwritten < numtowrite)  {
-    END_PROFILE(SMBwritebraw);
-    return(UNIXERROR(ERRHRD,ERRdiskfull));
-  }
+       if (nwritten < numtowrite)  {
+               END_PROFILE(SMBwritebraw);
+               return(UNIXERROR(ERRHRD,ERRdiskfull));
+       }
 
-  total_written = nwritten;
+       total_written = nwritten;
 
-  /* Return a message to the redirector to tell it
-     to send more bytes */
-  CVAL(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");
+       /* Return a message to the redirector to tell it to send more bytes */
+       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.");
   
-  /* Now read the raw data into the buffer and write it */
-  if (read_smb_length(smbd_server_fd(),inbuf,SMB_SECONDARY_WAIT) == -1) {
-    exit_server("secondary writebraw failed");
-  }
+       /* Now read the raw data into the buffer and write it */
+       if (read_smb_length(smbd_server_fd(),inbuf,SMB_SECONDARY_WAIT) == -1) {
+               exit_server("secondary writebraw failed");
+       }
   
-  /* Even though this is not an smb message, smb_len
-     returns the generic length of an smb message */
-  numtowrite = smb_len(inbuf);
+       /* Even though this is not an smb message, smb_len returns the generic length of an smb message */
+       numtowrite = smb_len(inbuf);
 
-  if (tcount > nwritten+numtowrite) {
-    DEBUG(3,("Client overestimated the write %d %d %d\n",
-            (int)tcount,(int)nwritten,(int)numtowrite));
-  }
+       /* Set up outbuf to return the correct return */
+       outsize = set_message(outbuf,1,0,True);
+       SCVAL(outbuf,smb_com,SMBwritec);
+       SSVAL(outbuf,smb_vwv0,total_written);
 
-  nwritten = vfs_transfer_file(smbd_server_fd(), NULL, -1, fsp,
-                              (SMB_OFF_T)numtowrite,NULL,0, 
-                              startpos+nwritten);
-  total_written += nwritten;
-  
-  /* Set up outbuf to return the correct return */
-  outsize = set_message(outbuf,1,0,True);
-  CVAL(outbuf,smb_com) = SMBwritec;
-  SSVAL(outbuf,smb_vwv0,total_written);
+       if (numtowrite != 0) {
 
-  if (nwritten < (ssize_t)numtowrite) {
-    CVAL(outbuf,smb_rcls) = ERRHRD;
-    SSVAL(outbuf,smb_err,ERRdiskfull);      
-  }
+               if (numtowrite > BUFFER_SIZE) {
+                       DEBUG(0,("reply_writebraw: Oversize secondary write raw requested (%u). Terminating\n",
+                               (unsigned int)numtowrite ));
+                       exit_server("secondary writebraw failed");
+               }
 
-  if ((lp_syncalways(SNUM(conn)) || write_through) && 
-      lp_strict_sync(SNUM(conn)))
-      sync_file(conn,fsp);
+               if (tcount > nwritten+numtowrite) {
+                       DEBUG(3,("Client overestimated the write %d %d %d\n",
+                               (int)tcount,(int)nwritten,(int)numtowrite));
+               }
 
-  DEBUG(3,("writebraw2 fnum=%d start=%.0f num=%d wrote=%d\n",
-          fsp->fnum, (double)startpos, (int)numtowrite,(int)total_written));
+               if (read_data( smbd_server_fd(), inbuf+4, numtowrite) != numtowrite ) {
+                       DEBUG(0,("reply_writebraw: Oversize secondary write raw read failed (%s). Terminating\n",
+                               strerror(errno) ));
+                       exit_server("secondary writebraw failed");
+               }
 
-  /* 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) {
-    /*
-     * 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");
-    return(-1);
-  }
+               nwritten = write_file(fsp,inbuf+4,startpos+nwritten,numtowrite);
 
-  return(outsize);
+               if (nwritten < (ssize_t)numtowrite) {
+                       SCVAL(outbuf,smb_rcls,ERRHRD);
+                       SSVAL(outbuf,smb_err,ERRdiskfull);      
+               }
+
+               if (nwritten > 0)
+                       total_written += nwritten;
+       }
+       if ((lp_syncalways(SNUM(conn)) || write_through) && lp_strict_sync(SNUM(conn)))
+               sync_file(conn,fsp);
+
+       DEBUG(3,("writebraw2 fnum=%d start=%.0f num=%d wrote=%d\n",
+               fsp->fnum, (double)startpos, (int)numtowrite,(int)total_written));
+
+       /* 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) {
+               /*
+                * 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");
+               return(-1);
+       }
+
+       return(outsize);
 }
 
 /****************************************************************************
@@ -2407,7 +1880,7 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf,
 
        status = do_unlock(fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtowrite, 
                           (SMB_BIG_UINT)startpos);
-       if (status != NT_STATUS_NOPROBLEMO) {
+       if (NT_STATUS_V(status)) {
                END_PROFILE(SMBwriteunlock);
                return ERROR_NT(status);
        }
@@ -2430,67 +1903,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);
 }
 
 
@@ -2579,7 +2061,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);      
   }
 
@@ -2759,21 +2241,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,
@@ -2790,6 +2261,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 */
@@ -2885,8 +2366,8 @@ int reply_lock(connection_struct *conn,
                 fsp->fd, fsp->fnum, (double)offset, (double)count));
 
        status = do_lock(fsp, conn, SVAL(inbuf,smb_pid), count, offset, WRITE_LOCK);
-       if (status != NT_STATUS_NOPROBLEMO) {
-               if (status != NT_STATUS_NOPROBLEMO && lp_blocking_locks(SNUM(conn))) {
+       if (NT_STATUS_V(status)) {
+               if (lp_blocking_locks(SNUM(conn))) {
                        /*
                         * A blocking lock was requested. Package up
                         * this smb into a queued request and push it
@@ -2924,7 +2405,7 @@ int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size,
        offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3);
        
        status = do_unlock(fsp, conn, SVAL(inbuf,smb_pid), count, offset);
-       if (status != NT_STATUS_NOPROBLEMO) {
+       if (NT_STATUS_V(status)) {
                END_PROFILE(SMBunlock);
                return ERROR_NT(status);
        }
@@ -2994,7 +2475,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));
@@ -3022,7 +2503,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);
@@ -3096,7 +2577,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",
@@ -3104,8 +2585,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;
@@ -3118,10 +2600,10 @@ 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;
+                       SCVAL(p,11,0);
                        srvstr_push(outbuf, p+12, queue[i].user, 16, STR_ASCII);
                        p += 28;
                }
@@ -3130,11 +2612,11 @@ 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);
                }
 
-               if (queue) free(queue);
+               SAFE_FREE(queue);
          
                DEBUG(3,("%d entries returned in queue\n",count));
        }
@@ -3182,111 +2664,102 @@ int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_
  The guts of the mkdir command, split out so it may be called by the NT SMB
  code. 
 ****************************************************************************/
-int mkdir_internal(connection_struct *conn, char *inbuf, char *outbuf, pstring directory)
+NTSTATUS mkdir_internal(connection_struct *conn, pstring directory)
 {
-  BOOL bad_path = False;
-  SMB_STRUCT_STAT sbuf;
-  int ret= -1;
-  
-  unix_convert(directory,conn,0,&bad_path,&sbuf);
-  
-  if (check_name(directory, conn))
-    ret = vfs_mkdir(conn,directory,unix_mode(conn,aDIR,directory));
-  
-  if (ret < 0)
-  {
-    if((errno == ENOENT) && bad_path)
-    {
-      unix_ERR_class = ERRDOS;
-      unix_ERR_code = ERRbadpath;
-    }
-    return(UNIXERROR(ERRDOS,ERRnoaccess));
-  }
-
-  return ret;
+       BOOL bad_path = False;
+       SMB_STRUCT_STAT sbuf;
+       int ret= -1;
+       
+       unix_convert(directory,conn,0,&bad_path,&sbuf);
+       
+       if (check_name(directory, conn))
+               ret = vfs_mkdir(conn,directory,unix_mode(conn,aDIR,directory));
+       
+       if (ret == -1) {
+               return map_nt_error_from_unix(errno);
+       }
+       
+       return NT_STATUS_OK;
 }
 
 /****************************************************************************
-  reply to a mkdir
+ Reply to a mkdir.
 ****************************************************************************/
+
 int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
-  pstring directory;
-  int outsize;
-  START_PROFILE(SMBmkdir);
+       pstring directory;
+       int outsize;
+       NTSTATUS status;
+       START_PROFILE(SMBmkdir);
  
-  srvstr_pull(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), -1, STR_TERMINATE);
+       srvstr_pull(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), -1, STR_TERMINATE);
 
-  outsize=mkdir_internal(conn, inbuf, outbuf, directory);
-  if(outsize == 0)
-    outsize = set_message(outbuf,0,0,True);
+       status = mkdir_internal(conn, directory);
+       if (!NT_STATUS_IS_OK(status))
+               return ERROR_NT(status);
+
+       outsize = set_message(outbuf,0,0,True);
 
-  DEBUG( 3, ( "mkdir %s ret=%d\n", directory, outsize ) );
+       DEBUG( 3, ( "mkdir %s ret=%d\n", directory, outsize ) );
 
-  END_PROFILE(SMBmkdir);
-  return(outsize);
+       END_PROFILE(SMBmkdir);
+       return(outsize);
 }
 
 /****************************************************************************
-Static function used by reply_rmdir to delete an entire directory
-tree recursively.
+ Static function used by reply_rmdir to delete an entire directory
+ tree recursively. Return False on ok, True on fail.
 ****************************************************************************/
 
 static BOOL recursive_rmdir(connection_struct *conn, char *directory)
 {
-  char *dname = NULL;
-  BOOL ret = False;
-  void *dirptr = OpenDir(NULL, directory, False);
+       char *dname = NULL;
+       BOOL ret = False;
+       void *dirptr = OpenDir(conn, directory, False);
 
-  if(dirptr == NULL)
-    return True;
+       if(dirptr == NULL)
+               return True;
 
-  while((dname = ReadDirName(dirptr)))
-  {
-    pstring fullname;
-    SMB_STRUCT_STAT st;
+       while((dname = ReadDirName(dirptr))) {
+               pstring fullname;
+               SMB_STRUCT_STAT st;
 
-    if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
-      continue;
+               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;
-    }
-    pstrcpy(fullname, directory);
-    pstrcat(fullname, "/");
-    pstrcat(fullname, dname);
+               /* Construct the full name. */
+               if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname)) {
+                       errno = ENOMEM;
+                       ret = True;
+                       break;
+               }
 
-    if(conn->vfs_ops.lstat(conn,fullname, &st) != 0)
-    {
-      ret = True;
-      break;
-    }
+               pstrcpy(fullname, directory);
+               pstrcat(fullname, "/");
+               pstrcat(fullname, dname);
 
-    if(st.st_mode & S_IFDIR)
-    {
-      if(recursive_rmdir(conn, fullname)!=0)
-      {
-        ret = True;
-        break;
-      }
-      if(vfs_rmdir(conn,fullname) != 0)
-      {
-        ret = True;
-        break;
-      }
-    }
-    else if(vfs_unlink(conn,fullname) != 0)
-    {
-      ret = True;
-      break;
-    }
-  }
-  CloseDir(dirptr);
-  return ret;
+               if(conn->vfs_ops.lstat(conn,fullname, &st) != 0) {
+                       ret = True;
+                       break;
+               }
+
+               if(st.st_mode & S_IFDIR) {
+                       if(recursive_rmdir(conn, fullname)!=0) {
+                               ret = True;
+                               break;
+                       }
+                       if(vfs_rmdir(conn,fullname) != 0) {
+                               ret = True;
+                               break;
+                       }
+               } else if(vfs_unlink(conn,fullname) != 0) {
+                       ret = True;
+                       break;
+               }
+       }
+       CloseDir(dirptr);
+       return ret;
 }
 
 /****************************************************************************
@@ -3295,86 +2768,77 @@ static BOOL recursive_rmdir(connection_struct *conn, char *directory)
 
 BOOL rmdir_internals(connection_struct *conn, char *directory)
 {
-  BOOL ok;
+       BOOL ok;
+
+       ok = (vfs_rmdir(conn,directory) == 0);
+       if(!ok && ((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn))) {
+               /* 
+                * 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(conn, directory, False);
 
-  ok = (vfs_rmdir(conn,directory) == 0);
-  if(!ok && ((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn)))
-  {
-    /* 
-     * 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(conn, 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(conn, dname)) {
+                                       all_veto_files = False;
+                                       break;
+                               }
+                       }
 
-    if(dirptr != NULL)
-    {
-      int dirpos = TellDir(dirptr);
-      while ((dname = ReadDirName(dirptr)))
-      {
-        if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
-          continue;
-        if(!IS_VETO_PATH(conn, dname))
-        {
-          all_veto_files = False;
-          break;
-        }
-      }
-      if(all_veto_files)
-      {
-        SeekDir(dirptr,dirpos);
-        while ((dname = ReadDirName(dirptr)))
-        {
-          pstring fullname;
-          SMB_STRUCT_STAT st;
+                       if(all_veto_files) {
+                               SeekDir(dirptr,dirpos);
+                               while ((dname = ReadDirName(dirptr))) {
+                                       pstring fullname;
+                                       SMB_STRUCT_STAT st;
 
-          if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
-            continue;
+                                       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);
-          pstrcat(fullname, "/");
-          pstrcat(fullname, dname);
+                                       /* Construct the full name. */
+                                       if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname)) {
+                                               errno = ENOMEM;
+                                               break;
+                                       }
+
+                                       pstrcpy(fullname, directory);
+                                       pstrcat(fullname, "/");
+                                       pstrcat(fullname, dname);
                      
-          if(conn->vfs_ops.lstat(conn,fullname, &st) != 0)
-            break;
-          if(st.st_mode & S_IFDIR)
-          {
-            if(lp_recursive_veto_delete(SNUM(conn)))
-            {
-              if(recursive_rmdir(conn, fullname) != 0)
-                break;
-            }
-            if(vfs_rmdir(conn,fullname) != 0)
-              break;
-          }
-          else if(vfs_unlink(conn,fullname) != 0)
-            break;
-        }
-        CloseDir(dirptr);
-        /* Retry the rmdir */
-        ok = (vfs_rmdir(conn,directory) == 0);
-      }
-      else
-        CloseDir(dirptr);
-    }
-    else
-      errno = ENOTEMPTY;
-  }
-          
-  if (!ok)
-    DEBUG(3,("rmdir_internals: couldn't remove directory %s : %s\n",
-          directory,strerror(errno)));
+                                       if(conn->vfs_ops.lstat(conn,fullname, &st) != 0)
+                                               break;
+                                       if(st.st_mode & S_IFDIR) {
+                                               if(lp_recursive_veto_delete(SNUM(conn))) {
+                                                       if(recursive_rmdir(conn, fullname) != 0)
+                                                               break;
+                                               }
+                                               if(vfs_rmdir(conn,fullname) != 0)
+                                                       break;
+                                       } else if(vfs_unlink(conn,fullname) != 0)
+                                               break;
+                               }
+                               CloseDir(dirptr);
+                               /* Retry the rmdir */
+                               ok = (vfs_rmdir(conn,directory) == 0);
+                       } else {
+                               CloseDir(dirptr);
+                       }
+               } else {
+                       errno = ENOTEMPTY;
+               }
+       }
+
+       if (!ok)
+               DEBUG(3,("rmdir_internals: couldn't remove directory %s : %s\n", directory,strerror(errno)));
 
-  return ok;
+       return ok;
 }
 
 /****************************************************************************
@@ -3487,26 +2951,26 @@ static BOOL resolve_wildcards(char *name1,char *name2)
 }
 
 /*******************************************************************
-check if a user is allowed to rename a file
+ Check if a user is allowed to rename a file.
 ********************************************************************/
-static BOOL can_rename(char *fname,connection_struct *conn)
+
+static NTSTATUS can_rename(char *fname,connection_struct *conn)
 {
-  SMB_STRUCT_STAT sbuf;
+       if (!CAN_WRITE(conn))
+               return NT_STATUS_ACCESS_DENIED;
 
-  if (!CAN_WRITE(conn)) return(False);
+       if (!check_file_sharing(conn,fname,True))
+               return NT_STATUS_SHARING_VIOLATION;
 
-  if (conn->vfs_ops.lstat(conn,fname,&sbuf) != 0) return(False);
-  if (!check_file_sharing(conn,fname,True)) return(False);
-  return(True);
+       return NT_STATUS_OK;
 }
 
 /****************************************************************************
  The guts of the rename command, split out so it may be called by the NT SMB
  code. 
 ****************************************************************************/
-int rename_internals(connection_struct *conn, 
-                    char *inbuf, char *outbuf, 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;
@@ -3516,8 +2980,7 @@ int rename_internals(connection_struct *conn,
        BOOL bad_path1 = False;
        BOOL bad_path2 = False;
        int count=0;
-       int error = ERRnoaccess;
-       BOOL exists=False;
+       NTSTATUS error = NT_STATUS_OK;
        BOOL rc = True;
        SMB_STRUCT_STAT sbuf1, sbuf2;
 
@@ -3555,8 +3018,20 @@ int rename_internals(connection_struct *conn,
         * Tine Smukavec <valentin.smukavec@hermes.si>.
         */
 
+#if 0
        if (!rc && is_mangled(mask))
                check_mangled_cache( mask );
+#endif
+       if (!rc)
+       {
+               char *unmangled;
+               
+               unmangled = dos_unmangle(mask);
+               if (unmangled)
+                       strncpy(mask, unmangled, strlen(unmangled) + 1);
+                       
+               SAFE_FREE(unmangled);
+       }
 
        has_wild = ms_has_wild(mask);
 
@@ -3579,7 +3054,8 @@ int 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));
 
@@ -3616,34 +3092,77 @@ int 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))
-                               count++;
-               } else {
-                       if (resolve_wildcards(directory,newname) && 
-                           can_rename(directory,conn) && 
-                           !vfs_file_exist(conn,newname,NULL) &&
-                           !conn->vfs_ops.rename(conn,directory,newname))
-                               count++;
+               if (!vfs_object_exist(conn, directory, NULL)) {
+                       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",
+                               get_nt_error_msg(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 = ERRrename;
+               error = can_rename(directory,conn);
+
+               if (!NT_STATUS_IS_OK(error)) {
+                       DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
+                               get_nt_error_msg(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",
+                       get_nt_error_msg(error), directory,newname));
+
+               return error;
        } else {
                /*
                 * Wildcards - process each file that matches.
@@ -3656,7 +3175,7 @@ int rename_internals(connection_struct *conn,
                        dirptr = OpenDir(conn, directory, True);
                
                if (dirptr) {
-                       error = ERRbadfile;
+                       error = NT_STATUS_OBJECT_NAME_NOT_FOUND;
                        
                        if (strequal(mask,"????????.???"))
                                pstrcpy(mask,"*");
@@ -3669,9 +3188,10 @@ int rename_internals(connection_struct *conn,
                                if(!mask_match(fname, mask, case_sensitive))
                                        continue;
                                
-                               error = ERRnoaccess;
+                               error = NT_STATUS_ACCESS_DENIED;
                                slprintf(fname,sizeof(fname)-1,"%s/%s",directory,dname);
-                               if (!can_rename(fname,conn)) {
+                               error = can_rename(fname,conn);
+                               if (!NT_STATUS_IS_OK(error)) {
                                        DEBUG(6,("rename %s refused\n", fname));
                                        continue;
                                }
@@ -3686,7 +3206,7 @@ int rename_internals(connection_struct *conn,
                                if (!replace_if_exists && 
                                     vfs_file_exist(conn,destname, NULL)) {
                                        DEBUG(6,("file_exist %s\n", destname));
-                                       error = 183;
+                                       error = NT_STATUS_OBJECT_NAME_COLLISION;
                                        continue;
                                }
                                
@@ -3698,137 +3218,132 @@ int rename_internals(connection_struct *conn,
                }
        }
        
-       if (count == 0) {
-               if (exists)
-                       return ERROR_DOS(ERRDOS,error);
-               else {
-                       if((errno == ENOENT) && (bad_path1 || bad_path2)) {
-                               unix_ERR_class = ERRDOS;
-                               unix_ERR_code = ERRbadpath;
-                       }
-                       return(UNIXERROR(ERRDOS,error));
-               }
+       if (count == 0 && NT_STATUS_IS_OK(error)) {
+               error = map_nt_error_from_unix(errno);
        }
        
-       return 0;
+       return error;
 }
 
 /****************************************************************************
  Reply to a mv.
 ****************************************************************************/
 
-int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, 
+            int dum_buffsize)
 {
-  int outsize = 0;
-  pstring name;
-  pstring newname;
-  char *p;
-
-  START_PROFILE(SMBmv);
-
-  p = smb_buf(inbuf) + 1;
-  p += srvstr_pull(inbuf, name, p, sizeof(name), -1, STR_TERMINATE);
-  p++;
-  p += srvstr_pull(inbuf, newname, p, sizeof(newname), -1, STR_TERMINATE);
-
-  RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
-  RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
+       int outsize = 0;
+       pstring name;
+       pstring newname;
+       char *p;
+       NTSTATUS status;
 
-  DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
+       START_PROFILE(SMBmv);
 
-  outsize = rename_internals(conn, inbuf, outbuf, name, newname, False);
-  if(outsize == 0) {
+       p = smb_buf(inbuf) + 1;
+       p += srvstr_pull(inbuf, name, p, sizeof(name), -1, STR_TERMINATE);
+       p++;
+       p += srvstr_pull(inbuf, newname, p, sizeof(newname), -1, STR_TERMINATE);
+       
+       RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
+       RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
+       
+       DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
+       
+       status = rename_internals(conn, name, newname, False);
+       if (!NT_STATUS_IS_OK(status)) {
+               return ERROR_NT(status);
+       }
 
        /*
-     * Win2k needs a changenotify request response before it will
-     * update after a rename..
-     */
-
-    process_pending_change_notify_queue((time_t)0);
-
-    outsize = set_message(outbuf,0,0,True);
-  }
+        * Win2k needs a changenotify request response before it will
+        * update after a rename..
+        */     
+       process_pending_change_notify_queue((time_t)0);
+       outsize = set_message(outbuf,0,0,True);
   
-  END_PROFILE(SMBmv);
-  return(outsize);
+       END_PROFILE(SMBmv);
+       return(outsize);
 }
 
 /*******************************************************************
-  copy a file as part of a reply_copy
-  ******************************************************************/
+ Copy a file as part of a reply_copy.
+******************************************************************/
 
 static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
                      int count,BOOL target_is_directory, int *err_ret)
 {
-  int Access,action;
-  SMB_STRUCT_STAT src_sbuf, sbuf2;
-  SMB_OFF_T ret=-1;
-  files_struct *fsp1,*fsp2;
-  pstring dest;
+       int Access,action;
+       SMB_STRUCT_STAT src_sbuf, sbuf2;
+       SMB_OFF_T ret=-1;
+       files_struct *fsp1,*fsp2;
+       pstring dest;
   
-  *err_ret = 0;
+       *err_ret = 0;
 
-  pstrcpy(dest,dest1);
-  if (target_is_directory) {
-    char *p = strrchr_m(src,'/');
-    if (p) 
-      p++;
-    else
-      p = src;
-    pstrcat(dest,"/");
-    pstrcat(dest,p);
-  }
+       pstrcpy(dest,dest1);
+       if (target_is_directory) {
+               char *p = strrchr_m(src,'/');
+               if (p) 
+                       p++;
+               else
+                       p = src;
+               pstrcat(dest,"/");
+               pstrcat(dest,p);
+       }
 
-  if (!vfs_file_exist(conn,src,&src_sbuf))
-    return(False);
+       if (!vfs_file_exist(conn,src,&src_sbuf))
+               return(False);
 
-  fsp1 = open_file_shared(conn,src,&src_sbuf,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY),
-                  (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),0,0,&Access,&action);
+       fsp1 = open_file_shared(conn,src,&src_sbuf,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY),
+                                       (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),0,0,&Access,&action);
 
-  if (!fsp1) {
-         return(False);
-  }
+       if (!fsp1)
+               return(False);
 
-  if (!target_is_directory && count)
-    ofun = FILE_EXISTS_OPEN;
+       if (!target_is_directory && count)
+               ofun = FILE_EXISTS_OPEN;
 
-  vfs_stat(conn,dest,&sbuf2);
-  fsp2 = open_file_shared(conn,dest,&sbuf2,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_WRONLY),
-                  ofun,src_sbuf.st_mode,0,&Access,&action);
+       if (vfs_stat(conn,dest,&sbuf2) == -1)
+               ZERO_STRUCTP(&sbuf2);
 
-  if (!fsp2) {
-    close_file(fsp1,False);
-    return(False);
-  }
+       fsp2 = open_file_shared(conn,dest,&sbuf2,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_WRONLY),
+                       ofun,src_sbuf.st_mode,0,&Access,&action);
 
-  if ((ofun&3) == 1) {
-    if(conn->vfs_ops.lseek(fsp2,fsp2->fd,0,SEEK_END) == -1) {
-      DEBUG(0,("copy_file: error - sys_lseek returned error %s\n",
-               strerror(errno) ));
-      /*
-       * Stop the copy from occurring.
-       */
-      ret = -1;
-      src_sbuf.st_size = 0;
-    }
-  }
+       if (!fsp2) {
+               close_file(fsp1,False);
+               return(False);
+       }
+
+       if ((ofun&3) == 1) {
+               if(conn->vfs_ops.lseek(fsp2,fsp2->fd,0,SEEK_END) == -1) {
+                       DEBUG(0,("copy_file: error - vfs lseek returned error %s\n", strerror(errno) ));
+                       /*
+                        * Stop the copy from occurring.
+                        */
+                       ret = -1;
+                       src_sbuf.st_size = 0;
+               }
+       }
   
-  if (src_sbuf.st_size)
-    ret = vfs_transfer_file(-1, fsp1, -1, fsp2, src_sbuf.st_size, NULL, 0, 0);
+       if (src_sbuf.st_size)
+               ret = vfs_transfer_file(fsp1, fsp2, src_sbuf.st_size);
 
-  close_file(fsp1,False);
-  /*
-   * As we are opening fsp1 read-only we only expect
-   * an error on close on fsp2 if we are out of space.
-   * Thus we don't look at the error return from the
-   * close of fsp1.
-   */
-  *err_ret = close_file(fsp2,False);
+       close_file(fsp1,False);
 
-  return(ret == (SMB_OFF_T)src_sbuf.st_size);
-}
+       /* 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.
+        * Thus we don't look at the error return from the
+        * close of fsp1.
+        */
+       *err_ret = close_file(fsp2,False);
 
+       return(ret == (SMB_OFF_T)src_sbuf.st_size);
+}
 
 /****************************************************************************
   reply to a file copy.
@@ -3914,8 +3429,21 @@ 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 0
+       if (!rc && is_mangled(mask))
+               check_mangled_cache( mask );
+#endif
+       if (!rc)
+       {
+               char *unmangled;
+               
+               unmangled = dos_unmangle(mask);
+               if (unmangled)
+                       strncpy(mask, unmangled, strlen(unmangled) + 1);
+                       
+               SAFE_FREE(unmangled);
+       }
+
 
   has_wild = ms_has_wild(mask);
 
@@ -4028,7 +3556,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));
 
@@ -4045,7 +3573,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));
 }
 
 /****************************************************************************
@@ -4086,6 +3614,39 @@ SMB_BIG_UINT get_lock_count( char *data, int data_offset, BOOL large_file_format
   return count;
 }
 
+#if !defined(HAVE_LONGLONG)
+/****************************************************************************
+ Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
+****************************************************************************/
+static uint32 map_lock_offset(uint32 high, uint32 low)
+{
+       unsigned int i;
+       uint32 mask = 0;
+       uint32 highcopy = high;
+       /*
+        * Try and find out how many significant bits there are in high.
+        */
+       for(i = 0; highcopy; i++)
+               highcopy >>= 1;
+       /*
+        * We use 31 bits not 32 here as POSIX
+        * lock offsets may not be negative.
+        */
+       mask = (~0) << (31 - i);
+       if(low & mask)
+               return 0; /* Fail. */
+       high <<= (31 - i);
+       return (high|low);
+}
+#endif /* !defined(HAVE_LONGLONG) */
+
 /****************************************************************************
  Get a lock offset, dealing with large offset requests.
 ****************************************************************************/
@@ -4232,7 +3793,7 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
                          (double)offset, (double)count, (unsigned int)lock_pid, fsp->fsp_name ));
                
                status = do_unlock(fsp,conn,lock_pid,count,offset);
-               if (status != NT_STATUS_NOPROBLEMO) {
+               if (NT_STATUS_V(status)) {
                        END_PROFILE(SMBlockingX);
                        return ERROR_NT(status);
                }
@@ -4265,7 +3826,7 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
                
                status = do_lock(fsp,conn,lock_pid, count,offset, 
                                 ((locktype & 1) ? READ_LOCK : WRITE_LOCK));
-               if (status != NT_STATUS_NOPROBLEMO) {
+               if (NT_STATUS_V(status)) {
                        if ((lock_timeout != 0) && lp_blocking_locks(SNUM(conn))) {
                                /*
                                 * A blocking lock was requested. Package up
@@ -4317,84 +3878,83 @@ 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)
@@ -4450,8 +4010,199 @@ int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size,
 }
 
 
+/* 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)