Now conn is part of smb_request, we don't need it as
[nivanova/samba-autobuild/.git] / source3 / smbd / sesssetup.c
index 4ec7d5f03ae43d7e96c4bdb14e82dd9996021e1b..167682ede23f1020edc021198b01b73fac58bbca 100644 (file)
@@ -1,31 +1,32 @@
-/* 
+/*
    Unix SMB/CIFS implementation.
    handle SMBsessionsetup
    Copyright (C) Andrew Tridgell 1998-2001
    Copyright (C) Andrew Bartlett      2001
    Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
    Copyright (C) Luke Howard          2003
+   Copyright (C) Volker Lendecke      2007
+   Copyright (C) Jeremy Allison              2007
 
    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 3 of the License, or
    (at your option) any later version.
-   
+
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-   
+
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
 
 extern struct auth_context *negprot_global_auth_context;
-extern BOOL global_encrypted_passwords_negotiated;
-extern BOOL global_spnego_negotiated;
+extern bool global_encrypted_passwords_negotiated;
+extern bool global_spnego_negotiated;
 extern enum protocol_types Protocol;
 extern int max_send;
 
@@ -35,11 +36,12 @@ uint32 global_client_caps = 0;
   on a logon error possibly map the error to success if "map to guest"
   is set approriately
 */
-static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **server_info,
+static NTSTATUS do_map_to_guest(NTSTATUS status,
+                               auth_serversupplied_info **server_info,
                                const char *user, const char *domain)
 {
        if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
-               if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) || 
+               if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
                    (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
                        DEBUG(3,("No such user %s [%s] - using guest account\n",
                                 user, domain));
@@ -49,7 +51,8 @@ static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **serv
 
        if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
                if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
-                       DEBUG(3,("Registered username %s for guest access\n",user));
+                       DEBUG(3,("Registered username %s for guest access\n",
+                               user));
                        status = make_server_info_guest(server_info);
                }
        }
@@ -61,25 +64,44 @@ static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **serv
  Add the standard 'Samba' signature to the end of the session setup.
 ****************************************************************************/
 
-static int add_signature(char *outbuf, char *p)
+static int push_signature(uint8 **outbuf)
 {
-       char *start = p;
-       fstring lanman;
+       char *lanman;
+       int result, tmp;
+
+       result = 0;
+
+       tmp = message_push_string(outbuf, "Unix", STR_TERMINATE);
+
+       if (tmp == -1) return -1;
+       result += tmp;
+
+       if (asprintf(&lanman, "Samba %s", SAMBA_VERSION_STRING) != -1) {
+               tmp = message_push_string(outbuf, lanman, STR_TERMINATE);
+               SAFE_FREE(lanman);
+       }
+       else {
+               tmp = message_push_string(outbuf, "Samba", STR_TERMINATE);
+       }
 
-       fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING);
+       if (tmp == -1) return -1;
+       result += tmp;
 
-       p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
-       p += srvstr_push(outbuf, p, lanman, -1, STR_TERMINATE);
-       p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
+       tmp = message_push_string(outbuf, lp_workgroup(), STR_TERMINATE);
 
-       return PTR_DIFF(p, start);
+       if (tmp == -1) return -1;
+       result += tmp;
+
+       return result;
 }
 
 /****************************************************************************
  Start the signing engine if needed. Don't fail signing here.
 ****************************************************************************/
 
-static void sessionsetup_start_signing_engine(const auth_serversupplied_info *server_info, char *inbuf)
+static void sessionsetup_start_signing_engine(
+                       const auth_serversupplied_info *server_info,
+                       const uint8 *inbuf)
 {
        if (!server_info->guest && !srv_signing_started()) {
                /* We need to start the signing engine
@@ -88,7 +110,7 @@ static void sessionsetup_start_signing_engine(const auth_serversupplied_info *se
                 * correct one. Subsequent packets will
                 * be correct.
                 */
-               srv_check_sign_mac(inbuf, False);
+               srv_check_sign_mac((char *)inbuf, False);
        }
 }
 
@@ -96,47 +118,39 @@ static void sessionsetup_start_signing_engine(const auth_serversupplied_info *se
  Send a security blob via a session setup reply.
 ****************************************************************************/
 
-static BOOL reply_sesssetup_blob(connection_struct *conn,
-                               const char *inbuf,
-                               char *outbuf,
-                               DATA_BLOB blob,
-                               NTSTATUS nt_status)
+static void reply_sesssetup_blob(struct smb_request *req,
+                                DATA_BLOB blob,
+                                NTSTATUS nt_status)
 {
-       char *p;
-
-       if (!NT_STATUS_IS_OK(nt_status) && !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
-               ERROR_NT(nt_status_squash(nt_status));
+       if (!NT_STATUS_IS_OK(nt_status) &&
+           !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+               reply_nterror(req, nt_status_squash(nt_status));
        } else {
-               set_message(inbuf,outbuf,4,0,True);
-
                nt_status = nt_status_squash(nt_status);
-               SIVAL(outbuf, smb_rcls, NT_STATUS_V(nt_status));
-               SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
-               SSVAL(outbuf, smb_vwv3, blob.length);
-               p = smb_buf(outbuf);
-
-               /* should we cap this? */
-               memcpy(p, blob.data, blob.length);
-               p += blob.length;
-
-               p += add_signature( outbuf, p );
+               SIVAL(req->outbuf, smb_rcls, NT_STATUS_V(nt_status));
+               SSVAL(req->outbuf, smb_vwv0, 0xFF); /* no chaining possible */
+               SSVAL(req->outbuf, smb_vwv3, blob.length);
 
-               set_message_end(inbuf,outbuf,p);
+               if ((message_push_blob(&req->outbuf, blob) == -1)
+                   || (push_signature(&req->outbuf) == -1)) {
+                       reply_nterror(req, NT_STATUS_NO_MEMORY);
+               }
        }
 
-       show_msg(outbuf);
-       return send_smb(smbd_server_fd(),outbuf);
+       show_msg((char *)req->outbuf);
+       srv_send_smb(smbd_server_fd(),(char *)req->outbuf,req->encrypted);
+       TALLOC_FREE(req->outbuf);
 }
 
 /****************************************************************************
- Do a 'guest' logon, getting back the 
+ Do a 'guest' logon, getting back the
 ****************************************************************************/
 
-static NTSTATUS check_guest_password(auth_serversupplied_info **server_info) 
+static NTSTATUS check_guest_password(auth_serversupplied_info **server_info)
 {
        struct auth_context *auth_context;
        auth_usersupplied_info *user_info = NULL;
-       
+
        NTSTATUS nt_status;
        unsigned char chal[8];
 
@@ -144,7 +158,8 @@ static NTSTATUS check_guest_password(auth_serversupplied_info **server_info)
 
        DEBUG(3,("Got anonymous request\n"));
 
-       if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, chal))) {
+       if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context,
+                                       chal))) {
                return nt_status;
        }
 
@@ -152,8 +167,10 @@ static NTSTATUS check_guest_password(auth_serversupplied_info **server_info)
                (auth_context->free)(&auth_context);
                return NT_STATUS_NO_MEMORY;
        }
-       
-       nt_status = auth_context->check_ntlm_password(auth_context, user_info, server_info);
+
+       nt_status = auth_context->check_ntlm_password(auth_context,
+                                               user_info,
+                                               server_info);
        (auth_context->free)(&auth_context);
        free_user_info(&user_info);
        return nt_status;
@@ -168,14 +185,14 @@ static NTSTATUS check_guest_password(auth_serversupplied_info **server_info)
  Cerate a clock skew error blob for a Windows client.
 ****************************************************************************/
 
-static BOOL make_krb5_skew_error(DATA_BLOB *pblob_out)
+static bool make_krb5_skew_error(DATA_BLOB *pblob_out)
 {
        krb5_context context = NULL;
        krb5_error_code kerr = 0;
        krb5_data reply;
        krb5_principal host_princ = NULL;
        char *host_princ_s = NULL;
-       BOOL ret = False;
+       bool ret = False;
 
        *pblob_out = data_blob_null;
 
@@ -193,14 +210,17 @@ static BOOL make_krb5_skew_error(DATA_BLOB *pblob_out)
 
        kerr = smb_krb5_parse_name(context, host_princ_s, &host_princ);
        if (kerr) {
-               DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed for name %s: Error %s\n",
+               DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed "
+                       "for name %s: Error %s\n",
                        host_princ_s, error_message(kerr) ));
                goto out;
        }
-       
-       kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW, host_princ, &reply);
+
+       kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW,
+                       host_princ, &reply);
        if (kerr) {
-               DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error failed: Error %s\n",
+               DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error "
+                       "failed: Error %s\n",
                        error_message(kerr) ));
                goto out;
        }
@@ -226,11 +246,10 @@ static BOOL make_krb5_skew_error(DATA_BLOB *pblob_out)
  Reply to a session setup spnego negotiate packet for kerberos.
 ****************************************************************************/
 
-static int reply_spnego_kerberos(connection_struct *conn, 
-                                char *inbuf, char *outbuf,
-                                int length, int bufsize,
-                                DATA_BLOB *secblob,
-                                BOOL *p_invalidate_vuid)
+static void reply_spnego_kerberos(struct smb_request *req,
+                                 DATA_BLOB *secblob,
+                                 uint16 vuid,
+                                 bool *p_invalidate_vuid)
 {
        TALLOC_CTX *mem_ctx;
        DATA_BLOB ticket;
@@ -238,8 +257,8 @@ static int reply_spnego_kerberos(connection_struct *conn,
        fstring netbios_domain_name;
        struct passwd *pw;
        fstring user;
-       int sess_vuid;
-       NTSTATUS ret;
+       int sess_vuid = req->vuid;
+       NTSTATUS ret = NT_STATUS_OK;
        PAC_DATA *pac_data;
        DATA_BLOB ap_rep, ap_rep_wrapped, response;
        auth_serversupplied_info *server_info = NULL;
@@ -247,8 +266,8 @@ static int reply_spnego_kerberos(connection_struct *conn,
        uint8 tok_id[2];
        DATA_BLOB nullblob = data_blob_null;
        fstring real_username;
-       BOOL map_domainuser_to_guest = False;
-       BOOL username_was_mapped;
+       bool map_domainuser_to_guest = False;
+       bool username_was_mapped;
        PAC_LOGON_INFO *logon_info = NULL;
 
        ZERO_STRUCT(ticket);
@@ -262,47 +281,56 @@ static int reply_spnego_kerberos(connection_struct *conn,
 
        mem_ctx = talloc_init("reply_spnego_kerberos");
        if (mem_ctx == NULL) {
-               return ERROR_NT(nt_status_squash(NT_STATUS_NO_MEMORY));
+               reply_nterror(req, nt_status_squash(NT_STATUS_NO_MEMORY));
+               return;
        }
 
        if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
                talloc_destroy(mem_ctx);
-               return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
+               reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
+               return;
        }
 
-       ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket, 
-                               &client, &pac_data, &ap_rep, 
+       ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket,
+                               &client, &pac_data, &ap_rep,
                                &session_key, True);
 
        data_blob_free(&ticket);
 
        if (!NT_STATUS_IS_OK(ret)) {
 #if 0
-               /* Experiment that failed. See "only happens with a KDC" comment below. */
+               /* Experiment that failed.
+                * See "only happens with a KDC" comment below. */
 
                if (NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
 
                        /*
-                        * Windows in this case returns NT_STATUS_MORE_PROCESSING_REQUIRED
-                        * with a negTokenTarg blob containing an krb5_error struct ASN1 encoded
-                        * containing KRB5KRB_AP_ERR_SKEW. The client then fixes its
-                        * clock and continues rather than giving an error. JRA.
+                        * Windows in this case returns
+                        * NT_STATUS_MORE_PROCESSING_REQUIRED
+                        * with a negTokenTarg blob containing an krb5_error
+                        * struct ASN1 encoded containing KRB5KRB_AP_ERR_SKEW.
+                        * The client then fixes its clock and continues rather
+                        * than giving an error. JRA.
                         * -- Looks like this only happens with a KDC. JRA.
                         */
 
-                       BOOL ok = make_krb5_skew_error(&ap_rep);
+                       bool ok = make_krb5_skew_error(&ap_rep);
                        if (!ok) {
                                talloc_destroy(mem_ctx);
-                               return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
+                               return ERROR_NT(nt_status_squash(
+                                               NT_STATUS_LOGON_FAILURE));
                        }
-                       ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_ERROR);
-                       response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
-                       reply_sesssetup_blob(conn, inbuf, outbuf, response, NT_STATUS_MORE_PROCESSING_REQUIRED);
+                       ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
+                                       TOK_ID_KRB_ERROR);
+                       response = spnego_gen_auth_response(&ap_rep_wrapped,
+                                       ret, OID_KERBEROS5_OLD);
+                       reply_sesssetup_blob(conn, inbuf, outbuf, response,
+                                       NT_STATUS_MORE_PROCESSING_REQUIRED);
 
                        /*
-                        * In this one case we don't invalidate the intermediate vuid.
-                        * as we're expecting the client to re-use it for the next
-                        * sessionsetupX packet. JRA.
+                        * In this one case we don't invalidate the
+                        * intermediate vuid as we're expecting the client
+                        * to re-use it for the next sessionsetupX packet. JRA.
                         */
 
                        *p_invalidate_vuid = False;
@@ -318,9 +346,11 @@ static int reply_spnego_kerberos(connection_struct *conn,
                        ret = NT_STATUS_LOGON_FAILURE;
                }
 #endif
-               DEBUG(1,("Failed to verify incoming ticket with error %s!\n", nt_errstr(ret))); 
+               DEBUG(1,("Failed to verify incoming ticket with error %s!\n",
+                               nt_errstr(ret)));
                talloc_destroy(mem_ctx);
-               return ERROR_NT(nt_status_squash(ret));
+               reply_nterror(req, nt_status_squash(ret));
+               return;
        }
 
        DEBUG(3,("Ticket name is [%s]\n", client));
@@ -332,7 +362,8 @@ static int reply_spnego_kerberos(connection_struct *conn,
                data_blob_free(&session_key);
                SAFE_FREE(client);
                talloc_destroy(mem_ctx);
-               return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
+               reply_nterror(req,nt_status_squash(NT_STATUS_LOGON_FAILURE));
+               return;
        }
 
        *p = 0;
@@ -353,7 +384,9 @@ static int reply_spnego_kerberos(connection_struct *conn,
                        data_blob_free(&session_key);
                        SAFE_FREE(client);
                        talloc_destroy(mem_ctx);
-                       return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
+                       reply_nterror(req, nt_status_squash(
+                                             NT_STATUS_LOGON_FAILURE));
+                       return;
                }
        }
 
@@ -363,8 +396,9 @@ static int reply_spnego_kerberos(connection_struct *conn,
        domain = p+1;
 
        if (logon_info && logon_info->info3.hdr_logon_dom.uni_str_len) {
-
-               unistr2_to_ascii(netbios_domain_name, &logon_info->info3.uni_logon_dom, -1);
+               unistr2_to_ascii(netbios_domain_name,
+                               &logon_info->info3.uni_logon_dom,
+                               sizeof(netbios_domain_name));
                domain = netbios_domain_name;
                DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));
 
@@ -405,7 +439,7 @@ static int reply_spnego_kerberos(connection_struct *conn,
        }
 
        fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
-       
+
        /* lookup the passwd struct, create a new user if necessary */
 
        username_was_mapped = map_username( user );
@@ -418,50 +452,55 @@ static int reply_spnego_kerberos(connection_struct *conn,
                /* do this before an eventual mappign to guest occurs */
                ret = smb_pam_accountcheck(pw->pw_name);
                if (  !NT_STATUS_IS_OK(ret)) {
-                       DEBUG(1, ("PAM account restriction prevents user login\n"));
+                       DEBUG(1,("PAM account restriction "
+                               "prevents user login\n"));
                        data_blob_free(&ap_rep);
                        data_blob_free(&session_key);
                        TALLOC_FREE(mem_ctx);
-                       return ERROR_NT(nt_status_squash(ret));
+                       reply_nterror(req, nt_status_squash(ret));
+                       return;
                }
        }
 
        if (!pw) {
 
                /* this was originally the behavior of Samba 2.2, if a user
-                  did not have a local uid but has been authenticated, then 
+                  did not have a local uid but has been authenticated, then
                   map them to a guest account */
 
-               if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){ 
+               if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){
                        map_domainuser_to_guest = True;
                        fstrcpy(user,lp_guestaccount());
                        pw = smb_getpwnam( mem_ctx, user, real_username, True );
-               } 
+               }
 
                /* extra sanity check that the guest account is valid */
 
                if ( !pw ) {
-                       DEBUG(1,("Username %s is invalid on this system\n", user));
+                       DEBUG(1,("Username %s is invalid on this system\n",
+                               user));
                        SAFE_FREE(client);
                        data_blob_free(&ap_rep);
                        data_blob_free(&session_key);
                        TALLOC_FREE(mem_ctx);
-                       return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
+                       reply_nterror(req, nt_status_squash(
+                                             NT_STATUS_LOGON_FAILURE));
+                       return;
                }
        }
 
        /* setup the string used by %U */
-       
+
        sub_set_smb_name( real_username );
        reload_services(True);
 
        if ( map_domainuser_to_guest ) {
                make_server_info_guest(&server_info);
        } else if (logon_info) {
-               /* pass the unmapped username here since map_username() 
+               /* pass the unmapped username here since map_username()
                   will be called again from inside make_server_info_info3() */
-               
-               ret = make_server_info_info3(mem_ctx, client, domain, 
+
+               ret = make_server_info_info3(mem_ctx, client, domain,
                                             &server_info, &logon_info->info3);
                if ( !NT_STATUS_IS_OK(ret) ) {
                        DEBUG(1,("make_server_info_info3 failed: %s!\n",
@@ -470,7 +509,8 @@ static int reply_spnego_kerberos(connection_struct *conn,
                        data_blob_free(&ap_rep);
                        data_blob_free(&session_key);
                        TALLOC_FREE(mem_ctx);
-                       return ERROR_NT(nt_status_squash(ret));
+                       reply_nterror(req, nt_status_squash(ret));
+                       return;
                }
 
        } else {
@@ -483,7 +523,8 @@ static int reply_spnego_kerberos(connection_struct *conn,
                        data_blob_free(&ap_rep);
                        data_blob_free(&session_key);
                        TALLOC_FREE(mem_ctx);
-                       return ERROR_NT(nt_status_squash(ret));
+                       reply_nterror(req, nt_status_squash(ret));
+                       return;
                }
 
                /* make_server_info_pw does not set the domain. Without this
@@ -491,15 +532,16 @@ static int reply_spnego_kerberos(connection_struct *conn,
                 * %D. */
 
                if (server_info->sam_account != NULL) {
-                       pdb_set_domain(server_info->sam_account, domain, PDB_SET);
+                       pdb_set_domain(server_info->sam_account,
+                                       domain, PDB_SET);
                }
        }
 
        server_info->was_mapped |= username_was_mapped;
-       
+
        /* we need to build the token for the user. make_server_info_guest()
           already does this */
-       
+
        if ( !server_info->ptok ) {
                ret = create_local_token( server_info );
                if ( !NT_STATUS_IS_OK(ret) ) {
@@ -508,51 +550,67 @@ static int reply_spnego_kerberos(connection_struct *conn,
                        data_blob_free(&session_key);
                        TALLOC_FREE( mem_ctx );
                        TALLOC_FREE( server_info );
-                       return ERROR_NT(nt_status_squash(ret));
+                       reply_nterror(req, nt_status_squash(ret));
+                       return;
                }
        }
 
-       /* register_vuid keeps the server info */
-       /* register_vuid takes ownership of session_key, no need to free after this.
-          A better interface would copy it.... */
-       sess_vuid = register_vuid(server_info, session_key, nullblob, client);
+       /* register_existing_vuid keeps the server info */
+       /* register_existing_vuid takes ownership of session_key on success,
+        * no need to free after this on success. A better interface would copy
+        * it.... */
+
+       if (!is_partial_auth_vuid(sess_vuid)) {
+               sess_vuid = register_initial_vuid();
+       }
+       sess_vuid = register_existing_vuid(sess_vuid,
+                                       server_info,
+                                       session_key,
+                                       nullblob,
+                                       client);
 
        SAFE_FREE(client);
 
+       reply_outbuf(req, 4, 0);
+       SSVAL(req->outbuf,smb_uid,sess_vuid);
+
        if (sess_vuid == UID_FIELD_INVALID ) {
                ret = NT_STATUS_LOGON_FAILURE;
+               data_blob_free(&session_key);
        } else {
                /* current_user_info is changed on new vuid */
                reload_services( True );
 
-               set_message(inbuf,outbuf,4,0,True);
-               SSVAL(outbuf, smb_vwv3, 0);
-                       
+               SSVAL(req->outbuf, smb_vwv3, 0);
+
                if (server_info->guest) {
-                       SSVAL(outbuf,smb_vwv2,1);
+                       SSVAL(req->outbuf,smb_vwv2,1);
                }
-               
-               SSVAL(outbuf, smb_uid, sess_vuid);
 
-               sessionsetup_start_signing_engine(server_info, inbuf);
+               SSVAL(req->outbuf, smb_uid, sess_vuid);
+
+               sessionsetup_start_signing_engine(server_info, req->inbuf);
+               /* Successful logon. Keep this vuid. */
+               *p_invalidate_vuid = False;
        }
 
         /* wrap that up in a nice GSS-API wrapping */
        if (NT_STATUS_IS_OK(ret)) {
-               ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_AP_REP);
+               ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
+                               TOK_ID_KRB_AP_REP);
        } else {
                ap_rep_wrapped = data_blob_null;
        }
-       response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
-       reply_sesssetup_blob(conn, inbuf, outbuf, response, ret);
+       response = spnego_gen_auth_response(&ap_rep_wrapped, ret,
+                       OID_KERBEROS5_OLD);
+       reply_sesssetup_blob(req, response, ret);
 
        data_blob_free(&ap_rep);
        data_blob_free(&ap_rep_wrapped);
        data_blob_free(&response);
        TALLOC_FREE(mem_ctx);
-
-       return -1; /* already replied */
 }
+
 #endif
 
 /****************************************************************************
@@ -563,61 +621,76 @@ static int reply_spnego_kerberos(connection_struct *conn,
  leg of the NTLM auth steps.
 ***************************************************************************/
 
-static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *outbuf,
+static void reply_spnego_ntlmssp(struct smb_request *req,
                                 uint16 vuid,
                                 AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
-                                DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status, 
-                                BOOL wrap) 
+                                DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
+                                bool wrap)
 {
-       BOOL ret;
        DATA_BLOB response;
        struct auth_serversupplied_info *server_info = NULL;
 
        if (NT_STATUS_IS_OK(nt_status)) {
                server_info = (*auth_ntlmssp_state)->server_info;
        } else {
-               nt_status = do_map_to_guest(nt_status, 
-                                           &server_info, 
-                                           (*auth_ntlmssp_state)->ntlmssp_state->user, 
-                                           (*auth_ntlmssp_state)->ntlmssp_state->domain);
+               nt_status = do_map_to_guest(nt_status,
+                           &server_info,
+                           (*auth_ntlmssp_state)->ntlmssp_state->user,
+                           (*auth_ntlmssp_state)->ntlmssp_state->domain);
        }
 
+       reply_outbuf(req, 4, 0);
+
+       SSVAL(req->outbuf, smb_uid, vuid);
+
        if (NT_STATUS_IS_OK(nt_status)) {
-               int sess_vuid;
                DATA_BLOB nullblob = data_blob_null;
-               DATA_BLOB session_key = data_blob((*auth_ntlmssp_state)->ntlmssp_state->session_key.data, (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
+               DATA_BLOB session_key =
+                       data_blob(
+                       (*auth_ntlmssp_state)->ntlmssp_state->session_key.data,
+                       (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
+
+               if (!is_partial_auth_vuid(vuid)) {
+                       data_blob_free(&session_key);
+                       nt_status = NT_STATUS_LOGON_FAILURE;
+                       goto out;
+               }
+               /* register_existing_vuid keeps the server info */
+               if (register_existing_vuid(vuid,
+                               server_info,
+                               session_key, nullblob,
+                               (*auth_ntlmssp_state)->ntlmssp_state->user) !=
+                                       vuid) {
+                       data_blob_free(&session_key);
+                       nt_status = NT_STATUS_LOGON_FAILURE;
+                       goto out;
+               }
 
-               /* register_vuid keeps the server info */
-               sess_vuid = register_vuid(server_info, session_key, nullblob, (*auth_ntlmssp_state)->ntlmssp_state->user);
                (*auth_ntlmssp_state)->server_info = NULL;
 
-               if (sess_vuid == UID_FIELD_INVALID ) {
-                       nt_status = NT_STATUS_LOGON_FAILURE;
-               } else {
-                       
-                       /* current_user_info is changed on new vuid */
-                       reload_services( True );
-
-                       set_message(inbuf,outbuf,4,0,True);
-                       SSVAL(outbuf, smb_vwv3, 0);
-                       
-                       if (server_info->guest) {
-                               SSVAL(outbuf,smb_vwv2,1);
-                       }
-                       
-                       SSVAL(outbuf,smb_uid,sess_vuid);
+               /* current_user_info is changed on new vuid */
+               reload_services( True );
+
+               SSVAL(req->outbuf, smb_vwv3, 0);
 
-                       sessionsetup_start_signing_engine(server_info, inbuf);
+               if (server_info->guest) {
+                       SSVAL(req->outbuf,smb_vwv2,1);
                }
+
+               sessionsetup_start_signing_engine(server_info,
+                                                 (uint8 *)req->inbuf);
        }
 
+  out:
+
        if (wrap) {
-               response = spnego_gen_auth_response(ntlmssp_blob, nt_status, OID_NTLMSSP);
+               response = spnego_gen_auth_response(ntlmssp_blob,
+                               nt_status, OID_NTLMSSP);
        } else {
                response = *ntlmssp_blob;
        }
 
-       ret = reply_sesssetup_blob(conn, inbuf, outbuf, response, nt_status);
+       reply_sesssetup_blob(req, response, nt_status);
        if (wrap) {
                data_blob_free(&response);
        }
@@ -625,21 +698,22 @@ static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *out
        /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
           and the other end, that we are not finished yet. */
 
-       if (!ret || !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+       if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
                /* NB. This is *NOT* an error case. JRA */
                auth_ntlmssp_end(auth_ntlmssp_state);
-               /* Kill the intermediate vuid */
-               invalidate_vuid(vuid);
+               if (!NT_STATUS_IS_OK(nt_status)) {
+                       /* Kill the intermediate vuid */
+                       invalidate_vuid(vuid);
+               }
        }
-
-       return ret;
 }
 
 /****************************************************************************
  Is this a krb5 mechanism ?
 ****************************************************************************/
 
-NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in, DATA_BLOB *pblob_out, BOOL *p_is_krb5)
+NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in, DATA_BLOB *pblob_out,
+               bool *p_is_krb5)
 {
        char *OIDs[ASN1_MAX_OIDS];
        int i;
@@ -652,22 +726,22 @@ NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in, DATA_BLOB *pblob_out, BOOL *
        }
 
        /* only look at the first OID for determining the mechToken --
-          accoirding to RFC2478, we should choose the one we want 
-          and renegotiate, but i smell a client bug here..  
-          
-          Problem observed when connecting to a member (samba box) 
-          of an AD domain as a user in a Samba domain.  Samba member 
-          server sent back krb5/mskrb5/ntlmssp as mechtypes, but the 
-          client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an 
+          according to RFC2478, we should choose the one we want
+          and renegotiate, but i smell a client bug here..
+
+          Problem observed when connecting to a member (samba box)
+          of an AD domain as a user in a Samba domain.  Samba member
+          server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
+          client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
           NTLMSSP mechtoken.                 --jerry              */
 
-#ifdef HAVE_KRB5       
+#ifdef HAVE_KRB5
        if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
            strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
                *p_is_krb5 = True;
        }
 #endif
-               
+
        for (i=0;OIDs[i];i++) {
                DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
                free(OIDs[i]);
@@ -679,39 +753,40 @@ NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in, DATA_BLOB *pblob_out, BOOL *
  Reply to a session setup spnego negotiate packet.
 ****************************************************************************/
 
-static int reply_spnego_negotiate(connection_struct *conn, 
-                                 char *inbuf,
-                                 char *outbuf,
-                                 uint16 vuid,
-                                 int length, int bufsize,
-                                 DATA_BLOB blob1,
-                                 AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
+static void reply_spnego_negotiate(struct smb_request *req,
+                                  uint16 vuid,
+                                  DATA_BLOB blob1,
+                                  AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
 {
        DATA_BLOB secblob;
        DATA_BLOB chal;
-       BOOL got_kerberos_mechanism = False;
+       bool got_kerberos_mechanism = False;
        NTSTATUS status;
 
-       status = parse_spnego_mechanisms(blob1, &secblob, &got_kerberos_mechanism);
+       status = parse_spnego_mechanisms(blob1, &secblob,
+                       &got_kerberos_mechanism);
        if (!NT_STATUS_IS_OK(status)) {
                /* Kill the intermediate vuid */
                invalidate_vuid(vuid);
-               return ERROR_NT(nt_status_squash(status));
+               reply_nterror(req, nt_status_squash(status));
+               return;
        }
 
-       DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n", (unsigned long)secblob.length));
+       DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n",
+                               (unsigned long)secblob.length));
 
 #ifdef HAVE_KRB5
-       if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
-               BOOL destroy_vuid = True;
-               int ret = reply_spnego_kerberos(conn, inbuf, outbuf, 
-                                               length, bufsize, &secblob, &destroy_vuid);
+       if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) ||
+                               lp_use_kerberos_keytab()) ) {
+               bool destroy_vuid = True;
+               reply_spnego_kerberos(req, &secblob, vuid,
+                                     &destroy_vuid);
                data_blob_free(&secblob);
                if (destroy_vuid) {
                        /* Kill the intermediate vuid */
                        invalidate_vuid(vuid);
                }
-               return ret;
+               return;
        }
 #endif
 
@@ -723,32 +798,32 @@ static int reply_spnego_negotiate(connection_struct *conn,
        if (!NT_STATUS_IS_OK(status)) {
                /* Kill the intermediate vuid */
                invalidate_vuid(vuid);
-               return ERROR_NT(nt_status_squash(status));
+               reply_nterror(req, nt_status_squash(status));
+               return;
        }
 
-       status = auth_ntlmssp_update(*auth_ntlmssp_state, 
+       status = auth_ntlmssp_update(*auth_ntlmssp_state,
                                        secblob, &chal);
 
        data_blob_free(&secblob);
 
-       reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, auth_ntlmssp_state,
+       reply_spnego_ntlmssp(req, vuid, auth_ntlmssp_state,
                             &chal, status, True);
 
        data_blob_free(&chal);
 
        /* already replied */
-       return -1;
+       return;
 }
 
 /****************************************************************************
  Reply to a session setup spnego auth packet.
 ****************************************************************************/
 
-static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
-                            uint16 vuid,
-                            int length, int bufsize,
-                            DATA_BLOB blob1,
-                            AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
+static void reply_spnego_auth(struct smb_request *req,
+                             uint16 vuid,
+                             DATA_BLOB blob1,
+                             AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
 {
        DATA_BLOB auth = data_blob_null;
        DATA_BLOB auth_reply = data_blob_null;
@@ -762,28 +837,33 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
                /* Kill the intermediate vuid */
                invalidate_vuid(vuid);
 
-               return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
+               reply_nterror(req, nt_status_squash(
+                                     NT_STATUS_INVALID_PARAMETER));
+               return;
        }
 
        if (auth.data[0] == ASN1_APPLICATION(0)) {
                /* Might be a second negTokenTarg packet */
 
-               BOOL got_krb5_mechanism = False;
-               status = parse_spnego_mechanisms(auth, &secblob, &got_krb5_mechanism);
+               bool got_krb5_mechanism = False;
+               status = parse_spnego_mechanisms(auth, &secblob,
+                               &got_krb5_mechanism);
                if (NT_STATUS_IS_OK(status)) {
-                       DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n", (unsigned long)secblob.length));
+                       DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n",
+                                       (unsigned long)secblob.length));
 #ifdef HAVE_KRB5
-                       if ( got_krb5_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
-                               BOOL destroy_vuid = True;
-                               int ret = reply_spnego_kerberos(conn, inbuf, outbuf, 
-                                                               length, bufsize, &secblob, &destroy_vuid);
+                       if ( got_krb5_mechanism && ((lp_security()==SEC_ADS) ||
+                                               lp_use_kerberos_keytab()) ) {
+                               bool destroy_vuid = True;
+                               reply_spnego_kerberos(req, &secblob,
+                                                     vuid, &destroy_vuid);
                                data_blob_free(&secblob);
                                data_blob_free(&auth);
                                if (destroy_vuid) {
                                        /* Kill the intermediate vuid */
                                        invalidate_vuid(vuid);
                                }
-                               return ret;
+                               return;
                        }
 #endif
                }
@@ -791,28 +871,30 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
 
        /* If we get here it wasn't a negTokenTarg auth packet. */
        data_blob_free(&secblob);
-       
+
        if (!*auth_ntlmssp_state) {
                /* Kill the intermediate vuid */
                invalidate_vuid(vuid);
 
                /* auth before negotiatiate? */
-               return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
+               reply_nterror(req, nt_status_squash(
+                                     NT_STATUS_INVALID_PARAMETER));
+               return;
        }
-       
-       status = auth_ntlmssp_update(*auth_ntlmssp_state, 
+
+       status = auth_ntlmssp_update(*auth_ntlmssp_state,
                                        auth, &auth_reply);
 
        data_blob_free(&auth);
 
-       reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, 
+       reply_spnego_ntlmssp(req, vuid,
                             auth_ntlmssp_state,
                             &auth_reply, status, True);
-               
+
        data_blob_free(&auth_reply);
 
        /* and tell smbd that we have already replied to this packet */
-       return -1;
+       return;
 }
 
 /****************************************************************************
@@ -852,11 +934,13 @@ static struct pending_auth_data *get_pending_auth_data(uint16 smbpid)
 }
 
 /****************************************************************************
- Check the size of an SPNEGO blob. If we need more return NT_STATUS_MORE_PROCESSING_REQUIRED,
- else return NT_STATUS_OK. Don't allow the blob to be more than 64k.
+ Check the size of an SPNEGO blob. If we need more return
+ NT_STATUS_MORE_PROCESSING_REQUIRED, else return NT_STATUS_OK. Don't allow
+ the blob to be more than 64k.
 ****************************************************************************/
 
-static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid, DATA_BLOB *pblob)
+static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid,
+               DATA_BLOB *pblob)
 {
        struct pending_auth_data *pad = NULL;
        ASN1_DATA data;
@@ -879,7 +963,8 @@ static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid, DATA_BLOB
 
                /* Integer wrap paranoia.... */
 
-               if (pad->partial_data.length + copy_len < pad->partial_data.length ||
+               if (pad->partial_data.length + copy_len <
+                               pad->partial_data.length ||
                    pad->partial_data.length + copy_len < copy_len) {
 
                        DEBUG(2,("check_spnego_blob_complete: integer wrap "
@@ -986,7 +1071,8 @@ static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid, DATA_BLOB
 
        /* Refuse the blob if it's bigger than 64k. */
        if (needed_len > 65536) {
-               DEBUG(2,("check_spnego_blob_complete: needed_len too large (%u)\n",
+               DEBUG(2,("check_spnego_blob_complete: needed_len "
+                       "too large (%u)\n",
                        (unsigned int)needed_len ));
                return NT_STATUS_INVALID_PARAMETER;
        }
@@ -1013,43 +1099,41 @@ static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid, DATA_BLOB
  conn POINTER CAN BE NULL HERE !
 ****************************************************************************/
 
-static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
-                                       char *outbuf,
-                                       int length,int bufsize)
+static void reply_sesssetup_and_X_spnego(struct smb_request *req)
 {
        uint8 *p;
        DATA_BLOB blob1;
-       int ret;
        size_t bufrem;
        fstring native_os, native_lanman, primary_domain;
-       char *p2;
-       uint16 data_blob_len = SVAL(inbuf, smb_vwv7);
+       const char *p2;
+       uint16 data_blob_len = SVAL(req->inbuf, smb_vwv7);
        enum remote_arch_types ra_type = get_remote_arch();
-       int vuid = SVAL(inbuf,smb_uid);
+       int vuid = SVAL(req->inbuf,smb_uid);
        user_struct *vuser = NULL;
        NTSTATUS status = NT_STATUS_OK;
-       uint16 smbpid = SVAL(inbuf,smb_pid);
-       uint16 smb_flag2 = SVAL(inbuf, smb_flg2);
+       uint16 smbpid = req->smbpid;
+       uint16 smb_flag2 = req->flags2;
 
        DEBUG(3,("Doing spnego session setup\n"));
 
        if (global_client_caps == 0) {
-               global_client_caps = IVAL(inbuf,smb_vwv10);
+               global_client_caps = IVAL(req->inbuf,smb_vwv10);
 
                if (!(global_client_caps & CAP_STATUS32)) {
                        remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
                }
 
        }
-               
-       p = (uint8 *)smb_buf(inbuf);
+
+       p = (uint8 *)smb_buf(req->inbuf);
 
        if (data_blob_len == 0) {
                /* an invalid request */
-               return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
+               reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
+               return;
        }
 
-       bufrem = smb_bufrem(inbuf, p);
+       bufrem = smb_bufrem(req->inbuf, p);
        /* pull the spnego blob */
        blob1 = data_blob(p, MIN(bufrem, data_blob_len));
 
@@ -1057,14 +1141,14 @@ static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
        file_save("negotiate.dat", blob1.data, blob1.length);
 #endif
 
-       p2 = inbuf + smb_vwv13 + data_blob_len;
-       p2 += srvstr_pull_buf(inbuf, smb_flag2, native_os, p2,
+       p2 = (char *)req->inbuf + smb_vwv13 + data_blob_len;
+       p2 += srvstr_pull_buf(req->inbuf, smb_flag2, native_os, p2,
                              sizeof(native_os), STR_TERMINATE);
-       p2 += srvstr_pull_buf(inbuf, smb_flag2, native_lanman, p2,
+       p2 += srvstr_pull_buf(req->inbuf, smb_flag2, native_lanman, p2,
                              sizeof(native_lanman), STR_TERMINATE);
-       p2 += srvstr_pull_buf(inbuf, smb_flag2, primary_domain, p2,
+       p2 += srvstr_pull_buf(req->inbuf, smb_flag2, primary_domain, p2,
                              sizeof(primary_domain), STR_TERMINATE);
-       DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n", 
+       DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
                native_os, native_lanman, primary_domain));
 
        if ( ra_type == RA_WIN2K ) {
@@ -1072,44 +1156,47 @@ static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
 
                if ( !strlen(native_os) && !strlen(native_lanman) )
                        set_remote_arch(RA_VISTA);
-               
-               /* Windows 2003 doesn't set the native lanman string, 
+
+               /* Windows 2003 doesn't set the native lanman string,
                   but does set primary domain which is a bug I think */
-                          
+
                if ( !strlen(native_lanman) ) {
                        ra_lanman_string( primary_domain );
                } else {
                        ra_lanman_string( native_lanman );
                }
        }
-               
-       vuser = get_partial_auth_user_struct(vuid);
-       if (!vuser) {
+
+       /* Did we get a valid vuid ? */
+       if (!is_partial_auth_vuid(vuid)) {
+               /* No, then try and see if this is an intermediate sessionsetup
+                * for a large SPNEGO packet. */
                struct pending_auth_data *pad = get_pending_auth_data(smbpid);
                if (pad) {
-                       DEBUG(10,("reply_sesssetup_and_X_spnego: found pending vuid %u\n",
+                       DEBUG(10,("reply_sesssetup_and_X_spnego: found "
+                               "pending vuid %u\n",
                                (unsigned int)pad->vuid ));
                        vuid = pad->vuid;
-                       vuser = get_partial_auth_user_struct(vuid);
                }
        }
 
-       if (!vuser) {
-               vuid = register_vuid(NULL, data_blob_null, data_blob_null, NULL);
-               if (vuid == UID_FIELD_INVALID ) {
+       /* Do we have a valid vuid now ? */
+       if (!is_partial_auth_vuid(vuid)) {
+               /* No, start a new authentication setup. */
+               vuid = register_initial_vuid();
+               if (vuid == UID_FIELD_INVALID) {
                        data_blob_free(&blob1);
-                       return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
+                       reply_nterror(req, nt_status_squash(
+                                             NT_STATUS_INVALID_PARAMETER));
+                       return;
                }
-       
-               vuser = get_partial_auth_user_struct(vuid);
        }
 
+       vuser = get_partial_auth_user_struct(vuid);
+       /* This MUST be valid. */
        if (!vuser) {
-               data_blob_free(&blob1);
-               return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
+               smb_panic("reply_sesssetup_and_X_spnego: invalid vuid.");
        }
-       
-       SSVAL(outbuf,smb_uid,vuid);
 
        /* Large (greater than 4k) SPNEGO blobs are split into multiple
         * sessionsetup requests as the Windows limit on the security blob
@@ -1118,52 +1205,60 @@ static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
 
        status = check_spnego_blob_complete(smbpid, vuid, &blob1);
        if (!NT_STATUS_IS_OK(status)) {
-               if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+               if (!NT_STATUS_EQUAL(status,
+                               NT_STATUS_MORE_PROCESSING_REQUIRED)) {
                        /* Real error - kill the intermediate vuid */
                        invalidate_vuid(vuid);
                }
                data_blob_free(&blob1);
-               return ERROR_NT(nt_status_squash(status));
+               reply_nterror(req, nt_status_squash(status));
+               return;
        }
 
        if (blob1.data[0] == ASN1_APPLICATION(0)) {
+
                /* its a negTokenTarg packet */
-               ret = reply_spnego_negotiate(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
-                                            &vuser->auth_ntlmssp_state);
+
+               reply_spnego_negotiate(req, vuid, blob1,
+                                      &vuser->auth_ntlmssp_state);
                data_blob_free(&blob1);
-               return ret;
+               return;
        }
 
        if (blob1.data[0] == ASN1_CONTEXT(1)) {
+
                /* its a auth packet */
-               ret = reply_spnego_auth(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
-                                       &vuser->auth_ntlmssp_state);
+
+               reply_spnego_auth(req, vuid, blob1,
+                                 &vuser->auth_ntlmssp_state);
                data_blob_free(&blob1);
-               return ret;
+               return;
        }
 
        if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
                DATA_BLOB chal;
+
                if (!vuser->auth_ntlmssp_state) {
                        status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
                        if (!NT_STATUS_IS_OK(status)) {
                                /* Kill the intermediate vuid */
                                invalidate_vuid(vuid);
                                data_blob_free(&blob1);
-                               return ERROR_NT(nt_status_squash(status));
+                               reply_nterror(req, nt_status_squash(status));
+                               return;
                        }
                }
 
                status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
                                                blob1, &chal);
-               
+
                data_blob_free(&blob1);
-               
-               reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, 
-                                          &vuser->auth_ntlmssp_state,
-                                          &chal, status, False);
+
+               reply_spnego_ntlmssp(req, vuid,
+                                    &vuser->auth_ntlmssp_state,
+                                    &chal, status, False);
                data_blob_free(&chal);
-               return -1;
+               return;
        }
 
        /* what sort of packet is this? */
@@ -1171,7 +1266,7 @@ static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
 
        data_blob_free(&blob1);
 
-       return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
+       reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
 }
 
 /****************************************************************************
@@ -1206,13 +1301,18 @@ static int shutdown_other_smbds(struct db_record *rec,
 
 static void setup_new_vc_session(void)
 {
-       DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x compatible we would close all old resources.\n"));
+       char addr[INET6_ADDRSTRLEN];
+
+       DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x "
+               "compatible we would close all old resources.\n"));
 #if 0
        conn_close_all();
        invalidate_all_vuids();
 #endif
        if (lp_reset_on_zero_vc()) {
-               connections_forall(shutdown_other_smbds, client_addr());
+               connections_forall(shutdown_other_smbds,
+                       CONST_DISCARD(void *,
+                       client_addr(get_client_fd(),addr,sizeof(addr))));
        }
 }
 
@@ -1220,11 +1320,10 @@ static void setup_new_vc_session(void)
  Reply to a session setup command.
 ****************************************************************************/
 
-int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
-                         int length,int bufsize)
+void reply_sesssetup_and_X(struct smb_request *req)
 {
        int sess_vuid;
-       int   smb_bufsize;    
+       int smb_bufsize;
        DATA_BLOB lm_resp;
        DATA_BLOB nt_resp;
        DATA_BLOB plaintext_password;
@@ -1234,121 +1333,150 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
        fstring native_os;
        fstring native_lanman;
        fstring primary_domain;
-       static BOOL done_sesssetup = False;
+       static bool done_sesssetup = False;
        auth_usersupplied_info *user_info = NULL;
        auth_serversupplied_info *server_info = NULL;
-       uint16 smb_flag2 = SVAL(inbuf, smb_flg2);
+       uint16 smb_flag2 = req->flags2;
 
        NTSTATUS nt_status;
 
-       BOOL doencrypt = global_encrypted_passwords_negotiated;
+       bool doencrypt = global_encrypted_passwords_negotiated;
 
        DATA_BLOB session_key;
-       
+
        START_PROFILE(SMBsesssetupX);
 
        ZERO_STRUCT(lm_resp);
        ZERO_STRUCT(nt_resp);
        ZERO_STRUCT(plaintext_password);
 
-       DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), smb_flag2));
+       DEBUG(3,("wct=%d flg2=0x%x\n", req->wct, req->flags2));
 
        /* a SPNEGO session setup has 12 command words, whereas a normal
           NT1 session setup has 13. See the cifs spec. */
-       if (CVAL(inbuf, smb_wct) == 12 &&
-           (smb_flag2 & FLAGS2_EXTENDED_SECURITY)) {
+       if (req->wct == 12 &&
+           (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
+
                if (!global_spnego_negotiated) {
-                       DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
-                       return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
+                       DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt "
+                                "at SPNEGO session setup when it was not "
+                                "negotiated.\n"));
+                       reply_nterror(req, nt_status_squash(
+                                             NT_STATUS_LOGON_FAILURE));
+                       END_PROFILE(SMBsesssetupX);
+                       return;
                }
 
-               if (SVAL(inbuf,smb_vwv4) == 0) {
+               if (SVAL(req->inbuf,smb_vwv4) == 0) {
                        setup_new_vc_session();
                }
-               return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
+
+               reply_sesssetup_and_X_spnego(req);
+               END_PROFILE(SMBsesssetupX);
+               return;
        }
 
-       smb_bufsize = SVAL(inbuf,smb_vwv2);
+       smb_bufsize = SVAL(req->inbuf,smb_vwv2);
 
        if (Protocol < PROTOCOL_NT1) {
-               uint16 passlen1 = SVAL(inbuf,smb_vwv7);
+               uint16 passlen1 = SVAL(req->inbuf,smb_vwv7);
 
-               /* Never do NT status codes with protocols before NT1 as we don't get client caps. */
+               /* Never do NT status codes with protocols before NT1 as we
+                * don't get client caps. */
                remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
 
-               if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
-                       return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
+               if ((passlen1 > MAX_PASS_LEN)
+                   || (passlen1 > smb_bufrem(req->inbuf,
+                                             smb_buf(req->inbuf)))) {
+                       reply_nterror(req, nt_status_squash(
+                                             NT_STATUS_INVALID_PARAMETER));
+                       END_PROFILE(SMBsesssetupX);
+                       return;
                }
 
                if (doencrypt) {
-                       lm_resp = data_blob(smb_buf(inbuf), passlen1);
+                       lm_resp = data_blob(smb_buf(req->inbuf), passlen1);
                } else {
-                       plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
+                       plaintext_password = data_blob(smb_buf(req->inbuf),
+                                                      passlen1+1);
                        /* Ensure null termination */
                        plaintext_password.data[passlen1] = 0;
                }
 
-               srvstr_pull_buf(inbuf, smb_flag2, user,
-                               smb_buf(inbuf)+passlen1, sizeof(user),
+               srvstr_pull_buf(req->inbuf, req->flags2, user,
+                               smb_buf(req->inbuf)+passlen1, sizeof(user),
                                STR_TERMINATE);
                *domain = 0;
 
        } else {
-               uint16 passlen1 = SVAL(inbuf,smb_vwv7);
-               uint16 passlen2 = SVAL(inbuf,smb_vwv8);
+               uint16 passlen1 = SVAL(req->inbuf,smb_vwv7);
+               uint16 passlen2 = SVAL(req->inbuf,smb_vwv8);
                enum remote_arch_types ra_type = get_remote_arch();
-               char *p = smb_buf(inbuf);    
-               char *save_p = smb_buf(inbuf);
+               char *p = smb_buf(req->inbuf);
+               char *save_p = smb_buf(req->inbuf);
                uint16 byte_count;
-                       
+
 
                if(global_client_caps == 0) {
-                       global_client_caps = IVAL(inbuf,smb_vwv11);
-               
+                       global_client_caps = IVAL(req->inbuf,smb_vwv11);
+
                        if (!(global_client_caps & CAP_STATUS32)) {
-                               remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
+                               remove_from_common_flags2(
+                                               FLAGS2_32_BIT_ERROR_CODES);
                        }
 
-                       /* 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.
+                       /* 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))) {
+
+                       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 (!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)
+                       /* 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;
+                       }
                }
-               
+
                /* check for nasty tricks */
-               if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
-                       return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
+               if (passlen1 > MAX_PASS_LEN
+                   || passlen1 > smb_bufrem(req->inbuf, p)) {
+                       reply_nterror(req, nt_status_squash(
+                                             NT_STATUS_INVALID_PARAMETER));
+                       END_PROFILE(SMBsesssetupX);
+                       return;
                }
 
-               if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
-                       return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
+               if (passlen2 > MAX_PASS_LEN
+                   || passlen2 > smb_bufrem(req->inbuf, p+passlen1)) {
+                       reply_nterror(req, nt_status_squash(
+                                             NT_STATUS_INVALID_PARAMETER));
+                       END_PROFILE(SMBsesssetupX);
+                       return;
                }
 
                /* Save the lanman2 password and the NT md4 password. */
-               
+
                if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
                        doencrypt = False;
                }
@@ -1357,59 +1485,67 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
                        lm_resp = data_blob(p, passlen1);
                        nt_resp = data_blob(p+passlen1, passlen2);
                } else {
-                       pstring pass;
-                       BOOL unic= smb_flag2 & FLAGS2_UNICODE_STRINGS;
-
-#if 0
-                       /* This was the previous fix. Not sure if it's still valid. JRA. */
-                       if ((ra_type == RA_WINNT) && (passlen2 == 0) && unic && passlen1) {
-                               /* NT4.0 stuffs up plaintext unicode password lengths... */
-                               srvstr_pull(inbuf, pass, smb_buf(inbuf) + 1,
-                                       sizeof(pass), passlen1, STR_TERMINATE);
-#endif
+                       char *pass = NULL;
+                       bool unic= smb_flag2 & FLAGS2_UNICODE_STRINGS;
 
                        if (unic && (passlen2 == 0) && passlen1) {
                                /* Only a ascii plaintext password was sent. */
-                               srvstr_pull(inbuf, smb_flag2, pass,
-                                           smb_buf(inbuf), sizeof(pass),
-                                           passlen1, STR_TERMINATE|STR_ASCII);
+                               (void)srvstr_pull_talloc(talloc_tos(),
+                                                       req->inbuf,
+                                                       req->flags2,
+                                                       &pass,
+                                                       smb_buf(req->inbuf),
+                                                       passlen1,
+                                                       STR_TERMINATE|STR_ASCII);
                        } else {
-                               srvstr_pull(inbuf, smb_flag2, pass,
-                                           smb_buf(inbuf), sizeof(pass),
-                                           unic ? passlen2 : passlen1,
-                                           STR_TERMINATE);
+                               (void)srvstr_pull_talloc(talloc_tos(),
+                                                       req->inbuf,
+                                                       req->flags2,
+                                                       &pass,
+                                                       smb_buf(req->inbuf),
+                                                       unic ? passlen2 : passlen1,
+                                                       STR_TERMINATE);
+                       }
+                       if (!pass) {
+                               reply_nterror(req, nt_status_squash(
+                                             NT_STATUS_INVALID_PARAMETER));
+                               END_PROFILE(SMBsesssetupX);
+                               return;
                        }
                        plaintext_password = data_blob(pass, strlen(pass)+1);
                }
-               
+
                p += passlen1 + passlen2;
-               p += srvstr_pull_buf(inbuf, smb_flag2, user, p,
+               p += srvstr_pull_buf(req->inbuf, req->flags2, user, p,
                                     sizeof(user), STR_TERMINATE);
-               p += srvstr_pull_buf(inbuf, smb_flag2, domain, p,
+               p += srvstr_pull_buf(req->inbuf, req->flags2, domain, p,
                                     sizeof(domain), STR_TERMINATE);
-               p += srvstr_pull_buf(inbuf, smb_flag2, native_os,
+               p += srvstr_pull_buf(req->inbuf, req->flags2, native_os,
                                     p, sizeof(native_os), STR_TERMINATE);
-               p += srvstr_pull_buf(inbuf, smb_flag2,
+               p += srvstr_pull_buf(req->inbuf, req->flags2,
                                     native_lanman, p, sizeof(native_lanman),
                                     STR_TERMINATE);
 
-               /* not documented or decoded by Ethereal but there is one more string 
-                  in the extra bytes which is the same as the PrimaryDomain when using 
-                  extended security.  Windows NT 4 and 2003 use this string to store 
-                  the native lanman string. Windows 9x does not include a string here 
-                  at all so we have to check if we have any extra bytes left */
-               
-               byte_count = SVAL(inbuf, smb_vwv13);
-               if ( PTR_DIFF(p, save_p) < byte_count)
-                       p += srvstr_pull_buf(inbuf, smb_flag2,
+               /* not documented or decoded by Ethereal but there is one more
+                * string in the extra bytes which is the same as the
+                * PrimaryDomain when using extended security.  Windows NT 4
+                * and 2003 use this string to store the native lanman string.
+                * Windows 9x does not include a string here at all so we have
+                * to check if we have any extra bytes left */
+
+               byte_count = SVAL(req->inbuf, smb_vwv13);
+               if ( PTR_DIFF(p, save_p) < byte_count) {
+                       p += srvstr_pull_buf(req->inbuf, req->flags2,
                                             primary_domain, p,
                                             sizeof(primary_domain),
                                             STR_TERMINATE);
-               else 
+               } else {
                        fstrcpy( primary_domain, "null" );
+               }
 
-               DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
-                        domain, native_os, native_lanman, primary_domain));
+               DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s] "
+                       "PrimaryDomain=[%s]\n",
+                       domain, native_os, native_lanman, primary_domain));
 
                if ( ra_type == RA_WIN2K ) {
                        if ( strlen(native_lanman) == 0 )
@@ -1420,19 +1556,26 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
 
        }
 
-       if (SVAL(inbuf,smb_vwv4) == 0) {
+       if (SVAL(req->inbuf,smb_vwv4) == 0) {
                setup_new_vc_session();
        }
 
-       DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
+       DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",
+                               domain, user, get_remote_machine_name()));
 
        if (*user) {
                if (global_spnego_negotiated) {
-                       
-                       /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */
-                       
-                       DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
-                       return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
+
+                       /* This has to be here, because this is a perfectly
+                        * valid behaviour for guest logons :-( */
+
+                       DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt "
+                               "at 'normal' session setup after "
+                               "negotiating spnego.\n"));
+                       reply_nterror(req, nt_status_squash(
+                                             NT_STATUS_LOGON_FAILURE));
+                       END_PROFILE(SMBsesssetupX);
+                       return;
                }
                fstrcpy(sub_user, user);
        } else {
@@ -1442,7 +1585,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
        sub_set_smb_name(sub_user);
 
        reload_services(True);
-       
+
        if (lp_security() == SEC_SHARE) {
                /* in share level we should ignore any passwords */
 
@@ -1456,64 +1599,80 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
                /* Then force it to null for the benfit of the code below */
                *user = 0;
        }
-       
+
        if (!*user) {
 
                nt_status = check_guest_password(&server_info);
 
        } else if (doencrypt) {
                if (!negprot_global_auth_context) {
-                       DEBUG(0, ("reply_sesssetup_and_X:  Attempted encrypted session setup without negprot denied!\n"));
-                       return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
+                       DEBUG(0, ("reply_sesssetup_and_X:  Attempted encrypted "
+                               "session setup without negprot denied!\n"));
+                       reply_nterror(req, nt_status_squash(
+                                             NT_STATUS_LOGON_FAILURE));
+                       END_PROFILE(SMBsesssetupX);
+                       return;
                }
-               nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
-                                                        lm_resp, nt_resp);
+               nt_status = make_user_info_for_reply_enc(&user_info, user,
+                                               domain,
+                                               lm_resp, nt_resp);
                if (NT_STATUS_IS_OK(nt_status)) {
-                       nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context, 
-                                                                                    user_info, 
-                                                                                    &server_info);
+                       nt_status = negprot_global_auth_context->check_ntlm_password(
+                                       negprot_global_auth_context,
+                                       user_info,
+                                       &server_info);
                }
        } else {
                struct auth_context *plaintext_auth_context = NULL;
                const uint8 *chal;
 
-               nt_status = make_auth_context_subsystem(&plaintext_auth_context);
+               nt_status = make_auth_context_subsystem(
+                               &plaintext_auth_context);
 
                if (NT_STATUS_IS_OK(nt_status)) {
-                       chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
-                       
-                       if (!make_user_info_for_reply(&user_info, 
+                       chal = plaintext_auth_context->get_ntlm_challenge(
+                                       plaintext_auth_context);
+
+                       if (!make_user_info_for_reply(&user_info,
                                                      user, domain, chal,
                                                      plaintext_password)) {
                                nt_status = NT_STATUS_NO_MEMORY;
                        }
-               
+
                        if (NT_STATUS_IS_OK(nt_status)) {
-                               nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context, 
-                                                                                       user_info, 
-                                                                                       &server_info); 
-                               
-                               (plaintext_auth_context->free)(&plaintext_auth_context);
+                               nt_status = plaintext_auth_context->check_ntlm_password(
+                                               plaintext_auth_context,
+                                               user_info,
+                                               &server_info);
+
+                               (plaintext_auth_context->free)(
+                                               &plaintext_auth_context);
                        }
                }
        }
 
        free_user_info(&user_info);
-       
+
        if (!NT_STATUS_IS_OK(nt_status)) {
-               nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
+               nt_status = do_map_to_guest(nt_status, &server_info,
+                               user, domain);
        }
-       
+
        if (!NT_STATUS_IS_OK(nt_status)) {
                data_blob_free(&nt_resp);
                data_blob_free(&lm_resp);
                data_blob_clear_free(&plaintext_password);
-               return ERROR_NT(nt_status_squash(nt_status));
+               reply_nterror(req, nt_status_squash(nt_status));
+               END_PROFILE(SMBsesssetupX);
+               return;
        }
 
-       /* Ensure we can't possible take a code path leading to a null defref. */
+       /* Ensure we can't possible take a code path leading to a
+        * null defref. */
        if (!server_info) {
-               return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
+               reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
+               END_PROFILE(SMBsesssetupX);
+               return;
        }
 
        nt_status = create_local_token(server_info);
@@ -1523,28 +1682,29 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
                data_blob_free(&nt_resp);
                data_blob_free(&lm_resp);
                data_blob_clear_free(&plaintext_password);
-               return ERROR_NT(nt_status_squash(nt_status));
+               reply_nterror(req, nt_status_squash(nt_status));
+               END_PROFILE(SMBsesssetupX);
+               return;
        }
 
        if (server_info->user_session_key.data) {
-               session_key = data_blob(server_info->user_session_key.data, server_info->user_session_key.length);
+               session_key = data_blob(server_info->user_session_key.data,
+                               server_info->user_session_key.length);
        } else {
                session_key = data_blob_null;
        }
 
        data_blob_clear_free(&plaintext_password);
-       
+
        /* it's ok - setup a reply */
-       set_message(inbuf,outbuf,3,0,True);
+       reply_outbuf(req, 3, 0);
        if (Protocol >= PROTOCOL_NT1) {
-               char *p = smb_buf( outbuf );
-               p += add_signature( outbuf, p );
-               set_message_end(inbuf, outbuf, p );
+               push_signature(&req->outbuf);
                /* perhaps grab OS version here?? */
        }
-       
+
        if (server_info->guest) {
-               SSVAL(outbuf,smb_vwv2,1);
+               SSVAL(req->outbuf,smb_vwv2,1);
        }
 
        /* register the name and uid as being validated, so further connections
@@ -1555,33 +1715,51 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
                data_blob_free(&session_key);
                TALLOC_FREE(server_info);
        } else {
-               /* register_vuid keeps the server info */
-               sess_vuid = register_vuid(server_info, session_key,
-                                         nt_resp.data ? nt_resp : lm_resp,
-                                         sub_user);
+               /* Ignore the initial vuid. */
+               sess_vuid = register_initial_vuid();
+               if (sess_vuid == UID_FIELD_INVALID) {
+                       data_blob_free(&nt_resp);
+                       data_blob_free(&lm_resp);
+                       data_blob_free(&session_key);
+                       reply_nterror(req, nt_status_squash(
+                                             NT_STATUS_LOGON_FAILURE));
+                       END_PROFILE(SMBsesssetupX);
+                       return;
+               }
+               /* register_existing_vuid keeps the server info */
+               sess_vuid = register_existing_vuid(sess_vuid,
+                                       server_info,
+                                       session_key,
+                                       nt_resp.data ? nt_resp : lm_resp,
+                                       sub_user);
                if (sess_vuid == UID_FIELD_INVALID) {
                        data_blob_free(&nt_resp);
                        data_blob_free(&lm_resp);
-                       return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
+                       data_blob_free(&session_key);
+                       reply_nterror(req, nt_status_squash(
+                                             NT_STATUS_LOGON_FAILURE));
+                       END_PROFILE(SMBsesssetupX);
+                       return;
                }
 
                /* current_user_info is changed on new vuid */
                reload_services( True );
 
-               sessionsetup_start_signing_engine(server_info, inbuf);
+               sessionsetup_start_signing_engine(server_info, req->inbuf);
        }
 
        data_blob_free(&nt_resp);
        data_blob_free(&lm_resp);
-       
-       SSVAL(outbuf,smb_uid,sess_vuid);
-       SSVAL(inbuf,smb_uid,sess_vuid);
-       
+
+       SSVAL(req->outbuf,smb_uid,sess_vuid);
+       SSVAL(req->inbuf,smb_uid,sess_vuid);
+
        if (!done_sesssetup)
                max_send = MIN(max_send,smb_bufsize);
-       
+
        done_sesssetup = True;
-       
+
        END_PROFILE(SMBsesssetupX);
-       return chain_reply(inbuf,outbuf,length,bufsize);
+       chain_reply(req);
+       return;
 }