s3: Fix an uninitialized variable read
[samba.git] / source3 / smbd / sesssetup.c
index 0cfe672a822b87251db2525c730324025d759317..68cb8d3a267a9d8c6cb31e54624fdc85a5c1ac45 100644 (file)
 */
 
 #include "includes.h"
-
-extern struct auth_context *negprot_global_auth_context;
-extern BOOL global_encrypted_passwords_negotiated;
-extern BOOL global_spnego_negotiated;
-extern enum protocol_types Protocol;
-extern int max_send;
-
-uint32 global_client_caps = 0;
+#include "smbd/globals.h"
+#include "../libcli/auth/spnego.h"
+
+/* For split krb5 SPNEGO blobs. */
+struct pending_auth_data {
+       struct pending_auth_data *prev, *next;
+       uint16 vuid; /* Tag for this entry. */
+       uint16 smbpid; /* Alternate tag for this entry. */
+       size_t needed_len;
+       DATA_BLOB partial_data;
+};
 
 /*
   on a logon error possibly map the error to success if "map to guest"
@@ -45,7 +48,7 @@ static NTSTATUS do_map_to_guest(NTSTATUS status,
                    (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
                        DEBUG(3,("No such user %s [%s] - using guest account\n",
                                 user, domain));
-                       status = make_server_info_guest(server_info);
+                       status = make_server_info_guest(NULL, server_info);
                }
        }
 
@@ -53,7 +56,7 @@ static NTSTATUS do_map_to_guest(NTSTATUS status,
                if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
                        DEBUG(3,("Registered username %s for guest access\n",
                                user));
-                       status = make_server_info_guest(server_info);
+                       status = make_server_info_guest(NULL, server_info);
                }
        }
 
@@ -76,7 +79,7 @@ static int push_signature(uint8 **outbuf)
        if (tmp == -1) return -1;
        result += tmp;
 
-       if (asprintf(&lanman, "Samba %s", SAMBA_VERSION_STRING) != -1) {
+       if (asprintf(&lanman, "Samba %s", samba_version_string()) != -1) {
                tmp = message_push_string(outbuf, lanman, STR_TERMINATE);
                SAFE_FREE(lanman);
        }
@@ -95,52 +98,29 @@ static int push_signature(uint8 **outbuf)
        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,
-                       const uint8 *inbuf)
-{
-       if (!server_info->guest && !srv_signing_started()) {
-               /* We need to start the signing engine
-                * here but a W2K client sends the old
-                * "BSRSPYL " signature instead of the
-                * correct one. Subsequent packets will
-                * be correct.
-                */
-               srv_check_sign_mac((char *)inbuf, False);
-       }
-}
-
 /****************************************************************************
  Send a security blob via a session setup reply.
 ****************************************************************************/
 
-static void reply_sesssetup_blob(connection_struct *conn,
-                                struct smb_request *req,
+static void reply_sesssetup_blob(struct smb_request *req,
                                 DATA_BLOB blob,
                                 NTSTATUS 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 {
-               nt_status = nt_status_squash(nt_status);
-               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);
-
-               if ((message_push_blob(&req->outbuf, blob) == -1)
-                   || (push_signature(&req->outbuf) == -1)) {
-                       reply_nterror(req, NT_STATUS_NO_MEMORY);
-               }
+               return;
        }
 
-       show_msg((char *)req->outbuf);
-       send_smb(smbd_server_fd(),(char *)req->outbuf);
-       TALLOC_FREE(req->outbuf);
+       nt_status = nt_status_squash(nt_status);
+       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);
+
+       if ((message_push_blob(&req->outbuf, blob) == -1)
+           || (push_signature(&req->outbuf) == -1)) {
+               reply_nterror(req, NT_STATUS_NO_MEMORY);
+       }
 }
 
 /****************************************************************************
@@ -186,14 +166,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;
 
@@ -247,11 +227,11 @@ static BOOL make_krb5_skew_error(DATA_BLOB *pblob_out)
  Reply to a session setup spnego negotiate packet for kerberos.
 ****************************************************************************/
 
-static void reply_spnego_kerberos(connection_struct *conn,
-                                 struct smb_request *req,
+static void reply_spnego_kerberos(struct smb_request *req,
                                  DATA_BLOB *secblob,
+                                 const char *mechOID,
                                  uint16 vuid,
-                                 BOOL *p_invalidate_vuid)
+                                 bool *p_invalidate_vuid)
 {
        TALLOC_CTX *mem_ctx;
        DATA_BLOB ticket;
@@ -261,19 +241,19 @@ static void reply_spnego_kerberos(connection_struct *conn,
        fstring user;
        int sess_vuid = req->vuid;
        NTSTATUS ret = NT_STATUS_OK;
-       PAC_DATA *pac_data;
+       struct PAC_DATA *pac_data = NULL;
        DATA_BLOB ap_rep, ap_rep_wrapped, response;
        auth_serversupplied_info *server_info = NULL;
        DATA_BLOB session_key = data_blob_null;
        uint8 tok_id[2];
        DATA_BLOB nullblob = data_blob_null;
        fstring real_username;
-       BOOL map_domainuser_to_guest = False;
-       BOOL username_was_mapped;
-       PAC_LOGON_INFO *logon_info = NULL;
+       bool map_domainuser_to_guest = False;
+       bool username_was_mapped;
+       struct PAC_LOGON_INFO *logon_info = NULL;
+       struct smbd_server_connection *sconn = smbd_server_conn;
 
        ZERO_STRUCT(ticket);
-       ZERO_STRUCT(pac_data);
        ZERO_STRUCT(ap_rep);
        ZERO_STRUCT(ap_rep_wrapped);
        ZERO_STRUCT(response);
@@ -316,7 +296,7 @@ static void reply_spnego_kerberos(connection_struct *conn,
                         * -- 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(
@@ -362,7 +342,6 @@ static void reply_spnego_kerberos(connection_struct *conn,
                DEBUG(3,("Doesn't look like a valid principal\n"));
                data_blob_free(&ap_rep);
                data_blob_free(&session_key);
-               SAFE_FREE(client);
                talloc_destroy(mem_ctx);
                reply_nterror(req,nt_status_squash(NT_STATUS_LOGON_FAILURE));
                return;
@@ -384,7 +363,6 @@ static void reply_spnego_kerberos(connection_struct *conn,
                if (!lp_allow_trusted_domains()) {
                        data_blob_free(&ap_rep);
                        data_blob_free(&session_key);
-                       SAFE_FREE(client);
                        talloc_destroy(mem_ctx);
                        reply_nterror(req, nt_status_squash(
                                              NT_STATUS_LOGON_FAILURE));
@@ -397,10 +375,9 @@ static void 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);
+       if (logon_info && logon_info->info3.base.domain.string) {
+               fstrcpy(netbios_domain_name,
+                       logon_info->info3.base.domain.string);
                domain = netbios_domain_name;
                DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));
 
@@ -413,30 +390,24 @@ static void reply_spnego_kerberos(connection_struct *conn,
                   name. And even w2k3 does use ntlmssp if you for example
                   connect to an ip address. */
 
-               struct winbindd_request wb_request;
-               struct winbindd_response wb_response;
-               NSS_STATUS wb_result;
-
-               ZERO_STRUCT(wb_request);
-               ZERO_STRUCT(wb_response);
+               wbcErr wbc_status;
+               struct wbcDomainInfo *info = NULL;
 
                DEBUG(10, ("Mapping [%s] to short name\n", domain));
 
-               fstrcpy(wb_request.domain_name, domain);
-
-               wb_result = winbindd_request_response(WINBINDD_DOMAIN_INFO,
-                                            &wb_request, &wb_response);
+               wbc_status = wbcDomainInfo(domain, &info);
 
-               if (wb_result == NSS_STATUS_SUCCESS) {
+               if (WBC_ERROR_IS_OK(wbc_status)) {
 
                        fstrcpy(netbios_domain_name,
-                               wb_response.data.domain_info.name);
-                       domain = netbios_domain_name;
+                               info->short_name);
 
+                       wbcFreeMemory(info);
+                       domain = netbios_domain_name;
                        DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain));
                } else {
-                       DEBUG(3, ("Could not find short name -- winbind "
-                                 "not running?\n"));
+                       DEBUG(3, ("Could not find short name: %s\n",
+                               wbcErrorString(wbc_status)));
                }
        }
 
@@ -444,14 +415,14 @@ static void reply_spnego_kerberos(connection_struct *conn,
 
        /* lookup the passwd struct, create a new user if necessary */
 
-       username_was_mapped = map_username( user );
+       username_was_mapped = map_username(sconn, user);
 
        pw = smb_getpwnam( mem_ctx, user, real_username, True );
 
        if (pw) {
                /* if a real user check pam account restrictions */
                /* only really perfomed if "obey pam restriction" is true */
-               /* do this before an eventual mappign to guest occurs */
+               /* do this before an eventual mapping to guest occurs */
                ret = smb_pam_accountcheck(pw->pw_name);
                if (  !NT_STATUS_IS_OK(ret)) {
                        DEBUG(1,("PAM account restriction "
@@ -481,7 +452,6 @@ static void reply_spnego_kerberos(connection_struct *conn,
                if ( !pw ) {
                        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);
@@ -497,7 +467,7 @@ static void reply_spnego_kerberos(connection_struct *conn,
        reload_services(True);
 
        if ( map_domainuser_to_guest ) {
-               make_server_info_guest(&server_info);
+               make_server_info_guest(NULL, &server_info);
        } else if (logon_info) {
                /* pass the unmapped username here since map_username()
                   will be called again from inside make_server_info_info3() */
@@ -507,7 +477,6 @@ static void reply_spnego_kerberos(connection_struct *conn,
                if ( !NT_STATUS_IS_OK(ret) ) {
                        DEBUG(1,("make_server_info_info3 failed: %s!\n",
                                 nt_errstr(ret)));
-                       SAFE_FREE(client);
                        data_blob_free(&ap_rep);
                        data_blob_free(&session_key);
                        TALLOC_FREE(mem_ctx);
@@ -516,12 +485,41 @@ static void reply_spnego_kerberos(connection_struct *conn,
                }
 
        } else {
-               ret = make_server_info_pw(&server_info, real_username, pw);
+               /*
+                * We didn't get a PAC, we have to make up the user
+                * ourselves. Try to ask the pdb backend to provide
+                * SID consistency with ntlmssp session setup
+                */
+               struct samu *sampass;
+
+               sampass = samu_new(talloc_tos());
+               if (sampass == NULL) {
+                       ret = NT_STATUS_NO_MEMORY;
+                       data_blob_free(&ap_rep);
+                       data_blob_free(&session_key);
+                       TALLOC_FREE(mem_ctx);
+                       reply_nterror(req, nt_status_squash(ret));
+                       return;
+               }
+
+               if (pdb_getsampwnam(sampass, real_username)) {
+                       DEBUG(10, ("found user %s in passdb, calling "
+                                  "make_server_info_sam\n", real_username));
+                       ret = make_server_info_sam(&server_info, sampass);
+               } else {
+                       /*
+                        * User not in passdb, make it up artificially
+                        */
+                       TALLOC_FREE(sampass);
+                       DEBUG(10, ("didn't find user %s in passdb, calling "
+                                  "make_server_info_pw\n", real_username));
+                       ret = make_server_info_pw(&server_info, real_username,
+                                                 pw);
+               }
 
                if ( !NT_STATUS_IS_OK(ret) ) {
-                       DEBUG(1,("make_server_info_pw failed: %s!\n",
+                       DEBUG(1,("make_server_info_[sam|pw] failed: %s!\n",
                                 nt_errstr(ret)));
-                       SAFE_FREE(client);
                        data_blob_free(&ap_rep);
                        data_blob_free(&session_key);
                        TALLOC_FREE(mem_ctx);
@@ -539,7 +537,7 @@ static void reply_spnego_kerberos(connection_struct *conn,
                }
        }
 
-       server_info->was_mapped |= username_was_mapped;
+       server_info->nss_token |= username_was_mapped;
 
        /* we need to build the token for the user. make_server_info_guest()
           already does this */
@@ -547,7 +545,8 @@ static void reply_spnego_kerberos(connection_struct *conn,
        if ( !server_info->ptok ) {
                ret = create_local_token( server_info );
                if ( !NT_STATUS_IS_OK(ret) ) {
-                       SAFE_FREE(client);
+                       DEBUG(10,("failed to create local token: %s\n",
+                               nt_errstr(ret)));
                        data_blob_free(&ap_rep);
                        data_blob_free(&session_key);
                        TALLOC_FREE( mem_ctx );
@@ -557,28 +556,30 @@ static void reply_spnego_kerberos(connection_struct *conn,
                }
        }
 
+       if (!is_partial_auth_vuid(sconn, sess_vuid)) {
+               sess_vuid = register_initial_vuid(sconn);
+       }
+
+       data_blob_free(&server_info->user_session_key);
+       server_info->user_session_key = session_key;
+       session_key = data_blob_null;
+
        /* 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,
+       sess_vuid = register_existing_vuid(sconn,
+                                       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 );
@@ -591,7 +592,6 @@ static void reply_spnego_kerberos(connection_struct *conn,
 
                SSVAL(req->outbuf, smb_uid, sess_vuid);
 
-               sessionsetup_start_signing_engine(server_info, req->inbuf);
                /* Successful logon. Keep this vuid. */
                *p_invalidate_vuid = False;
        }
@@ -604,8 +604,8 @@ static void reply_spnego_kerberos(connection_struct *conn,
                ap_rep_wrapped = data_blob_null;
        }
        response = spnego_gen_auth_response(&ap_rep_wrapped, ret,
-                       OID_KERBEROS5_OLD);
-       reply_sesssetup_blob(conn, req, response, ret);
+                       mechOID);
+       reply_sesssetup_blob(req, response, ret);
 
        data_blob_free(&ap_rep);
        data_blob_free(&ap_rep_wrapped);
@@ -623,15 +623,16 @@ static void reply_spnego_kerberos(connection_struct *conn,
  leg of the NTLM auth steps.
 ***************************************************************************/
 
-static void reply_spnego_ntlmssp(connection_struct *conn,
-                                struct smb_request *req,
+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)
+                                const char *OID,
+                                bool wrap)
 {
        DATA_BLOB response;
        struct auth_serversupplied_info *server_info = NULL;
+       struct smbd_server_connection *sconn = smbd_server_conn;
 
        if (NT_STATUS_IS_OK(nt_status)) {
                server_info = (*auth_ntlmssp_state)->server_info;
@@ -648,23 +649,24 @@ static void reply_spnego_ntlmssp(connection_struct *conn,
 
        if (NT_STATUS_IS_OK(nt_status)) {
                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);
 
-               if (!is_partial_auth_vuid(vuid)) {
-                       data_blob_free(&session_key);
+               if (!is_partial_auth_vuid(sconn, vuid)) {
                        nt_status = NT_STATUS_LOGON_FAILURE;
                        goto out;
                }
+
+               data_blob_free(&server_info->user_session_key);
+               server_info->user_session_key =
+                       data_blob_talloc(
+                       server_info,
+                       (*auth_ntlmssp_state)->ntlmssp_state->session_key.data,
+                       (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
+
                /* register_existing_vuid keeps the server info */
-               if (register_existing_vuid(vuid,
-                               server_info,
-                               session_key, nullblob,
+               if (register_existing_vuid(sconn, vuid,
+                               server_info, nullblob,
                                (*auth_ntlmssp_state)->ntlmssp_state->user) !=
                                        vuid) {
-                       data_blob_free(&session_key);
                        nt_status = NT_STATUS_LOGON_FAILURE;
                        goto out;
                }
@@ -679,21 +681,18 @@ static void reply_spnego_ntlmssp(connection_struct *conn,
                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);
+                               nt_status, OID);
        } else {
                response = *ntlmssp_blob;
        }
 
-       reply_sesssetup_blob(conn, req, response, nt_status);
+       reply_sesssetup_blob(req, response, nt_status);
        if (wrap) {
                data_blob_free(&response);
        }
@@ -706,7 +705,7 @@ static void reply_spnego_ntlmssp(connection_struct *conn,
                auth_ntlmssp_end(auth_ntlmssp_state);
                if (!NT_STATUS_IS_OK(nt_status)) {
                        /* Kill the intermediate vuid */
-                       invalidate_vuid(vuid);
+                       invalidate_vuid(sconn, vuid);
                }
        }
 }
@@ -715,13 +714,15 @@ static void reply_spnego_ntlmssp(connection_struct *conn,
  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,
+               char **kerb_mechOID)
 {
        char *OIDs[ASN1_MAX_OIDS];
        int i;
+       NTSTATUS ret = NT_STATUS_OK;
 
-       *p_is_krb5 = False;
+       *kerb_mechOID = NULL;
 
        /* parse out the OIDs and the first sec blob */
        if (!parse_negTokenTarg(blob_in, OIDs, pblob_out)) {
@@ -741,37 +742,61 @@ NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in, DATA_BLOB *pblob_out,
 #ifdef HAVE_KRB5
        if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
            strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
-               *p_is_krb5 = True;
+               *kerb_mechOID = SMB_STRDUP(OIDs[0]);
+               if (*kerb_mechOID == NULL) {
+                       ret = NT_STATUS_NO_MEMORY;
+               }
        }
 #endif
 
        for (i=0;OIDs[i];i++) {
                DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
-               free(OIDs[i]);
+               talloc_free(OIDs[i]);
        }
-       return NT_STATUS_OK;
+       return ret;
+}
+
+/****************************************************************************
+ Fall back from krb5 to NTLMSSP.
+****************************************************************************/
+
+static void reply_spnego_downgrade_to_ntlmssp(struct smb_request *req,
+                                               uint16 vuid)
+{
+       DATA_BLOB response;
+
+       reply_outbuf(req, 4, 0);
+        SSVAL(req->outbuf,smb_uid,vuid);
+
+       DEBUG(3,("reply_spnego_downgrade_to_ntlmssp: Got krb5 ticket in SPNEGO "
+               "but set to downgrade to NTLMSSP\n"));
+
+       response = spnego_gen_auth_response(NULL,
+                       NT_STATUS_MORE_PROCESSING_REQUIRED,
+                       OID_NTLMSSP);
+       reply_sesssetup_blob(req, response, NT_STATUS_MORE_PROCESSING_REQUIRED);
+       data_blob_free(&response);
 }
 
 /****************************************************************************
  Reply to a session setup spnego negotiate packet.
 ****************************************************************************/
 
-static void reply_spnego_negotiate(connection_struct *conn,
-                                  struct smb_request *req,
+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;
+       char *kerb_mech = NULL;
        NTSTATUS status;
+       struct smbd_server_connection *sconn = smbd_server_conn;
 
-       status = parse_spnego_mechanisms(blob1, &secblob,
-                       &got_kerberos_mechanism);
+       status = parse_spnego_mechanisms(blob1, &secblob, &kerb_mech);
        if (!NT_STATUS_IS_OK(status)) {
                /* Kill the intermediate vuid */
-               invalidate_vuid(vuid);
+               invalidate_vuid(sconn, vuid);
                reply_nterror(req, nt_status_squash(status));
                return;
        }
@@ -780,16 +805,17 @@ static void reply_spnego_negotiate(connection_struct *conn,
                                (unsigned long)secblob.length));
 
 #ifdef HAVE_KRB5
-       if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) ||
-                               lp_use_kerberos_keytab()) ) {
-               BOOL destroy_vuid = True;
-               reply_spnego_kerberos(conn, req, &secblob, vuid,
-                                     &destroy_vuid);
+       if (kerb_mech && ((lp_security()==SEC_ADS) ||
+                               USE_KERBEROS_KEYTAB) ) {
+               bool destroy_vuid = True;
+               reply_spnego_kerberos(req, &secblob, kerb_mech,
+                                     vuid, &destroy_vuid);
                data_blob_free(&secblob);
                if (destroy_vuid) {
                        /* Kill the intermediate vuid */
-                       invalidate_vuid(vuid);
+                       invalidate_vuid(sconn, vuid);
                }
+               SAFE_FREE(kerb_mech);
                return;
        }
 #endif
@@ -798,10 +824,19 @@ static void reply_spnego_negotiate(connection_struct *conn,
                auth_ntlmssp_end(auth_ntlmssp_state);
        }
 
+       if (kerb_mech) {
+               data_blob_free(&secblob);
+               /* The mechtoken is a krb5 ticket, but
+                * we need to fall back to NTLM. */
+               reply_spnego_downgrade_to_ntlmssp(req, vuid);
+               SAFE_FREE(kerb_mech);
+               return;
+       }
+
        status = auth_ntlmssp_start(auth_ntlmssp_state);
        if (!NT_STATUS_IS_OK(status)) {
                /* Kill the intermediate vuid */
-               invalidate_vuid(vuid);
+               invalidate_vuid(sconn, vuid);
                reply_nterror(req, nt_status_squash(status));
                return;
        }
@@ -811,8 +846,8 @@ static void reply_spnego_negotiate(connection_struct *conn,
 
        data_blob_free(&secblob);
 
-       reply_spnego_ntlmssp(conn, req, vuid, auth_ntlmssp_state,
-                            &chal, status, True);
+       reply_spnego_ntlmssp(req, vuid, auth_ntlmssp_state,
+                            &chal, status, OID_NTLMSSP, true);
 
        data_blob_free(&chal);
 
@@ -824,8 +859,7 @@ static void reply_spnego_negotiate(connection_struct *conn,
  Reply to a session setup spnego auth packet.
 ****************************************************************************/
 
-static void reply_spnego_auth(connection_struct *conn,
-                             struct smb_request *req,
+static void reply_spnego_auth(struct smb_request *req,
                              uint16 vuid,
                              DATA_BLOB blob1,
                              AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
@@ -833,44 +867,65 @@ static void reply_spnego_auth(connection_struct *conn,
        DATA_BLOB auth = data_blob_null;
        DATA_BLOB auth_reply = data_blob_null;
        DATA_BLOB secblob = data_blob_null;
-       NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
+       NTSTATUS status = NT_STATUS_LOGON_FAILURE;
+       struct smbd_server_connection *sconn = smbd_server_conn;
 
        if (!spnego_parse_auth(blob1, &auth)) {
 #if 0
                file_save("auth.dat", blob1.data, blob1.length);
 #endif
                /* Kill the intermediate vuid */
-               invalidate_vuid(vuid);
+               invalidate_vuid(sconn, vuid);
 
                reply_nterror(req, nt_status_squash(
-                                     NT_STATUS_INVALID_PARAMETER));
+                                     NT_STATUS_LOGON_FAILURE));
                return;
        }
 
        if (auth.data[0] == ASN1_APPLICATION(0)) {
                /* Might be a second negTokenTarg packet */
+               char *kerb_mech = NULL;
 
-               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));
+               status = parse_spnego_mechanisms(auth, &secblob, &kerb_mech);
+
+               if (!NT_STATUS_IS_OK(status)) {
+                       /* Kill the intermediate vuid */
+                       invalidate_vuid(sconn, vuid);
+                       reply_nterror(req, nt_status_squash(status));
+                       return;
+               }
+
+               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;
-                               reply_spnego_kerberos(conn, req, &secblob,
-                                                     vuid, &destroy_vuid);
-                               data_blob_free(&secblob);
-                               data_blob_free(&auth);
-                               if (destroy_vuid) {
-                                       /* Kill the intermediate vuid */
-                                       invalidate_vuid(vuid);
-                               }
-                               return;
+               if (kerb_mech && ((lp_security()==SEC_ADS) ||
+                                       USE_KERBEROS_KEYTAB)) {
+                       bool destroy_vuid = True;
+                       reply_spnego_kerberos(req, &secblob, kerb_mech,
+                                             vuid, &destroy_vuid);
+                       data_blob_free(&secblob);
+                       data_blob_free(&auth);
+                       if (destroy_vuid) {
+                               /* Kill the intermediate vuid */
+                               invalidate_vuid(sconn, vuid);
                        }
+                       SAFE_FREE(kerb_mech);
+                       return;
+               }
 #endif
+               /* Can't blunder into NTLMSSP auth if we have
+                * a krb5 ticket. */
+
+               if (kerb_mech) {
+                       /* Kill the intermediate vuid */
+                       invalidate_vuid(sconn, vuid);
+                       DEBUG(3,("reply_spnego_auth: network "
+                               "misconfiguration, client sent us a "
+                               "krb5 ticket and kerberos security "
+                               "not enabled\n"));
+                       reply_nterror(req, nt_status_squash(
+                                       NT_STATUS_LOGON_FAILURE));
+                       SAFE_FREE(kerb_mech);
                }
        }
 
@@ -878,13 +933,13 @@ static void reply_spnego_auth(connection_struct *conn,
        data_blob_free(&secblob);
 
        if (!*auth_ntlmssp_state) {
-               /* Kill the intermediate vuid */
-               invalidate_vuid(vuid);
-
-               /* auth before negotiatiate? */
-               reply_nterror(req, nt_status_squash(
-                                     NT_STATUS_INVALID_PARAMETER));
-               return;
+               status = auth_ntlmssp_start(auth_ntlmssp_state);
+               if (!NT_STATUS_IS_OK(status)) {
+                       /* Kill the intermediate vuid */
+                       invalidate_vuid(sconn, vuid);
+                       reply_nterror(req, nt_status_squash(status));
+                       return;
+               }
        }
 
        status = auth_ntlmssp_update(*auth_ntlmssp_state,
@@ -892,9 +947,11 @@ static void reply_spnego_auth(connection_struct *conn,
 
        data_blob_free(&auth);
 
-       reply_spnego_ntlmssp(conn, req, vuid,
+       /* Don't send the mechid as we've already sent this (RFC4178). */
+
+       reply_spnego_ntlmssp(req, vuid,
                             auth_ntlmssp_state,
-                            &auth_reply, status, True);
+                            &auth_reply, status, NULL, true);
 
        data_blob_free(&auth_reply);
 
@@ -902,22 +959,17 @@ static void reply_spnego_auth(connection_struct *conn,
        return;
 }
 
-/****************************************************************************
- List to store partial SPNEGO auth fragments.
-****************************************************************************/
-
-static struct pending_auth_data *pd_list;
-
 /****************************************************************************
  Delete an entry on the list.
 ****************************************************************************/
 
-static void delete_partial_auth(struct pending_auth_data *pad)
+static void delete_partial_auth(struct smbd_server_connection *sconn,
+                               struct pending_auth_data *pad)
 {
        if (!pad) {
                return;
        }
-       DLIST_REMOVE(pd_list, pad);
+       DLIST_REMOVE(sconn->smb1.pd_list, pad);
        data_blob_free(&pad->partial_data);
        SAFE_FREE(pad);
 }
@@ -926,11 +978,17 @@ static void delete_partial_auth(struct pending_auth_data *pad)
  Search for a partial SPNEGO auth fragment matching an smbpid.
 ****************************************************************************/
 
-static struct pending_auth_data *get_pending_auth_data(uint16 smbpid)
+static struct pending_auth_data *get_pending_auth_data(
+               struct smbd_server_connection *sconn,
+               uint16_t smbpid)
 {
        struct pending_auth_data *pad;
-
-       for (pad = pd_list; pad; pad = pad->next) {
+/*
+ * NOTE: using the smbpid here is completely wrong...
+ *       see [MS-SMB]
+ *       3.3.5.3 Receiving an SMB_COM_SESSION_SETUP_ANDX Request
+ */
+       for (pad = sconn->smb1.pd_list; pad; pad = pad->next) {
                if (pad->smbpid == smbpid) {
                        break;
                }
@@ -944,20 +1002,21 @@ static struct pending_auth_data *get_pending_auth_data(uint16 smbpid)
  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(struct smbd_server_connection *sconn,
+                                          uint16 smbpid, uint16 vuid,
+                                          DATA_BLOB *pblob)
 {
        struct pending_auth_data *pad = NULL;
-       ASN1_DATA data;
+       ASN1_DATA *data;
        size_t needed_len = 0;
 
-       pad = get_pending_auth_data(smbpid);
+       pad = get_pending_auth_data(sconn, smbpid);
 
        /* Ensure we have some data. */
        if (pblob->length == 0) {
                /* Caller can cope. */
                DEBUG(2,("check_spnego_blob_complete: zero blob length !\n"));
-               delete_partial_auth(pad);
+               delete_partial_auth(sconn, pad);
                return NT_STATUS_OK;
        }
 
@@ -978,7 +1037,7 @@ static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid,
                                (unsigned int)pad->partial_data.length,
                                (unsigned int)copy_len ));
 
-                       delete_partial_auth(pad);
+                       delete_partial_auth(sconn, pad);
                        return NT_STATUS_INVALID_PARAMETER;
                }
 
@@ -1014,7 +1073,7 @@ static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid,
                        data_blob_free(pblob);
                        *pblob = pad->partial_data;
                        ZERO_STRUCT(pad->partial_data);
-                       delete_partial_auth(pad);
+                       delete_partial_auth(sconn, pad);
                        return NT_STATUS_OK;
                }
 
@@ -1035,34 +1094,39 @@ static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid,
         * the data given in this blob is enough.
         */
 
-       asn1_load(&data, *pblob);
-       asn1_start_tag(&data, pblob->data[0]);
-       if (data.has_error || data.nesting == NULL) {
-               asn1_free(&data);
+       data = asn1_init(NULL);
+       if (data == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       asn1_load(data, *pblob);
+       asn1_start_tag(data, pblob->data[0]);
+       if (data->has_error || data->nesting == NULL) {
+               asn1_free(data);
                /* Let caller catch. */
                return NT_STATUS_OK;
        }
 
        /* Integer wrap paranoia.... */
 
-       if (data.nesting->taglen + data.nesting->start < data.nesting->taglen ||
-           data.nesting->taglen + data.nesting->start < data.nesting->start) {
+       if (data->nesting->taglen + data->nesting->start < data->nesting->taglen ||
+           data->nesting->taglen + data->nesting->start < data->nesting->start) {
 
                DEBUG(2,("check_spnego_blob_complete: integer wrap "
                        "data.nesting->taglen = %u, "
                        "data.nesting->start = %u\n",
-                       (unsigned int)data.nesting->taglen,
-                       (unsigned int)data.nesting->start ));
+                       (unsigned int)data->nesting->taglen,
+                       (unsigned int)data->nesting->start ));
 
-               asn1_free(&data);
+               asn1_free(data);
                return NT_STATUS_INVALID_PARAMETER;
        }
 
        /* Total length of the needed asn1 is the tag length
         * plus the current offset. */
 
-       needed_len = data.nesting->taglen + data.nesting->start;
-       asn1_free(&data);
+       needed_len = data->nesting->taglen + data->nesting->start;
+       asn1_free(data);
 
        DEBUG(10,("check_spnego_blob_complete: needed_len = %u, "
                "pblob->length = %u\n",
@@ -1094,7 +1158,7 @@ static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid,
        }
        pad->smbpid = smbpid;
        pad->vuid = vuid;
-       DLIST_ADD(pd_list, pad);
+       DLIST_ADD(sconn->smb1.pd_list, pad);
 
        return NT_STATUS_MORE_PROCESSING_REQUIRED;
 }
@@ -1104,26 +1168,28 @@ static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid,
  conn POINTER CAN BE NULL HERE !
 ****************************************************************************/
 
-static void reply_sesssetup_and_X_spnego(connection_struct *conn,
-                                        struct smb_request *req)
+static void reply_sesssetup_and_X_spnego(struct smb_request *req)
 {
-       uint8 *p;
+       const uint8 *p;
        DATA_BLOB blob1;
        size_t bufrem;
-       fstring native_os, native_lanman, primary_domain;
+       char *tmp;
+       const char *native_os;
+       const char *native_lanman;
+       const char *primary_domain;
        const char *p2;
-       uint16 data_blob_len = SVAL(req->inbuf, smb_vwv7);
+       uint16 data_blob_len = SVAL(req->vwv+7, 0);
        enum remote_arch_types ra_type = get_remote_arch();
-       int vuid = SVAL(req->inbuf,smb_uid);
+       int vuid = req->vuid;
        user_struct *vuser = NULL;
        NTSTATUS status = NT_STATUS_OK;
        uint16 smbpid = req->smbpid;
-       uint16 smb_flag2 = req->flags2;
+       struct smbd_server_connection *sconn = smbd_server_conn;
 
        DEBUG(3,("Doing spnego session setup\n"));
 
        if (global_client_caps == 0) {
-               global_client_caps = IVAL(req->inbuf,smb_vwv10);
+               global_client_caps = IVAL(req->vwv+10, 0);
 
                if (!(global_client_caps & CAP_STATUS32)) {
                        remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
@@ -1131,7 +1197,7 @@ static void reply_sesssetup_and_X_spnego(connection_struct *conn,
 
        }
 
-       p = (uint8 *)smb_buf(req->inbuf);
+       p = req->buf;
 
        if (data_blob_len == 0) {
                /* an invalid request */
@@ -1139,7 +1205,7 @@ static void reply_sesssetup_and_X_spnego(connection_struct *conn,
                return;
        }
 
-       bufrem = smb_bufrem(req->inbuf, p);
+       bufrem = smbreq_bufrem(req, p);
        /* pull the spnego blob */
        blob1 = data_blob(p, MIN(bufrem, data_blob_len));
 
@@ -1147,13 +1213,20 @@ static void reply_sesssetup_and_X_spnego(connection_struct *conn,
        file_save("negotiate.dat", blob1.data, blob1.length);
 #endif
 
-       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(req->inbuf, smb_flag2, native_lanman, p2,
-                             sizeof(native_lanman), STR_TERMINATE);
-       p2 += srvstr_pull_buf(req->inbuf, smb_flag2, primary_domain, p2,
-                             sizeof(primary_domain), STR_TERMINATE);
+       p2 = (char *)req->buf + blob1.length;
+
+       p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
+                                    STR_TERMINATE);
+       native_os = tmp ? tmp : "";
+
+       p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
+                                    STR_TERMINATE);
+       native_lanman = tmp ? tmp : "";
+
+       p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
+                                    STR_TERMINATE);
+       primary_domain = tmp ? tmp : "";
+
        DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
                native_os, native_lanman, primary_domain));
 
@@ -1174,10 +1247,11 @@ static void reply_sesssetup_and_X_spnego(connection_struct *conn,
        }
 
        /* Did we get a valid vuid ? */
-       if (!is_partial_auth_vuid(vuid)) {
+       if (!is_partial_auth_vuid(sconn, 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);
+               struct pending_auth_data *pad;
+               pad = get_pending_auth_data(sconn, smbpid);
                if (pad) {
                        DEBUG(10,("reply_sesssetup_and_X_spnego: found "
                                "pending vuid %u\n",
@@ -1187,9 +1261,9 @@ static void reply_sesssetup_and_X_spnego(connection_struct *conn,
        }
 
        /* Do we have a valid vuid now ? */
-       if (!is_partial_auth_vuid(vuid)) {
+       if (!is_partial_auth_vuid(sconn, vuid)) {
                /* No, start a new authentication setup. */
-               vuid = register_initial_vuid();
+               vuid = register_initial_vuid(sconn);
                if (vuid == UID_FIELD_INVALID) {
                        data_blob_free(&blob1);
                        reply_nterror(req, nt_status_squash(
@@ -1198,7 +1272,7 @@ static void reply_sesssetup_and_X_spnego(connection_struct *conn,
                }
        }
 
-       vuser = get_partial_auth_user_struct(vuid);
+       vuser = get_partial_auth_user_struct(sconn, vuid);
        /* This MUST be valid. */
        if (!vuser) {
                smb_panic("reply_sesssetup_and_X_spnego: invalid vuid.");
@@ -1209,12 +1283,12 @@ static void reply_sesssetup_and_X_spnego(connection_struct *conn,
         * field is 4k. Bug #4400. JRA.
         */
 
-       status = check_spnego_blob_complete(smbpid, vuid, &blob1);
+       status = check_spnego_blob_complete(sconn, smbpid, vuid, &blob1);
        if (!NT_STATUS_IS_OK(status)) {
                if (!NT_STATUS_EQUAL(status,
                                NT_STATUS_MORE_PROCESSING_REQUIRED)) {
                        /* Real error - kill the intermediate vuid */
-                       invalidate_vuid(vuid);
+                       invalidate_vuid(sconn, vuid);
                }
                data_blob_free(&blob1);
                reply_nterror(req, nt_status_squash(status));
@@ -1225,7 +1299,7 @@ static void reply_sesssetup_and_X_spnego(connection_struct *conn,
 
                /* its a negTokenTarg packet */
 
-               reply_spnego_negotiate(conn, req, vuid, blob1,
+               reply_spnego_negotiate(req, vuid, blob1,
                                       &vuser->auth_ntlmssp_state);
                data_blob_free(&blob1);
                return;
@@ -1235,7 +1309,7 @@ static void reply_sesssetup_and_X_spnego(connection_struct *conn,
 
                /* its a auth packet */
 
-               reply_spnego_auth(conn, req, vuid, blob1,
+               reply_spnego_auth(req, vuid, blob1,
                                  &vuser->auth_ntlmssp_state);
                data_blob_free(&blob1);
                return;
@@ -1248,7 +1322,7 @@ static void reply_sesssetup_and_X_spnego(connection_struct *conn,
                        status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
                        if (!NT_STATUS_IS_OK(status)) {
                                /* Kill the intermediate vuid */
-                               invalidate_vuid(vuid);
+                               invalidate_vuid(sconn, vuid);
                                data_blob_free(&blob1);
                                reply_nterror(req, nt_status_squash(status));
                                return;
@@ -1260,9 +1334,9 @@ static void reply_sesssetup_and_X_spnego(connection_struct *conn,
 
                data_blob_free(&blob1);
 
-               reply_spnego_ntlmssp(conn, req, vuid,
+               reply_spnego_ntlmssp(req, vuid,
                                     &vuser->auth_ntlmssp_state,
-                                    &chal, status, False);
+                                    &chal, status, OID_NTLMSSP, false);
                data_blob_free(&chal);
                return;
        }
@@ -1300,6 +1374,9 @@ static int shutdown_other_smbds(struct db_record *rec,
                return 0;
        }
 
+       DEBUG(0,("shutdown_other_smbds: shutting down pid %u "
+                "(IP %s)\n", (unsigned int)procid_to_pid(&crec->pid), ip));
+
        messaging_send(smbd_messaging_context(), crec->pid, MSG_SHUTDOWN,
                       &data_blob_null);
        return 0;
@@ -1307,6 +1384,8 @@ static int shutdown_other_smbds(struct db_record *rec,
 
 static void setup_new_vc_session(void)
 {
+       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
@@ -1314,7 +1393,9 @@ static void setup_new_vc_session(void)
        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))));
        }
 }
 
@@ -1322,29 +1403,28 @@ static void setup_new_vc_session(void)
  Reply to a session setup command.
 ****************************************************************************/
 
-void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req)
+void reply_sesssetup_and_X(struct smb_request *req)
 {
        int sess_vuid;
        int smb_bufsize;
        DATA_BLOB lm_resp;
        DATA_BLOB nt_resp;
        DATA_BLOB plaintext_password;
-       fstring user;
+       char *tmp;
+       const char *user;
        fstring sub_user; /* Sainitised username for substituion */
-       fstring domain;
-       fstring native_os;
-       fstring native_lanman;
-       fstring primary_domain;
-       static BOOL done_sesssetup = False;
+       const char *domain;
+       const char *native_os;
+       const char *native_lanman;
+       const char *primary_domain;
        auth_usersupplied_info *user_info = NULL;
        auth_serversupplied_info *server_info = NULL;
        uint16 smb_flag2 = req->flags2;
 
        NTSTATUS nt_status;
+       struct smbd_server_connection *sconn = smbd_server_conn;
 
-       BOOL doencrypt = global_encrypted_passwords_negotiated;
-
-       DATA_BLOB session_key;
+       bool doencrypt = sconn->smb1.negprot.encrypted_passwords;
 
        START_PROFILE(SMBsesssetupX);
 
@@ -1359,7 +1439,7 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req)
        if (req->wct == 12 &&
            (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
 
-               if (!global_spnego_negotiated) {
+               if (!sconn->smb1.negprot.spnego) {
                        DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt "
                                 "at SPNEGO session setup when it was not "
                                 "negotiated.\n"));
@@ -1369,27 +1449,25 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req)
                        return;
                }
 
-               if (SVAL(req->inbuf,smb_vwv4) == 0) {
+               if (SVAL(req->vwv+4, 0) == 0) {
                        setup_new_vc_session();
                }
 
-               reply_sesssetup_and_X_spnego(conn, req);
+               reply_sesssetup_and_X_spnego(req);
                END_PROFILE(SMBsesssetupX);
                return;
        }
 
-       smb_bufsize = SVAL(req->inbuf,smb_vwv2);
+       smb_bufsize = SVAL(req->vwv+2, 0);
 
-       if (Protocol < PROTOCOL_NT1) {
-               uint16 passlen1 = SVAL(req->inbuf,smb_vwv7);
+       if (get_Protocol() < PROTOCOL_NT1) {
+               uint16 passlen1 = SVAL(req->vwv+7, 0);
 
                /* 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(req->inbuf,
-                                             smb_buf(req->inbuf)))) {
+               if ((passlen1 > MAX_PASS_LEN) || (passlen1 > req->buflen)) {
                        reply_nterror(req, nt_status_squash(
                                              NT_STATUS_INVALID_PARAMETER));
                        END_PROFILE(SMBsesssetupX);
@@ -1397,30 +1475,30 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req)
                }
 
                if (doencrypt) {
-                       lm_resp = data_blob(smb_buf(req->inbuf), passlen1);
+                       lm_resp = data_blob(req->buf, passlen1);
                } else {
-                       plaintext_password = data_blob(smb_buf(req->inbuf),
-                                                      passlen1+1);
+                       plaintext_password = data_blob(req->buf, passlen1+1);
                        /* Ensure null termination */
                        plaintext_password.data[passlen1] = 0;
                }
 
-               srvstr_pull_buf(req->inbuf, req->flags2, user,
-                               smb_buf(req->inbuf)+passlen1, sizeof(user),
-                               STR_TERMINATE);
-               *domain = 0;
+               srvstr_pull_req_talloc(talloc_tos(), req, &tmp,
+                                      req->buf + passlen1, STR_TERMINATE);
+               user = tmp ? tmp : "";
+
+               domain = "";
 
        } else {
-               uint16 passlen1 = SVAL(req->inbuf,smb_vwv7);
-               uint16 passlen2 = SVAL(req->inbuf,smb_vwv8);
+               uint16 passlen1 = SVAL(req->vwv+7, 0);
+               uint16 passlen2 = SVAL(req->vwv+8, 0);
                enum remote_arch_types ra_type = get_remote_arch();
-               char *p = smb_buf(req->inbuf);
-               char *save_p = smb_buf(req->inbuf);
+               const uint8_t *p = req->buf;
+               const uint8_t *save_p = req->buf;
                uint16 byte_count;
 
 
                if(global_client_caps == 0) {
-                       global_client_caps = IVAL(req->inbuf,smb_vwv11);
+                       global_client_caps = IVAL(req->vwv+11, 0);
 
                        if (!(global_client_caps & CAP_STATUS32)) {
                                remove_from_common_flags2(
@@ -1462,7 +1540,7 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req)
 
                /* check for nasty tricks */
                if (passlen1 > MAX_PASS_LEN
-                   || passlen1 > smb_bufrem(req->inbuf, p)) {
+                   || passlen1 > smbreq_bufrem(req, p)) {
                        reply_nterror(req, nt_status_squash(
                                              NT_STATUS_INVALID_PARAMETER));
                        END_PROFILE(SMBsesssetupX);
@@ -1470,7 +1548,7 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req)
                }
 
                if (passlen2 > MAX_PASS_LEN
-                   || passlen2 > smb_bufrem(req->inbuf, p+passlen1)) {
+                   || passlen2 > smbreq_bufrem(req, p+passlen1)) {
                        reply_nterror(req, nt_status_squash(
                                              NT_STATUS_INVALID_PARAMETER));
                        END_PROFILE(SMBsesssetupX);
@@ -1486,45 +1564,58 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req)
                if (doencrypt) {
                        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
+               } else if (lp_security() != SEC_SHARE) {
+                       /*
+                        * In share level we should ignore any passwords, so
+                        * only read them if we're not.
+                        */
+                       char *pass = NULL;
+                       bool unic= smb_flag2 & FLAGS2_UNICODE_STRINGS;
 
                        if (unic && (passlen2 == 0) && passlen1) {
                                /* Only a ascii plaintext password was sent. */
-                               srvstr_pull(req->inbuf, req->flags2, pass,
-                                           smb_buf(req->inbuf), sizeof(pass),
-                                           passlen1, STR_TERMINATE|STR_ASCII);
+                               (void)srvstr_pull_talloc(talloc_tos(),
+                                                       req->inbuf,
+                                                       req->flags2,
+                                                       &pass,
+                                                       req->buf,
+                                                       passlen1,
+                                                       STR_TERMINATE|STR_ASCII);
                        } else {
-                               srvstr_pull(req->inbuf, req->flags2, pass,
-                                           smb_buf(req->inbuf), sizeof(pass),
-                                           unic ? passlen2 : passlen1,
-                                           STR_TERMINATE);
+                               (void)srvstr_pull_talloc(talloc_tos(),
+                                                       req->inbuf,
+                                                       req->flags2,
+                                                       &pass,
+                                                       req->buf,
+                                                       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(req->inbuf, req->flags2, user, p,
-                                    sizeof(user), STR_TERMINATE);
-               p += srvstr_pull_buf(req->inbuf, req->flags2, domain, p,
-                                    sizeof(domain), STR_TERMINATE);
-               p += srvstr_pull_buf(req->inbuf, req->flags2, native_os,
-                                    p, sizeof(native_os), STR_TERMINATE);
-               p += srvstr_pull_buf(req->inbuf, req->flags2,
-                                    native_lanman, p, sizeof(native_lanman),
-                                    STR_TERMINATE);
+
+               p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
+                                           STR_TERMINATE);
+               user = tmp ? tmp : "";
+
+               p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
+                                           STR_TERMINATE);
+               domain = tmp ? tmp : "";
+
+               p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
+                                           STR_TERMINATE);
+               native_os = tmp ? tmp : "";
+
+               p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
+                                           STR_TERMINATE);
+               native_lanman = tmp ? tmp : "";
 
                /* not documented or decoded by Ethereal but there is one more
                 * string in the extra bytes which is the same as the
@@ -1533,14 +1624,13 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req)
                 * 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);
+               byte_count = SVAL(req->vwv+13, 0);
                if ( PTR_DIFF(p, save_p) < byte_count) {
-                       p += srvstr_pull_buf(req->inbuf, req->flags2,
-                                            primary_domain, p,
-                                            sizeof(primary_domain),
-                                            STR_TERMINATE);
+                       p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
+                                                   STR_TERMINATE);
+                       primary_domain = tmp ? tmp : "";
                } else {
-                       fstrcpy( primary_domain, "null" );
+                       primary_domain = talloc_strdup(talloc_tos(), "null");
                }
 
                DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s] "
@@ -1556,7 +1646,7 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req)
 
        }
 
-       if (SVAL(req->inbuf,smb_vwv4) == 0) {
+       if (SVAL(req->vwv+4, 0) == 0) {
                setup_new_vc_session();
        }
 
@@ -1564,7 +1654,7 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req)
                                domain, user, get_remote_machine_name()));
 
        if (*user) {
-               if (global_spnego_negotiated) {
+               if (sconn->smb1.negprot.spnego) {
 
                        /* This has to be here, because this is a perfectly
                         * valid behaviour for guest logons :-( */
@@ -1587,17 +1677,17 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req)
        reload_services(True);
 
        if (lp_security() == SEC_SHARE) {
-               /* in share level we should ignore any passwords */
+               /* In share level we should ignore any passwords */
 
                data_blob_free(&lm_resp);
                data_blob_free(&nt_resp);
                data_blob_clear_free(&plaintext_password);
 
-               map_username(sub_user);
-               add_session_user(sub_user);
-               add_session_workgroup(domain);
+               map_username(sconn, sub_user);
+               add_session_user(sconn, sub_user);
+               add_session_workgroup(sconn, domain);
                /* Then force it to null for the benfit of the code below */
-               *user = 0;
+               user = "";
        }
 
        if (!*user) {
@@ -1605,7 +1695,9 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req)
                nt_status = check_guest_password(&server_info);
 
        } else if (doencrypt) {
-               if (!negprot_global_auth_context) {
+               struct auth_context *negprot_auth_context = NULL;
+               negprot_auth_context = sconn->smb1.negprot.auth_context;
+               if (!negprot_auth_context) {
                        DEBUG(0, ("reply_sesssetup_and_X:  Attempted encrypted "
                                "session setup without negprot denied!\n"));
                        reply_nterror(req, nt_status_squash(
@@ -1617,21 +1709,22 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req)
                                                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,
+                       nt_status = negprot_auth_context->check_ntlm_password(
+                                       negprot_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);
 
                if (NT_STATUS_IS_OK(nt_status)) {
-                       chal = plaintext_auth_context->get_ntlm_challenge(
-                                       plaintext_auth_context);
+                       uint8_t chal[8];
+
+                       plaintext_auth_context->get_ntlm_challenge(
+                                       plaintext_auth_context, chal);
 
                        if (!make_user_info_for_reply(&user_info,
                                                      user, domain, chal,
@@ -1675,30 +1768,26 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req)
                return;
        }
 
-       nt_status = create_local_token(server_info);
-       if (!NT_STATUS_IS_OK(nt_status)) {
-               DEBUG(10, ("create_local_token failed: %s\n",
-                          nt_errstr(nt_status)));
-               data_blob_free(&nt_resp);
-               data_blob_free(&lm_resp);
-               data_blob_clear_free(&plaintext_password);
-               reply_nterror(req, nt_status_squash(nt_status));
-               END_PROFILE(SMBsesssetupX);
-               return;
-       }
+       if (!server_info->ptok) {
+               nt_status = create_local_token(server_info);
 
-       if (server_info->user_session_key.data) {
-               session_key = data_blob(server_info->user_session_key.data,
-                               server_info->user_session_key.length);
-       } else {
-               session_key = data_blob_null;
+               if (!NT_STATUS_IS_OK(nt_status)) {
+                       DEBUG(10, ("create_local_token failed: %s\n",
+                                  nt_errstr(nt_status)));
+                       data_blob_free(&nt_resp);
+                       data_blob_free(&lm_resp);
+                       data_blob_clear_free(&plaintext_password);
+                       reply_nterror(req, nt_status_squash(nt_status));
+                       END_PROFILE(SMBsesssetupX);
+                       return;
+               }
        }
 
        data_blob_clear_free(&plaintext_password);
 
        /* it's ok - setup a reply */
        reply_outbuf(req, 3, 0);
-       if (Protocol >= PROTOCOL_NT1) {
+       if (get_Protocol() >= PROTOCOL_NT1) {
                push_signature(&req->outbuf);
                /* perhaps grab OS version here?? */
        }
@@ -1712,30 +1801,26 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req)
 
        if (lp_security() == SEC_SHARE) {
                sess_vuid = UID_FIELD_INVALID;
-               data_blob_free(&session_key);
                TALLOC_FREE(server_info);
        } else {
                /* Ignore the initial vuid. */
-               sess_vuid = register_initial_vuid();
+               sess_vuid = register_initial_vuid(sconn);
                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,
+               sess_vuid = register_existing_vuid(sconn, 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);
-                       data_blob_free(&session_key);
                        reply_nterror(req, nt_status_squash(
                                              NT_STATUS_LOGON_FAILURE));
                        END_PROFILE(SMBsesssetupX);
@@ -1744,8 +1829,6 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req)
 
                /* current_user_info is changed on new vuid */
                reload_services( True );
-
-               sessionsetup_start_signing_engine(server_info, req->inbuf);
        }
 
        data_blob_free(&nt_resp);
@@ -1753,13 +1836,15 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req)
 
        SSVAL(req->outbuf,smb_uid,sess_vuid);
        SSVAL(req->inbuf,smb_uid,sess_vuid);
+       req->vuid = sess_vuid;
 
-       if (!done_sesssetup)
-               max_send = MIN(max_send,smb_bufsize);
-
-       done_sesssetup = True;
+       if (!sconn->smb1.sessions.done_sesssetup) {
+               sconn->smb1.sessions.max_send =
+                       MIN(sconn->smb1.sessions.max_send,smb_bufsize);
+       }
+       sconn->smb1.sessions.done_sesssetup = true;
 
        END_PROFILE(SMBsesssetupX);
-       chain_reply_new(req);
+       chain_reply(req);
        return;
 }