Changes all over the shop, but all towards:
authorAndrew Bartlett <abartlet@samba.org>
Sat, 22 Nov 2003 13:19:38 +0000 (13:19 +0000)
committerAndrew Bartlett <abartlet@samba.org>
Sat, 22 Nov 2003 13:19:38 +0000 (13:19 +0000)
 - NTLM2 support in the server
 - KEY_EXCH support in the server
 - variable length session keys.

In detail:

 - NTLM2 is an extension of NTLMv1, that is compatible with existing
domain controllers (unlike NTLMv2, which requires a DC upgrade).

 * This is known as 'NTLMv2 session security' *

(This is not yet implemented on the RPC pipes however, so there may
well still be issues for PDC setups, particuarly around password
changes.  We do not fully understand the sign/seal implications of
NTLM2 on RPC pipes.)

This requires modifications to our authentication subsystem, as we
must handle the 'challege' input into the challenge-response algorithm
being changed.  This also needs to be turned off for
'security=server', which does not support this.

- KEY_EXCH is another 'security' mechanism, whereby the session key
actually used by the server is sent by the client, rather than being
the shared-secret directly or indirectly.

- As both these methods change the session key, the auth subsystem
needed to be changed, to 'override' session keys provided by the
backend.

- There has also been a major overhaul of the NTLMSSP subsystem, to merge the 'client' and 'server' functions, so they both operate on a single structure.  This should help the SPNEGO implementation.

- The 'names blob' in NTLMSSP is always in unicode - never in ascii.
Don't make an ascii version ever.

- The other big change is to allow variable length session keys.  We
have always assumed that session keys are 16 bytes long - and padded
to this length if shorter.  However, Kerberos session keys are 8 bytes
long, when the krb5 login uses DES.

 * This fix allows SMB signging on machines not yet running MIT KRB5 1.3.1. *

- Add better DEBUG() messages to ntlm_auth, warning administrators of
misconfigurations that prevent access to the privileged pipe.  This
should help reduce some of the 'it just doesn't work' issues.

- Fix data_blob_talloc() to behave the same way data_blob() does when
passed a NULL data pointer.  (just allocate)

REMEMBER to make clean after this commit - I have changed plenty of data structures...
(This used to be commit f3bbc87b0dac63426cda6fac7a295d3aad810ecc)

35 files changed:
source3/auth/auth.c
source3/auth/auth_ntlmssp.c
source3/auth/auth_sam.c
source3/auth/auth_util.c
source3/include/auth.h
source3/include/client.h
source3/include/includes.h
source3/include/ntdomain.h
source3/include/ntlmssp.h
source3/include/smb.h
source3/lib/data_blob.c
source3/libads/kerberos_verify.c
source3/libsmb/cliconnect.c
source3/libsmb/clientgen.c
source3/libsmb/clikrb5.c
source3/libsmb/clispnego.c
source3/libsmb/ntlmssp.c
source3/libsmb/ntlmssp_parse.c
source3/libsmb/ntlmssp_sign.c
source3/libsmb/smb_signing.c
source3/libsmb/smbencrypt.c
source3/nsswitch/winbindd_cm.c
source3/nsswitch/winbindd_pam.c
source3/rpc_client/cli_netlogon.c
source3/rpc_client/cli_pipe.c
source3/rpc_client/cli_samr.c
source3/rpc_parse/parse_net.c
source3/rpc_parse/parse_samr.c
source3/rpc_server/srv_netlog_nt.c
source3/rpc_server/srv_pipe.c
source3/rpc_server/srv_pipe_hnd.c
source3/rpc_server/srv_samr_nt.c
source3/smbd/password.c
source3/smbd/sesssetup.c
source3/utils/ntlm_auth.c

index 553d9a686e31b82a6d52b4c5088d1aa67bd12d01..20dccc65924431f974409c8c981a8a080eeb3e97 100644 (file)
@@ -88,6 +88,8 @@ static const uint8 *get_ntlm_challenge(struct auth_context *auth_context)
                return auth_context->challenge.data;
        }
 
+       auth_context->challenge_may_be_modified = False;
+
        for (auth_method = auth_context->auth_method_list; auth_method; auth_method = auth_method->next) {
                if (auth_method->get_chal == NULL) {
                        DEBUG(5, ("auth_get_challenge: module %s did not want to specify a challenge\n", auth_method->name));
@@ -127,6 +129,7 @@ static const uint8 *get_ntlm_challenge(struct auth_context *auth_context)
                                                           chal, sizeof(chal));
                
                challenge_set_by = "random";
+               auth_context->challenge_may_be_modified = True;
        } 
        
        DEBUG(5, ("auth_context challenge created by %s\n", challenge_set_by));
index 3af0cbaada4fe76dd920847453bc5cad70905315..a5ce101e5e7360b46e458918f0e6dacd549ad2ff 100644 (file)
 
 #include "includes.h"
 
-static const uint8 *auth_ntlmssp_get_challenge(struct ntlmssp_state *ntlmssp_state)
+/**
+ * Return the challenge as determined by the authentication subsystem 
+ * @return an 8 byte random challenge
+ */
+
+static const uint8 *auth_ntlmssp_get_challenge(const struct ntlmssp_state *ntlmssp_state)
 {
        AUTH_NTLMSSP_STATE *auth_ntlmssp_state = ntlmssp_state->auth_context;
        return auth_ntlmssp_state->auth_context->get_ntlm_challenge(auth_ntlmssp_state->auth_context);
 }
 
-static NTSTATUS auth_ntlmssp_check_password(struct ntlmssp_state *ntlmssp_state) 
+/**
+ * Some authentication methods 'fix' the challenge, so we may not be able to set it
+ *
+ * @return If the effective challenge used by the auth subsystem may be modified
+ */
+static BOOL auth_ntlmssp_may_set_challenge(const struct ntlmssp_state *ntlmssp_state)
+{
+       AUTH_NTLMSSP_STATE *auth_ntlmssp_state = ntlmssp_state->auth_context;
+       struct auth_context *auth_context = auth_ntlmssp_state->auth_context;
+
+       return auth_context->challenge_may_be_modified;
+}
+
+/**
+ * NTLM2 authentication modifies the effective challange, 
+ * @param challenge The new challenge value
+ */
+static NTSTATUS auth_ntlmssp_set_challenge(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *challenge)
+{
+       AUTH_NTLMSSP_STATE *auth_ntlmssp_state = ntlmssp_state->auth_context;
+       struct auth_context *auth_context = auth_ntlmssp_state->auth_context;
+
+       SMB_ASSERT(challenge->length == 8);
+
+       auth_context->challenge = data_blob_talloc(auth_context->mem_ctx, 
+                                                  challenge->data, challenge->length);
+
+       auth_context->challenge_set_by = "NTLMSSP callback (NTLM2)";
+
+       DEBUG(5, ("auth_context challenge set by %s\n", auth_context->challenge_set_by));
+       DEBUG(5, ("challenge is: \n"));
+       dump_data(5, (const char *)auth_context->challenge.data, auth_context->challenge.length);
+       return NT_STATUS_OK;
+}
+
+/**
+ * Check the password on an NTLMSSP login.  
+ *
+ * Return the session keys used on the connection.
+ */
+
+static NTSTATUS auth_ntlmssp_check_password(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *nt_session_key, DATA_BLOB *lm_session_key) 
 {
        AUTH_NTLMSSP_STATE *auth_ntlmssp_state = ntlmssp_state->auth_context;
        uint32 auth_flags = AUTH_FLAG_NONE;
@@ -45,7 +91,7 @@ static NTSTATUS auth_ntlmssp_check_password(struct ntlmssp_state *ntlmssp_state)
                auth_flags |= AUTH_FLAG_NTLM_RESP;
        } else  if (auth_ntlmssp_state->ntlmssp_state->nt_resp.length > 24) {
                auth_flags |= AUTH_FLAG_NTLMv2_RESP;
-       };
+       }
 
        /* the client has given us its machine name (which we otherwise would not get on port 445).
           we need to possibly reload smb.conf if smb.conf includes depend on the machine name */
@@ -71,10 +117,26 @@ static NTSTATUS auth_ntlmssp_check_password(struct ntlmssp_state *ntlmssp_state)
                return nt_status;
        }
 
-       nt_status = auth_ntlmssp_state->auth_context->check_ntlm_password(auth_ntlmssp_state->auth_context, user_info, &auth_ntlmssp_state->server_info); 
-                       
+       nt_status = auth_ntlmssp_state->auth_context->check_ntlm_password(auth_ntlmssp_state->auth_context, 
+                                                                         user_info, &auth_ntlmssp_state->server_info); 
+
        free_user_info(&user_info);
 
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               return nt_status;
+       }
+       if (auth_ntlmssp_state->server_info->nt_session_key.length) {
+               DEBUG(10, ("Got NT session key of length %u\n", auth_ntlmssp_state->server_info->nt_session_key.length));
+               *nt_session_key = data_blob_talloc(auth_ntlmssp_state->mem_ctx, 
+                                                  auth_ntlmssp_state->server_info->nt_session_key.data,
+                                                  auth_ntlmssp_state->server_info->nt_session_key.length);
+       }
+       if (auth_ntlmssp_state->server_info->lm_session_key.length) {
+               DEBUG(10, ("Got LM session key of length %u\n", auth_ntlmssp_state->server_info->lm_session_key.length));
+               *lm_session_key = data_blob_talloc(auth_ntlmssp_state->mem_ctx, 
+                                                  auth_ntlmssp_state->server_info->lm_session_key.data,
+                                                  auth_ntlmssp_state->server_info->lm_session_key.length);
+       }
        return nt_status;
 }
 
@@ -106,18 +168,20 @@ NTSTATUS auth_ntlmssp_start(AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
 
        (*auth_ntlmssp_state)->ntlmssp_state->auth_context = (*auth_ntlmssp_state);
        (*auth_ntlmssp_state)->ntlmssp_state->get_challenge = auth_ntlmssp_get_challenge;
+       (*auth_ntlmssp_state)->ntlmssp_state->may_set_challenge = auth_ntlmssp_may_set_challenge;
+       (*auth_ntlmssp_state)->ntlmssp_state->set_challenge = auth_ntlmssp_set_challenge;
        (*auth_ntlmssp_state)->ntlmssp_state->check_password = auth_ntlmssp_check_password;
        (*auth_ntlmssp_state)->ntlmssp_state->server_role = lp_server_role();
 
        return NT_STATUS_OK;
 }
 
-NTSTATUS auth_ntlmssp_end(AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
+void auth_ntlmssp_end(AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
 {
        TALLOC_CTX *mem_ctx = (*auth_ntlmssp_state)->mem_ctx;
 
        if ((*auth_ntlmssp_state)->ntlmssp_state) {
-               ntlmssp_server_end(&(*auth_ntlmssp_state)->ntlmssp_state);
+               ntlmssp_end(&(*auth_ntlmssp_state)->ntlmssp_state);
        }
        if ((*auth_ntlmssp_state)->auth_context) {
                ((*auth_ntlmssp_state)->auth_context->free)(&(*auth_ntlmssp_state)->auth_context);
@@ -127,11 +191,10 @@ NTSTATUS auth_ntlmssp_end(AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
        }
        talloc_destroy(mem_ctx);
        *auth_ntlmssp_state = NULL;
-       return NT_STATUS_OK;
 }
 
 NTSTATUS auth_ntlmssp_update(AUTH_NTLMSSP_STATE *auth_ntlmssp_state, 
                             const DATA_BLOB request, DATA_BLOB *reply) 
 {
-       return ntlmssp_server_update(auth_ntlmssp_state->ntlmssp_state, request, reply);
+       return ntlmssp_update(auth_ntlmssp_state->ntlmssp_state, request, reply);
 }
index 2a00b6fb807712fd93a5e544b77650d4b835003b..7352a9685be2b3b3680822fbfe5a833462818dc3 100644 (file)
@@ -33,7 +33,7 @@
 static BOOL smb_pwd_check_ntlmv1(const DATA_BLOB *nt_response,
                                 const uchar *part_passwd,
                                 const DATA_BLOB *sec_blob,
-                                uint8 user_sess_key[16])
+                                DATA_BLOB *user_sess_key)
 {
        /* Finish the encryption of part_passwd. */
        uchar p24[24];
@@ -56,7 +56,8 @@ static BOOL smb_pwd_check_ntlmv1(const DATA_BLOB *nt_response,
 
        SMBOWFencrypt(part_passwd, sec_blob->data, p24);
        if (user_sess_key != NULL) {
-               SMBsesskeygen_ntv1(part_passwd, NULL, user_sess_key);
+               *user_sess_key = data_blob(NULL, 16);
+               SMBsesskeygen_ntv1(part_passwd, NULL, user_sess_key->data);
        }
        
        
@@ -83,7 +84,7 @@ static BOOL smb_pwd_check_ntlmv2(const DATA_BLOB *ntv2_response,
                                 const uchar *part_passwd,
                                 const DATA_BLOB *sec_blob,
                                 const char *user, const char *domain,
-                                uint8 user_sess_key[16])
+                                DATA_BLOB *user_sess_key)
 {
        /* Finish the encryption of part_passwd. */
        uchar kr[16];
@@ -120,7 +121,8 @@ static BOOL smb_pwd_check_ntlmv2(const DATA_BLOB *ntv2_response,
 
        SMBOWFencrypt_ntv2(kr, sec_blob, &client_key_data, value_from_encryption);
        if (user_sess_key != NULL) {
-               SMBsesskeygen_ntv2(kr, value_from_encryption, user_sess_key);
+               *user_sess_key = data_blob(NULL, 16);
+               SMBsesskeygen_ntv2(kr, value_from_encryption, user_sess_key->data);
        }
 
 #if DEBUG_PASSWORD
@@ -148,7 +150,8 @@ static NTSTATUS sam_password_ok(const struct auth_context *auth_context,
                                TALLOC_CTX *mem_ctx,
                                SAM_ACCOUNT *sampass, 
                                const auth_usersupplied_info *user_info, 
-                               uint8 user_sess_key[16])
+                               DATA_BLOB *user_sess_key, 
+                               DATA_BLOB *lm_sess_key)
 {
        uint16 acct_ctrl;
        const uint8 *nt_pw, *lm_pw;
@@ -225,6 +228,16 @@ static NTSTATUS sam_password_ok(const struct auth_context *auth_context,
                        if (smb_pwd_check_ntlmv1(&user_info->nt_resp, 
                                                 nt_pw, &auth_context->challenge,
                                                 user_sess_key)) {
+                               /* The LM session key for this response is not very secure, 
+                                  so use it only if we otherwise allow LM authentication */
+                               lm_pw = pdb_get_lanman_passwd(sampass);
+
+                               if (lp_lanman_auth() && lm_pw) {
+                                       uint8 first_8_lm_hash[16];
+                                       memcpy(first_8_lm_hash, lm_pw, 8);
+                                       memset(first_8_lm_hash + 8, '\0', 8);
+                                       *lm_sess_key = data_blob(first_8_lm_hash, 16);
+                               }
                                return NT_STATUS_OK;
                        } else {
                                DEBUG(3,("sam_password_ok: NT MD4 password check failed for user %s\n",pdb_get_username(sampass)));
@@ -252,7 +265,12 @@ static NTSTATUS sam_password_ok(const struct auth_context *auth_context,
                        DEBUG(4,("sam_password_ok: Checking LM password\n"));
                        if (smb_pwd_check_ntlmv1(&user_info->lm_resp, 
                                                 lm_pw, &auth_context->challenge,
-                                                user_sess_key)) {
+                                                NULL)) {
+                               uint8 first_8_lm_hash[16];
+                               memcpy(first_8_lm_hash, lm_pw, 8);
+                               memset(first_8_lm_hash + 8, '\0', 8);
+                               *user_sess_key = data_blob(first_8_lm_hash, 16);
+                               *lm_sess_key = data_blob(first_8_lm_hash, 16);
                                return NT_STATUS_OK;
                        }
                }
@@ -272,7 +290,7 @@ static NTSTATUS sam_password_ok(const struct auth_context *auth_context,
                                          nt_pw, &auth_context->challenge, 
                                          user_info->smb_name.str, 
                                          user_info->client_domain.str,
-                                         user_sess_key)) {
+                                         NULL)) {
                        return NT_STATUS_OK;
                }
 
@@ -281,7 +299,7 @@ static NTSTATUS sam_password_ok(const struct auth_context *auth_context,
                                          nt_pw, &auth_context->challenge, 
                                          user_info->smb_name.str, 
                                          "",
-                                         user_sess_key)) {
+                                         NULL)) {
                        return NT_STATUS_OK;
                }
 
@@ -292,7 +310,19 @@ static NTSTATUS sam_password_ok(const struct auth_context *auth_context,
                if (lp_ntlm_auth()) {
                        if (smb_pwd_check_ntlmv1(&user_info->lm_resp, 
                                                 nt_pw, &auth_context->challenge,
-                                                user_sess_key)) {
+                                                NULL)) {
+                               /* The session key for this response is still very odd.  
+                                  It not very secure, so use it only if we otherwise 
+                                  allow LM authentication */
+                               lm_pw = pdb_get_lanman_passwd(sampass);
+                       
+                               if (lp_lanman_auth() && lm_pw) {
+                                       uint8 first_8_lm_hash[16];
+                                       memcpy(first_8_lm_hash, lm_pw, 8);
+                                       memset(first_8_lm_hash + 8, '\0', 8);
+                                       *user_sess_key = data_blob(first_8_lm_hash, 16);
+                                       *lm_sess_key = data_blob(first_8_lm_hash, 16);
+                               }
                                return NT_STATUS_OK;
                        }
                        DEBUG(3,("sam_password_ok: LM password, NT MD4 password in LM field and LMv2 failed for user %s\n",pdb_get_username(sampass)));
@@ -301,7 +331,6 @@ static NTSTATUS sam_password_ok(const struct auth_context *auth_context,
                        DEBUG(3,("sam_password_ok: LM password and LMv2 failed for user %s, and NT MD4 password in LM field not permitted\n",pdb_get_username(sampass)));
                        return NT_STATUS_WRONG_PASSWORD;
                }
-                       
        }
                
        /* Should not be reached, but if they send nothing... */
@@ -421,8 +450,8 @@ static NTSTATUS check_sam_security(const struct auth_context *auth_context,
        SAM_ACCOUNT *sampass=NULL;
        BOOL ret;
        NTSTATUS nt_status;
-       uint8 user_sess_key[16];
-       const uint8* lm_hash;
+       DATA_BLOB user_sess_key = data_blob(NULL, 0);
+       DATA_BLOB lm_sess_key = data_blob(NULL, 0);
 
        if (!user_info || !auth_context) {
                return NT_STATUS_UNSUCCESSFUL;
@@ -446,7 +475,8 @@ static NTSTATUS check_sam_security(const struct auth_context *auth_context,
                return NT_STATUS_NO_SUCH_USER;
        }
 
-       nt_status = sam_password_ok(auth_context, mem_ctx, sampass, user_info, user_sess_key);
+       nt_status = sam_password_ok(auth_context, mem_ctx, sampass, 
+                                   user_info, &user_sess_key, &lm_sess_key);
        
        if (!NT_STATUS_IS_OK(nt_status)) {
                pdb_free_sam(&sampass);
@@ -465,12 +495,8 @@ static NTSTATUS check_sam_security(const struct auth_context *auth_context,
                return nt_status;
        }
 
-       lm_hash = pdb_get_lanman_passwd((*server_info)->sam_account);
-       if (lm_hash) {
-               memcpy((*server_info)->first_8_lm_hash, lm_hash, 8);
-       }
-       
-       memcpy((*server_info)->session_key, user_sess_key, sizeof(user_sess_key));
+       (*server_info)->nt_session_key = user_sess_key;
+       (*server_info)->lm_session_key = lm_sess_key;
 
        return nt_status;
 }
index d7d7f53e2d4898c7133d04c16591585c5695c877..5d3f8f02777b2b120bd45b2ce65418283704aa4b 100644 (file)
@@ -900,7 +900,13 @@ NTSTATUS make_server_info_guest(auth_serversupplied_info **server_info)
        nt_status = make_server_info_sam(server_info, sampass);
 
        if (NT_STATUS_IS_OK(nt_status)) {
+               static const char zeros[16];
                (*server_info)->guest = True;
+               
+               /* annoying, but the Guest really does have a session key, 
+                  and it is all zeros! */
+               (*server_info)->nt_session_key = data_blob(zeros, sizeof(zeros));
+               (*server_info)->lm_session_key = data_blob(zeros, sizeof(zeros));
        }
 
        return nt_status;
@@ -992,6 +998,8 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx,
                                auth_serversupplied_info **server_info, 
                                NET_USER_INFO_3 *info3) 
 {
+       static const char zeros[16];
+
        NTSTATUS nt_status = NT_STATUS_OK;
        char *found_username;
        const char *nt_domain;
@@ -1210,10 +1218,20 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx,
        (*server_info)->ptok = token; 
 
        SAFE_FREE(all_group_SIDs);
+
+       /* ensure we are never given NULL session keys */
        
-       memcpy((*server_info)->session_key, info3->user_sess_key, sizeof((*server_info)->session_key)/* 16 */);
-       memcpy((*server_info)->first_8_lm_hash, info3->padding, 8);
+       if (memcmp(info3->user_sess_key, zeros, sizeof(zeros)) == 0) {
+               (*server_info)->nt_session_key = data_blob(NULL, 0);
+       } else {
+               (*server_info)->nt_session_key = data_blob(info3->user_sess_key, sizeof(info3->user_sess_key));
+       }
 
+       if (memcmp(info3->padding, zeros, sizeof(zeros)) == 0) {
+               (*server_info)->lm_session_key = data_blob(NULL, 0);
+       } else {
+               (*server_info)->lm_session_key = data_blob(info3->padding, 16);
+       }
        return NT_STATUS_OK;
 }
 
@@ -1256,6 +1274,8 @@ void free_server_info(auth_serversupplied_info **server_info)
                delete_nt_token( &(*server_info)->ptok );
                SAFE_FREE((*server_info)->groups);
                SAFE_FREE((*server_info)->unix_name);
+               data_blob_free(&(*server_info)->lm_session_key);
+               data_blob_free(&(*server_info)->nt_session_key);
                ZERO_STRUCT(**server_info);
        }
        SAFE_FREE(*server_info);
index 6b42418be8d4d3dce1d1f22509c017225068d95f..ecf4d539d8c032826fc14c0eb4f07742a9eb3f00 100644 (file)
@@ -87,10 +87,9 @@ typedef struct auth_serversupplied_info
        
        NT_USER_TOKEN *ptok;
        
-       uint8 session_key[16];
+       DATA_BLOB nt_session_key;
+       DATA_BLOB lm_session_key;
        
-       uint8 first_8_lm_hash[8];
-
        uint32 sam_fill_level;  /* How far is this structure filled? */
        
        SAM_ACCOUNT *sam_account;
@@ -107,6 +106,8 @@ struct auth_context {
        /* Who set this up in the first place? */ 
        const char *challenge_set_by; 
 
+       BOOL challenge_may_be_modified;
+
        struct auth_methods *challenge_set_method; 
        /* What order are the various methods in?   Try to stop it changing under us */ 
        struct auth_methods *auth_method_list;  
index 598e6c0bda521ef72251cddabc20238c377e4a52..968b73f0b41cdaadd6eee576b5f880e9795d1b3c 100644 (file)
@@ -113,7 +113,7 @@ struct cli_state {
 
        /* the session key for this CLI, outside 
           any per-pipe authenticaion */
-       unsigned char user_session_key[16];
+       DATA_BLOB user_session_key;
 
        /*
         * Only used in NT domain calls.
@@ -133,7 +133,7 @@ struct cli_state {
                                               schannel. */
        struct netsec_auth_struct auth_info;
 
-       NTLMSSP_CLIENT_STATE *ntlmssp_pipe_state;
+       NTLMSSP_STATE *ntlmssp_pipe_state;
 
        unsigned char sess_key[16];        /* Current session key. */
        DOM_CRED clnt_cred;                /* Client credential. */
index ebb09b6c6ceeb62a382976ecf655bdfeb8b37ee4..638648dc44d659cf1a5ec5f56283b9f131174b01 100644 (file)
@@ -1298,7 +1298,7 @@ krb5_const_principal get_principal_from_tkt(krb5_ticket *tkt);
 krb5_error_code krb5_locate_kdc(krb5_context ctx, const krb5_data *realm, struct sockaddr **addr_pp, int *naddrs, int get_masters);
 krb5_error_code get_kerberos_allowed_etypes(krb5_context context, krb5_enctype **enctypes);
 void free_kerberos_etypes(krb5_context context, krb5_enctype *enctypes);
-BOOL get_krb5_smb_session_key(krb5_context context, krb5_auth_context auth_context, uint8 session_key[16], BOOL remote);
+BOOL get_krb5_smb_session_key(krb5_context context, krb5_auth_context auth_context, DATA_BLOB *session_key, BOOL remote);
 #endif /* HAVE_KRB5 */
 
 /* TRUE and FALSE are part of the C99 standard and gcc, but
index 3fe8f41d8d4dcdde8f1d6e55ea8331073f46cad6..b1a4107980d55a2c7cb5067163c4f65523ef1999 100644 (file)
@@ -229,7 +229,7 @@ typedef struct pipes_struct
        fstring pipe_user_name;
        struct current_user pipe_user;
 
-       uint8 session_key[16];
+       DATA_BLOB session_key;
 
        /*
         * Set to true when an RPC bind has been done on this pipe.
index f1b1bc25e43ea6d7dfc5c6f19db23d29c44f7b46..681d4071dbb4ee3dc445213e1b20d8cf0b6c13cb 100644 (file)
@@ -30,6 +30,7 @@ enum NTLMSSP_ROLE
 /* NTLMSSP message types */
 enum NTLM_MESSAGE_TYPE
 {
+       NTLMSSP_INITIAL = 0 /* samba internal state */,
        NTLMSSP_NEGOTIATE = 1,
        NTLMSSP_CHALLENGE = 2,
        NTLMSSP_AUTH      = 3,
@@ -70,29 +71,10 @@ enum NTLM_MESSAGE_TYPE
 typedef struct ntlmssp_state 
 {
        TALLOC_CTX *mem_ctx;
+       unsigned int ref_count;
        enum NTLMSSP_ROLE role;
-       BOOL unicode;
-       char *user;
-       char *domain;
-       char *workstation;
-       DATA_BLOB lm_resp;
-       DATA_BLOB nt_resp;
-       DATA_BLOB chal;
-       void *auth_context;
-       const uint8 *(*get_challenge)(struct ntlmssp_state *ntlmssp_state);
-       NTSTATUS (*check_password)(struct ntlmssp_state *ntlmssp_state);
-
-       const char *(*get_global_myname)(void);
-       const char *(*get_domain)(void);
-
-       int server_role;
+       enum server_types server_role;
        uint32 expected_state;
-} NTLMSSP_STATE;
-
-typedef struct ntlmssp_client_state 
-{
-       TALLOC_CTX *mem_ctx;
-       unsigned int ref_count;
 
        BOOL unicode;
        BOOL use_ntlmv2;
@@ -102,30 +84,78 @@ typedef struct ntlmssp_client_state
        char *password;
        char *server_domain;
 
-       const char *(*get_global_myname)(void);
-       const char *(*get_domain)(void);
+       DATA_BLOB internal_chal; /* Random challenge as supplied to the client for NTLM authentication */
 
-       DATA_BLOB chal;
+       DATA_BLOB chal; /* Random challenge as input into the actual NTLM (or NTLM2) authentication */
        DATA_BLOB lm_resp;
        DATA_BLOB nt_resp;
        DATA_BLOB session_key;
        
-       uint32 neg_flags;
+       uint32 neg_flags; /* the current state of negotiation with the NTLMSSP partner */
        
+       void *auth_context;
+
+       /**
+        * Callback to get the 'challenge' used for NTLM authentication.  
+        *
+        * @param ntlmssp_state This structure
+        * @return 8 bytes of challnege data, determined by the server to be the challenge for NTLM authentication
+        *
+        */
+       const uint8 *(*get_challenge)(const struct ntlmssp_state *ntlmssp_state);
+
+       /**
+        * Callback to find if the challenge used by NTLM authentication may be modified 
+        *
+        * The NTLM2 authentication scheme modifies the effective challenge, but this is not compatiable with the
+        * current 'security=server' implementation..  
+        *
+        * @param ntlmssp_state This structure
+        * @return Can the challenge be set to arbitary values?
+        *
+        */
+       BOOL (*may_set_challenge)(const struct ntlmssp_state *ntlmssp_state);
+
+       /**
+        * Callback to set the 'challenge' used for NTLM authentication.  
+        *
+        * The callback may use the void *auth_context to store state information, but the same value is always available
+        * from the DATA_BLOB chal on this structure.
+        *
+        * @param ntlmssp_state This structure
+        * @param challange 8 bytes of data, agreed by the client and server to be the effective challenge for NTLM2 authentication
+        *
+        */
+       NTSTATUS (*set_challenge)(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *challenge);
+
+       /**
+        * Callback to check the user's password.  
+        *
+        * The callback must reads the feilds of this structure for the information it needs on the user 
+        * @param ntlmssp_state This structure
+        * @param nt_session_key If an NT session key is returned by the authentication process, return it here
+        * @param lm_session_key If an LM session key is returned by the authentication process, return it here
+        *
+        */
+       NTSTATUS (*check_password)(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *nt_session_key, DATA_BLOB *lm_session_key);
+
+       const char *(*get_global_myname)(void);
+       const char *(*get_domain)(void);
+
        /* SMB Signing */
        
        uint32 ntlmssp_seq_num;
 
        /* ntlmv2 */
-       char cli_sign_const[16];
-       char cli_seal_const[16];
-       char srv_sign_const[16];
-       char srv_seal_const[16];
+       char send_sign_const[16];
+       char send_seal_const[16];
+       char recv_sign_const[16];
+       char recv_seal_const[16];
 
-       unsigned char cli_sign_hash[258];
-       unsigned char cli_seal_hash[258];
-       unsigned char srv_sign_hash[258];
-       unsigned char srv_seal_hash[258];
+       unsigned char send_sign_hash[258];
+       unsigned char send_seal_hash[258];
+       unsigned char recv_sign_hash[258];
+       unsigned char recv_seal_hash[258];
 
        /* ntlmv1 */
        unsigned char ntlmssp_hash[258];
@@ -135,5 +165,5 @@ typedef struct ntlmssp_client_state
           Store it here, until we need it */
        DATA_BLOB stored_response; 
        
-} NTLMSSP_CLIENT_STATE;
+} NTLMSSP_STATE;
 
index e41b5834f70b6b1116137da70c13a451a4484d99..4bd40216d7b01765ccd2dcc944996d14e996dec5 100644 (file)
@@ -1546,7 +1546,7 @@ typedef struct user_struct
 
        NT_USER_TOKEN *nt_user_token;
 
-       uint8 session_key[16];
+       DATA_BLOB session_key;
 
        char *session_keystr; /* used by utmp and pam session code.  
                                 TDB key string */
index 4056212fc5637247cd40504bc9a8dd829f507de9..83afc591a1544f589a08bfc335d579990e94ed28 100644 (file)
@@ -61,14 +61,20 @@ DATA_BLOB data_blob_talloc(TALLOC_CTX *mem_ctx, const void *p, size_t length)
 {
        DATA_BLOB ret;
 
-       if (!p || !length) {
+       if (!length) {
                ZERO_STRUCT(ret);
                return ret;
        }
 
-       ret.data = talloc_memdup(mem_ctx, p, length);
-       if (ret.data == NULL)
-               smb_panic("data_blob_talloc: talloc_memdup failed.\n");
+       if (p) {
+               ret.data = talloc_memdup(mem_ctx, p, length);
+               if (ret.data == NULL)
+                       smb_panic("data_blob_talloc: talloc_memdup failed.\n");
+       } else {
+               ret.data = talloc(mem_ctx, length);
+               if (ret.data == NULL)
+                       smb_panic("data_blob_talloc: talloc failed.\n");
+       }
 
        ret.length = length;
        ret.free = NULL;
index cdea5a2fe420fe216bbdaceeba82337ae37db9a6..b0efb8f598f15dc6cb55bb473adb1ea8bef8f07c 100644 (file)
@@ -162,7 +162,7 @@ static BOOL setup_keytab(krb5_context context,
 NTSTATUS ads_verify_ticket(const char *realm, const DATA_BLOB *ticket, 
                           char **principal, DATA_BLOB *auth_data,
                           DATA_BLOB *ap_rep,
-                          uint8 session_key[16])
+                          DATA_BLOB *session_key)
 {
        NTSTATUS sret = NT_STATUS_LOGON_FAILURE;
        krb5_context context = NULL;
index b5f7b97ae83f9bca6553403d2c8c34c70b0508cc..a920a1b7ff24ef2666d4e5ed8e31762a4180d0c6 100644 (file)
@@ -241,9 +241,16 @@ static BOOL cli_session_setup_plaintext(struct cli_state *cli, const char *user,
        return True;
 }
 
-static void set_cli_session_key (struct cli_state *cli, DATA_BLOB session_key) 
+/**
+ * Set the user session key for a connection
+ * @param cli The cli structure to add it too
+ * @param session_key The session key used.  (A copy of this is taken for the cli struct)
+ *
+ */
+
+static void cli_set_session_key (struct cli_state *cli, const DATA_BLOB session_key) 
 {
-       memcpy(cli->user_session_key, session_key.data, MIN(session_key.length, sizeof(cli->user_session_key)));
+       cli->user_session_key = data_blob(session_key.data, session_key.length);
 }
 
 /****************************************************************************
@@ -311,7 +318,7 @@ static BOOL cli_session_setup_nt1(struct cli_state *cli, const char *user,
                        session_key = data_blob(NULL, 16);
                        SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data);
                }
-               cli_simple_set_signing(cli, session_key.data, nt_response); 
+               cli_simple_set_signing(cli, session_key, nt_response); 
        } else {
                /* pre-encrypted password supplied.  Only used for 
                   security=server, can't do
@@ -373,14 +380,16 @@ static BOOL cli_session_setup_nt1(struct cli_state *cli, const char *user,
 
        if (session_key.data) {
                /* Have plaintext orginal */
-               set_cli_session_key(cli, session_key);
+               cli_set_session_key(cli, session_key);
        }
 
        ret = True;
 end:   
        data_blob_free(&lm_response);
        data_blob_free(&nt_response);
-       data_blob_free(&session_key);
+
+       if (!ret)
+               data_blob_free(&session_key);
        return ret;
 }
 
@@ -484,19 +493,19 @@ static void use_in_memory_ccache(void) {
  Do a spnego/kerberos encrypted session setup.
 ****************************************************************************/
 
-static BOOL cli_session_setup_kerberos(struct cli_state *cli, const char *principal, const char *workgroup)
+static NTSTATUS cli_session_setup_kerberos(struct cli_state *cli, const char *principal, const char *workgroup)
 {
        DATA_BLOB blob2, negTokenTarg;
-       unsigned char session_key_krb5[16];
+       DATA_BLOB session_key_krb5;
        DATA_BLOB null_blob = data_blob(NULL, 0);
        
        DEBUG(2,("Doing kerberos session setup\n"));
 
        /* generate the encapsulated kerberos5 ticket */
-       negTokenTarg = spnego_gen_negTokenTarg(principal, 0, session_key_krb5);
+       negTokenTarg = spnego_gen_negTokenTarg(principal, 0, &session_key_krb5);
 
        if (!negTokenTarg.data)
-               return False;
+               return NT_STATUS_UNSUCCESSFUL;
 
 #if 0
        file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length);
@@ -509,9 +518,16 @@ static BOOL cli_session_setup_kerberos(struct cli_state *cli, const char *princi
        /* we don't need this blob for kerberos */
        data_blob_free(&blob2);
 
+       cli_set_session_key(cli, session_key_krb5);
+
        data_blob_free(&negTokenTarg);
 
-       return !cli_is_error(cli);
+       if (cli_is_error(cli)) {
+               if (NT_STATUS_IS_OK(cli_nt_error(cli))) {
+                       return NT_STATUS_UNSUCCESSFUL;
+               }
+       } 
+       return NT_STATUS_OK;
 }
 #endif /* HAVE_KRB5 */
 
@@ -520,10 +536,10 @@ static BOOL cli_session_setup_kerberos(struct cli_state *cli, const char *princi
  Do a spnego/NTLMSSP encrypted session setup.
 ****************************************************************************/
 
-static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, const char *user, 
+static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *user, 
                                      const char *pass, const char *workgroup)
 {
-       struct ntlmssp_client_state *ntlmssp_state;
+       struct ntlmssp_state *ntlmssp_state;
        NTSTATUS nt_status;
        int turn = 1;
        DATA_BLOB msg1;
@@ -534,21 +550,21 @@ static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, const char *user,
        cli_temp_set_signing(cli);
 
        if (!NT_STATUS_IS_OK(nt_status = ntlmssp_client_start(&ntlmssp_state))) {
-               return False;
+               return nt_status;
        }
 
        if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, user))) {
-               return False;
+               return nt_status;
        }
        if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, workgroup))) {
-               return False;
+               return nt_status;
        }
        if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, pass))) {
-               return False;
+               return nt_status;
        }
 
        do {
-               nt_status = ntlmssp_client_update(ntlmssp_state, 
+               nt_status = ntlmssp_update(ntlmssp_state, 
                                                  blob_in, &blob_out);
                data_blob_free(&blob_in);
                if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
@@ -562,18 +578,27 @@ static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, const char *user,
                        }
                
                        cli_simple_set_signing(cli, 
-                                              ntlmssp_state->session_key.data
+                                              data_blob(ntlmssp_state->session_key.data, ntlmssp_state->session_key.length)
                                               null_blob); 
                        
                        /* now send that blob on its way */
                        if (!cli_session_setup_blob_send(cli, msg1)) {
-                               return False;
+                               DEBUG(3, ("Failed to send NTLMSSP/SPENGO blob to server!\n"));
+                               nt_status = NT_STATUS_UNSUCCESSFUL;
+                       } else {
+                               data_blob_free(&msg1);
+                               
+                               blob = cli_session_setup_blob_receive(cli);
+                               
+                               nt_status = cli_nt_error(cli);
+                               if (cli_is_error(cli) && NT_STATUS_IS_OK(nt_status)) {
+                                       if (cli->smb_rw_error == READ_BAD_SIG) {
+                                               nt_status = NT_STATUS_ACCESS_DENIED;
+                                       } else {
+                                               nt_status = NT_STATUS_UNSUCCESSFUL;
+                                       }
+                               }
                        }
-                       data_blob_free(&msg1);
-                       
-                       blob = cli_session_setup_blob_receive(cli);
-
-                       nt_status = cli_nt_error(cli);
                }
                
                if (!blob.length) {
@@ -606,24 +631,22 @@ static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, const char *user,
 
        if (NT_STATUS_IS_OK(nt_status)) {
                fstrcpy(cli->server_domain, ntlmssp_state->server_domain);
-               set_cli_session_key(cli, ntlmssp_state->session_key);
+               cli_set_session_key(cli, ntlmssp_state->session_key);
        }
 
        /* we have a reference conter on ntlmssp_state, if we are signing
           then the state will be kept by the signing engine */
 
-       if (!NT_STATUS_IS_OK(ntlmssp_client_end(&ntlmssp_state))) {
-               return False;
-       }
-       
-       return (NT_STATUS_IS_OK(nt_status));
+       ntlmssp_end(&ntlmssp_state);
+
+       return nt_status;
 }
 
 /****************************************************************************
  Do a spnego encrypted session setup.
 ****************************************************************************/
 
-BOOL cli_session_setup_spnego(struct cli_state *cli, const char *user, 
+NTSTATUS cli_session_setup_spnego(struct cli_state *cli, const char *user, 
                              const char *pass, const char *workgroup)
 {
        char *principal;
@@ -651,7 +674,7 @@ BOOL cli_session_setup_spnego(struct cli_state *cli, const char *user,
           reply */
        if (!spnego_parse_negTokenInit(blob, OIDs, &principal)) {
                data_blob_free(&blob);
-               return False;
+               return NT_STATUS_INVALID_PARAMETER;
        }
        data_blob_free(&blob);
 
@@ -681,7 +704,7 @@ BOOL cli_session_setup_spnego(struct cli_state *cli, const char *user,
                        
                        if (ret){
                                DEBUG(0, ("Kinit failed: %s\n", error_message(ret)));
-                               return False;
+                               return NT_STATUS_LOGON_FAILURE;
                        }
                }
                
@@ -773,8 +796,14 @@ BOOL cli_session_setup(struct cli_state *cli,
 
        /* if the server supports extended security then use SPNEGO */
 
-       if (cli->capabilities & CAP_EXTENDED_SECURITY)
-               return cli_session_setup_spnego(cli, user, pass, workgroup);
+       if (cli->capabilities & CAP_EXTENDED_SECURITY) {
+               NTSTATUS nt_status;
+               if (!NT_STATUS_IS_OK(nt_status = cli_session_setup_spnego(cli, user, pass, workgroup))) {
+                       DEBUG(3, ("SPENGO login failed: %s\n", get_friendly_nt_error_msg(nt_status)));
+                       return False;
+               }
+               return True;
+       }
 
        /* otherwise do a NT1 style session setup */
 
index 9b54acf77561f807d3e0f6208e0f6b30f28ab691..0873700fc0ad35e3803c8075d489ee56cffb6b13 100644 (file)
@@ -339,7 +339,7 @@ close the session
 void cli_nt_session_close(struct cli_state *cli)
 {
        if (cli->ntlmssp_pipe_state) {
-               ntlmssp_client_end(&cli->ntlmssp_pipe_state);
+               ntlmssp_end(&cli->ntlmssp_pipe_state);
        }
 
        if (cli->nt_pipe_fnum != 0)
@@ -375,9 +375,10 @@ void cli_close_connection(struct cli_state *cli)
 
        cli_free_signing_context(cli);
        data_blob_free(&cli->secblob);
+       data_blob_free(&cli->user_session_key);
 
        if (cli->ntlmssp_pipe_state) 
-               ntlmssp_client_end(&cli->ntlmssp_pipe_state);
+               ntlmssp_end(&cli->ntlmssp_pipe_state);
 
        if (cli->mem_ctx) {
                talloc_destroy(cli->mem_ctx);
index 1fccc04a013b34107af999280bd0d6536a574afe..5568b5e033253ec82aedce4ad353dd89f05cc5c9 100644 (file)
@@ -307,7 +307,7 @@ cleanup_princ:
 /*
   get a kerberos5 ticket for the given service 
 */
-DATA_BLOB cli_krb5_get_ticket(const char *principal, time_t time_offset, unsigned char session_key_krb5[16])
+DATA_BLOB cli_krb5_get_ticket(const char *principal, time_t time_offset, DATA_BLOB *session_key_krb5)
 {
        krb5_error_code retval;
        krb5_data packet;
@@ -369,7 +369,7 @@ failed:
        return data_blob(NULL, 0);
 }
 
- BOOL get_krb5_smb_session_key(krb5_context context, krb5_auth_context auth_context, uint8 session_key[16], BOOL remote)
+ BOOL get_krb5_smb_session_key(krb5_context context, krb5_auth_context auth_context, DATA_BLOB *session_key, BOOL remote)
  {
        krb5_keyblock *skey;
        krb5_error_code err;
@@ -383,11 +383,11 @@ failed:
                err = krb5_auth_con_getlocalsubkey(context, auth_context, &skey);
        if (err == 0 && skey != NULL) {
                DEBUG(10, ("Got KRB5 session key of length %d\n",  KRB5_KEY_LENGTH(skey)));
-               if (KRB5_KEY_LENGTH(skey) == 16) {
-                       memcpy(session_key, KRB5_KEY_DATA(skey), KRB5_KEY_LENGTH(skey));
-                       dump_data_pw("KRB5 Session Key:\n", session_key, 16);
-                       ret = True;
-               }
+               *session_key = data_blob(KRB5_KEY_DATA(skey), KRB5_KEY_LENGTH(skey));
+               dump_data_pw("KRB5 Session Key:\n", session_key->data, session_key->length);
+
+               ret = True;
+
                krb5_free_keyblock(context, skey);
        } else {
                DEBUG(10, ("KRB5 error getting session key %d\n", err));
@@ -410,7 +410,7 @@ failed:
 
 #else /* HAVE_KRB5 */
  /* this saves a few linking headaches */
-DATA_BLOB cli_krb5_get_ticket(const char *principal, time_t time_offset, unsigned char session_key_krb5[16])
+DATA_BLOB cli_krb5_get_ticket(const char *principal, time_t time_offset, DATA_BLOB *session_key_krb5)
  {
         DEBUG(0,("NO KERBEROS SUPPORT\n"));
         return data_blob(NULL, 0);
index 63076a1a1ce661d9327a61e2da9406cbc27fd447..92543736ff258b767ee766c6a258965c055d8426 100644 (file)
@@ -323,7 +323,7 @@ BOOL spnego_parse_krb5_wrap(DATA_BLOB blob, DATA_BLOB *ticket, uint8 tok_id[2])
    generate a SPNEGO negTokenTarg packet, ready for a EXTENDED_SECURITY
    kerberos session setup 
 */
-DATA_BLOB spnego_gen_negTokenTarg(const char *principal, int time_offset, unsigned char session_key_krb5[16])
+DATA_BLOB spnego_gen_negTokenTarg(const char *principal, int time_offset, DATA_BLOB *session_key_krb5)
 {
        DATA_BLOB tkt, tkt_wrapped, targ;
        const char *krb_mechs[] = {OID_KERBEROS5_OLD, OID_NTLMSSP, NULL};
index c51b599b0411c40c1abc43665bf064d66d919fa6..a0da1efcc10965323d66cd4c094b180884af8117 100644 (file)
 
 #include "includes.h"
 
+static NTSTATUS ntlmssp_client_initial(struct ntlmssp_state *ntlmssp_state, 
+                                      DATA_BLOB reply, DATA_BLOB *next_request);
+static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state,
+                                        const DATA_BLOB in, DATA_BLOB *out);
+static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state, 
+                                        const DATA_BLOB reply, DATA_BLOB *next_request);
+static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state,
+                                   const DATA_BLOB request, DATA_BLOB *reply);
+
+/**
+ * Callbacks for NTLMSSP - for both client and server operating modes
+ * 
+ */
+
+static const struct ntlmssp_callbacks {
+       enum NTLMSSP_ROLE role;
+       enum NTLM_MESSAGE_TYPE ntlmssp_command;
+       NTSTATUS (*fn)(struct ntlmssp_state *ntlmssp_state, 
+                      DATA_BLOB in, DATA_BLOB *out);
+} ntlmssp_callbacks[] = {
+       {NTLMSSP_CLIENT, NTLMSSP_INITIAL, ntlmssp_client_initial},
+       {NTLMSSP_SERVER, NTLMSSP_NEGOTIATE, ntlmssp_server_negotiate},
+       {NTLMSSP_CLIENT, NTLMSSP_CHALLENGE, ntlmssp_client_challenge},
+       {NTLMSSP_SERVER, NTLMSSP_AUTH, ntlmssp_server_auth},
+       {NTLMSSP_CLIENT, NTLMSSP_UNKNOWN, NULL},
+       {NTLMSSP_SERVER, NTLMSSP_UNKNOWN, NULL}
+};
+
+
 /**
  * Print out the NTLMSSP flags for debugging 
  * @param neg_flags The flags from the packet
@@ -71,7 +100,7 @@ void debug_ntlmssp_flags(uint32 neg_flags)
  *
  */
    
-static const uint8 *get_challenge(struct ntlmssp_state *ntlmssp_state)
+static const uint8 *get_challenge(const struct ntlmssp_state *ntlmssp_state)
 {
        static uchar chal[8];
        generate_random_buffer(chal, sizeof(chal), False);
@@ -79,6 +108,188 @@ static const uint8 *get_challenge(struct ntlmssp_state *ntlmssp_state)
        return chal;
 }
 
+/**
+ * Default 'we can set the challenge to anything we like' implementation
+ *
+ */
+   
+static BOOL may_set_challenge(const struct ntlmssp_state *ntlmssp_state)
+{
+       return True;
+}
+
+/**
+ * Default 'we can set the challenge to anything we like' implementation
+ *
+ * Does not actually do anything, as the value is always in the structure anyway.
+ *
+ */
+   
+static NTSTATUS set_challenge(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *challenge)
+{
+       SMB_ASSERT(challenge->length == 8);
+       return NT_STATUS_OK;
+}
+
+/** 
+ * Set a username on an NTLMSSP context - ensures it is talloc()ed 
+ *
+ */
+
+NTSTATUS ntlmssp_set_username(NTLMSSP_STATE *ntlmssp_state, const char *user) 
+{
+       ntlmssp_state->user = talloc_strdup(ntlmssp_state->mem_ctx, user);
+       if (!ntlmssp_state->user) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       return NT_STATUS_OK;
+}
+
+/** 
+ * Set a password on an NTLMSSP context - ensures it is talloc()ed 
+ *
+ */
+NTSTATUS ntlmssp_set_password(NTLMSSP_STATE *ntlmssp_state, const char *password) 
+{
+       if (!password) {
+               ntlmssp_state->password = NULL;
+       } else {
+               ntlmssp_state->password = talloc_strdup(ntlmssp_state->mem_ctx, password);
+               if (!ntlmssp_state->password) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+       }
+       return NT_STATUS_OK;
+}
+
+/** 
+ * Set a domain on an NTLMSSP context - ensures it is talloc()ed 
+ *
+ */
+NTSTATUS ntlmssp_set_domain(NTLMSSP_STATE *ntlmssp_state, const char *domain) 
+{
+       ntlmssp_state->domain = talloc_strdup(ntlmssp_state->mem_ctx, domain);
+       if (!ntlmssp_state->domain) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       return NT_STATUS_OK;
+}
+
+/** 
+ * Set a workstation on an NTLMSSP context - ensures it is talloc()ed 
+ *
+ */
+NTSTATUS ntlmssp_set_workstation(NTLMSSP_STATE *ntlmssp_state, const char *workstation) 
+{
+       ntlmssp_state->workstation = talloc_strdup(ntlmssp_state->mem_ctx, workstation);
+       if (!ntlmssp_state->domain) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       return NT_STATUS_OK;
+}
+
+/**
+ *  Store a DATA_BLOB containing an NTLMSSP response, for use later.
+ *  This copies the data blob
+ */
+
+NTSTATUS ntlmssp_store_response(NTLMSSP_STATE *ntlmssp_state,
+                               DATA_BLOB response) 
+{
+       ntlmssp_state->stored_response = data_blob_talloc(ntlmssp_state->mem_ctx, 
+                                                         response.data, response.length);
+       return NT_STATUS_OK;
+}
+
+/**
+ * Next state function for the NTLMSSP state machine
+ * 
+ * @param ntlmssp_state NTLMSSP State
+ * @param in The packet in from the NTLMSSP partner, as a DATA_BLOB
+ * @param out The reply, as an allocated DATA_BLOB, caller to free.
+ * @return Errors, NT_STATUS_MORE_PROCESSING_REQUIRED or NT_STATUS_OK. 
+ */
+
+NTSTATUS ntlmssp_update(NTLMSSP_STATE *ntlmssp_state, 
+                       const DATA_BLOB in, DATA_BLOB *out) 
+{
+       DATA_BLOB input;
+       uint32 ntlmssp_command;
+       int i;
+
+       *out = data_blob(NULL, 0);
+
+       if (!in.length && ntlmssp_state->stored_response.length) {
+               input = ntlmssp_state->stored_response;
+               
+               /* we only want to read the stored response once - overwrite it */
+               ntlmssp_state->stored_response = data_blob(NULL, 0);
+       } else {
+               input = in;
+       }
+
+       if (!input.length) {
+               switch (ntlmssp_state->role) {
+               case NTLMSSP_CLIENT:
+                       ntlmssp_command = NTLMSSP_INITIAL;
+                       break;
+               case NTLMSSP_SERVER:
+                       /* 'datagram' mode - no neg packet */
+                       ntlmssp_command = NTLMSSP_NEGOTIATE;
+                       break;
+               }
+       } else {
+               if (!msrpc_parse(&input, "Cd",
+                                "NTLMSSP",
+                                &ntlmssp_command)) {
+                       DEBUG(1, ("Failed to parse NTLMSSP packet, could not extract NTLMSSP command\n"));
+                       dump_data(2, (const char *)input.data, input.length);
+                       return NT_STATUS_INVALID_PARAMETER;
+               }
+       }
+
+       if (ntlmssp_command != ntlmssp_state->expected_state) {
+               DEBUG(1, ("got NTLMSSP command %u, expected %u\n", ntlmssp_command, ntlmssp_state->expected_state));
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       for (i=0; ntlmssp_callbacks[i].fn; i++) {
+               if (ntlmssp_callbacks[i].role == ntlmssp_state->role 
+                   && ntlmssp_callbacks[i].ntlmssp_command == ntlmssp_command) {
+                       return ntlmssp_callbacks[i].fn(ntlmssp_state, input, out);
+               }
+       }
+
+       DEBUG(1, ("failed to find NTLMSSP callback for NTLMSSP mode %u, command %u\n", 
+                 ntlmssp_state->role, ntlmssp_command)); 
+
+       return NT_STATUS_INVALID_PARAMETER;
+}
+
+/**
+ * End an NTLMSSP state machine
+ * 
+ * @param ntlmssp_state NTLMSSP State, free()ed by this function
+ */
+
+void ntlmssp_end(NTLMSSP_STATE **ntlmssp_state)
+{
+       TALLOC_CTX *mem_ctx = (*ntlmssp_state)->mem_ctx;
+
+       (*ntlmssp_state)->ref_count--;
+
+       if ((*ntlmssp_state)->ref_count == 0) {
+               data_blob_free(&(*ntlmssp_state)->chal);
+               data_blob_free(&(*ntlmssp_state)->lm_resp);
+               data_blob_free(&(*ntlmssp_state)->nt_resp);
+
+               talloc_destroy(mem_ctx);
+       }
+
+       *ntlmssp_state = NULL;
+       return;
+}
+
 /**
  * Determine correct target name flags for reply, given server role 
  * and negotiated flags
@@ -107,6 +318,46 @@ static const char *ntlmssp_target_name(struct ntlmssp_state *ntlmssp_state,
        }
 }
 
+static void ntlmssp_handle_neg_flags(struct ntlmssp_state *ntlmssp_state,
+                                     uint32 neg_flags, BOOL allow_lm) {
+       if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE) {
+               ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
+               ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_OEM;
+               ntlmssp_state->unicode = True;
+       } else {
+               ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_UNICODE;
+               ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_OEM;
+               ntlmssp_state->unicode = False;
+       }
+
+       if (neg_flags & NTLMSSP_NEGOTIATE_LM_KEY && allow_lm) {
+               /* other end forcing us to use LM */
+               ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_LM_KEY;
+               ntlmssp_state->use_ntlmv2 = False;
+       } else {
+               ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
+       }
+
+       if (!(neg_flags & NTLMSSP_NEGOTIATE_NTLM2)) {
+               ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
+               ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
+       }
+
+       if (!(neg_flags & NTLMSSP_NEGOTIATE_128)) {
+               ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_128;
+       }
+
+       if (!(neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH)) {
+               ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_KEY_EXCH;
+       }
+
+       if ((neg_flags & NTLMSSP_REQUEST_TARGET)) {
+               ntlmssp_state->neg_flags |= NTLMSSP_REQUEST_TARGET;
+       }
+       
+}
+
+
 /**
  * Next state function for the Negotiate packet
  * 
@@ -150,31 +401,27 @@ static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state,
                debug_ntlmssp_flags(neg_flags);
        }
        
-       cryptkey = ntlmssp_state->get_challenge(ntlmssp_state);
+       ntlmssp_handle_neg_flags(ntlmssp_state, neg_flags, lp_lanman_auth());
 
-       data_blob_free(&ntlmssp_state->chal);
-       ntlmssp_state->chal = data_blob(cryptkey, 8);
-
-       /* Give them the challenge. For now, ignore neg_flags and just
-          return the flags we want. Obviously this is not correct */
-       
-       chal_flags = 
-               NTLMSSP_NEGOTIATE_128 | 
-               NTLMSSP_NEGOTIATE_NTLM;
-       
-       if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE) {
-               chal_flags |= NTLMSSP_NEGOTIATE_UNICODE;
-               ntlmssp_state->unicode = True;
-       } else {
-               chal_flags |= NTLMSSP_NEGOTIATE_OEM;
-       }
+       chal_flags = ntlmssp_state->neg_flags;
 
        target_name = ntlmssp_target_name(ntlmssp_state, 
                                          neg_flags, &chal_flags); 
-
-       if (target_name == NULL)
+       if (target_name == NULL) 
                return NT_STATUS_INVALID_PARAMETER;
 
+       /* Ask our caller what challenge they would like in the packet */
+       cryptkey = ntlmssp_state->get_challenge(ntlmssp_state);
+
+       /* Check if we may set the challenge */
+       if (!ntlmssp_state->may_set_challenge(ntlmssp_state)) {
+               ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
+       }
+
+       ntlmssp_state->chal = data_blob_talloc(ntlmssp_state->mem_ctx, cryptkey, 8);
+       ntlmssp_state->internal_chal = data_blob_talloc(ntlmssp_state->mem_ctx, cryptkey, 8);
+       
+
        /* This should be a 'netbios domain -> DNS domain' mapping */
        dnsdomname[0] = '\0';
        get_mydomname(dnsdomname);
@@ -184,6 +431,7 @@ static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state,
        get_myfullname(dnsname);
        strlower_m(dnsname);
        
+       /* This creates the 'blob' of names that appears at the end of the packet */
        if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) 
        {
                const char *target_name_dns = "";
@@ -194,16 +442,17 @@ static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state,
                }
 
                msrpc_gen(&struct_blob, "aaaaa",
-                         ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_DOMAIN, target_name,
-                         ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_SERVER, ntlmssp_state->get_global_myname(),
-                         ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_DOMAIN_DNS, target_name_dns,
-                         ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_SERVER_DNS, dnsdomname,
-                         ntlmssp_state->unicode, 0, "");
+                         NTLMSSP_NAME_TYPE_DOMAIN, target_name,
+                         NTLMSSP_NAME_TYPE_SERVER, ntlmssp_state->get_global_myname(),
+                         NTLMSSP_NAME_TYPE_DOMAIN_DNS, dnsdomname,
+                         NTLMSSP_NAME_TYPE_SERVER_DNS, dnsname,
+                         0, "");
        } else {
                struct_blob = data_blob(NULL, 0);
        }
 
        {
+               /* Marshel the packet in the right format, be it unicode or ASCII */
                const char *gen_string;
                if (ntlmssp_state->unicode) {
                        gen_string = "CdUdbddB";
@@ -240,13 +489,27 @@ static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state,
 static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state,
                                    const DATA_BLOB request, DATA_BLOB *reply) 
 {
-       DATA_BLOB sess_key;
-       uint32 ntlmssp_command, neg_flags;
+       DATA_BLOB encrypted_session_key = data_blob(NULL, 0);
+       DATA_BLOB nt_session_key = data_blob(NULL, 0);
+       DATA_BLOB lm_session_key = data_blob(NULL, 0);
+       DATA_BLOB session_key = data_blob(NULL, 0);
+       uint32 ntlmssp_command, auth_flags;
        NTSTATUS nt_status;
 
+       /* used by NTLM2 */
+       BOOL doing_ntlm2 = False;
+
+       uchar session_nonce[16];
+       uchar session_nonce_hash[16];
+
        const char *parse_string;
+       char *domain = NULL;
+       char *user = NULL;
+       char *workstation = NULL;
 
        /* parse the NTLMSSP packet */
+       *reply = data_blob(NULL, 0);
+
 #if 0
        file_save("ntlmssp_auth.dat", request.data, request.length);
 #endif
@@ -260,9 +523,9 @@ static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state,
        data_blob_free(&ntlmssp_state->lm_resp);
        data_blob_free(&ntlmssp_state->nt_resp);
 
-       SAFE_FREE(ntlmssp_state->user);
-       SAFE_FREE(ntlmssp_state->domain);
-       SAFE_FREE(ntlmssp_state->workstation);
+       ntlmssp_state->user = NULL;
+       ntlmssp_state->domain = NULL;
+       ntlmssp_state->workstation = NULL;
 
        /* now the NTLMSSP encoded auth hashes */
        if (!msrpc_parse(&request, parse_string,
@@ -270,18 +533,73 @@ static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state,
                         &ntlmssp_command, 
                         &ntlmssp_state->lm_resp,
                         &ntlmssp_state->nt_resp,
-                        &ntlmssp_state->domain, 
-                        &ntlmssp_state->user, 
-                        &ntlmssp_state->workstation,
-                        &sess_key,
-                        &neg_flags)) {
+                        &domain, 
+                        &user, 
+                        &workstation,
+                        &encrypted_session_key,
+                        &auth_flags)) {
                DEBUG(1, ("ntlmssp_server_auth: failed to parse NTLMSSP:\n"));
                dump_data(2, (const char *)request.data, request.length);
-               return NT_STATUS_INVALID_PARAMETER;
+               SAFE_FREE(domain);
+               SAFE_FREE(user);
+               SAFE_FREE(workstation);
+               data_blob_free(&encrypted_session_key);
+               auth_flags = 0;
+               
+               /* Try again with a shorter string (Win9X truncates this packet) */
+               if (ntlmssp_state->unicode) {
+                       parse_string = "CdBBUUU";
+               } else {
+                       parse_string = "CdBBAAA";
+               }
+
+               /* now the NTLMSSP encoded auth hashes */
+               if (!msrpc_parse(&request, parse_string,
+                                "NTLMSSP", 
+                                &ntlmssp_command, 
+                                &ntlmssp_state->lm_resp,
+                                &ntlmssp_state->nt_resp,
+                                &domain, 
+                                &user, 
+                                &workstation)) {
+                       DEBUG(1, ("ntlmssp_server_auth: failed to parse NTLMSSP:\n"));
+                       dump_data(2, (const char *)request.data, request.length);
+                       SAFE_FREE(domain);
+                       SAFE_FREE(user);
+                       SAFE_FREE(workstation);
+
+                       return NT_STATUS_INVALID_PARAMETER;
+               }
        }
 
-       data_blob_free(&sess_key);
-       
+       if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, domain))) {
+               SAFE_FREE(domain);
+               SAFE_FREE(user);
+               SAFE_FREE(workstation);
+               data_blob_free(&encrypted_session_key);
+               return nt_status;
+       }
+
+       if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, user))) {
+               SAFE_FREE(domain);
+               SAFE_FREE(user);
+               SAFE_FREE(workstation);
+               data_blob_free(&encrypted_session_key);
+               return nt_status;
+       }
+
+       if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_workstation(ntlmssp_state, workstation))) {
+               SAFE_FREE(domain);
+               SAFE_FREE(user);
+               SAFE_FREE(workstation);
+               data_blob_free(&encrypted_session_key);
+               return nt_status;
+       }
+
+       SAFE_FREE(domain);
+       SAFE_FREE(user);
+       SAFE_FREE(workstation);
+
        DEBUG(3,("Got user=[%s] domain=[%s] workstation=[%s] len1=%lu len2=%lu\n",
                 ntlmssp_state->user, ntlmssp_state->domain, ntlmssp_state->workstation, (unsigned long)ntlmssp_state->lm_resp.length, (unsigned long)ntlmssp_state->nt_resp.length));
 
@@ -290,9 +608,98 @@ static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state,
        file_save("lmhash1.dat",  &ntlmssp_state->lm_resp.data,  &ntlmssp_state->lm_resp.length);
 #endif
 
-       nt_status = ntlmssp_state->check_password(ntlmssp_state);
+       /* NTLM2 uses a 'challenge' that is made of up both the server challenge, and a 
+          client challenge 
        
-       *reply = data_blob(NULL, 0);
+          However, the NTLM2 flag may still be set for the real NTLMv2 logins, be careful.
+       */
+       if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+               if (ntlmssp_state->nt_resp.length == 24 && ntlmssp_state->lm_resp.length == 24) {
+                       struct MD5Context md5_session_nonce_ctx;
+                       SMB_ASSERT(ntlmssp_state->internal_chal.data && ntlmssp_state->internal_chal.length == 8);
+                       
+                       doing_ntlm2 = True;
+
+                       memcpy(session_nonce, ntlmssp_state->internal_chal.data, 8);
+                       memcpy(&session_nonce[8], ntlmssp_state->lm_resp.data, 8);
+                       
+                       MD5Init(&md5_session_nonce_ctx);
+                       MD5Update(&md5_session_nonce_ctx, session_nonce, 16);
+                       MD5Final(session_nonce_hash, &md5_session_nonce_ctx);
+                       
+                       ntlmssp_state->chal = data_blob_talloc(ntlmssp_state->mem_ctx, session_nonce_hash, 8);
+
+                       /* LM response is no longer useful */
+                       data_blob_free(&ntlmssp_state->lm_resp);
+
+                       /* We changed the effective challenge - set it */
+                       if (!NT_STATUS_IS_OK(nt_status = ntlmssp_state->set_challenge(ntlmssp_state, &ntlmssp_state->chal))) {
+                               data_blob_free(&encrypted_session_key);
+                               return nt_status;
+                       }
+               }
+       }
+
+       /* Finally, actually ask if the password is OK */
+       if (!NT_STATUS_IS_OK(nt_status = ntlmssp_state->check_password(ntlmssp_state, &nt_session_key, &lm_session_key))) {
+               data_blob_free(&encrypted_session_key);
+               return nt_status;
+       }
+
+       dump_data_pw("NT session key:\n", nt_session_key.data, nt_session_key.length);
+       dump_data_pw("LM first-8:\n", lm_session_key.data, lm_session_key.length);
+
+       /* Handle the different session key derivation for NTLM2 */
+       if (doing_ntlm2) {
+               if (nt_session_key.data && nt_session_key.length == 16) {
+                       session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16);
+                       hmac_md5(nt_session_key.data, session_nonce, 
+                                sizeof(session_nonce), session_key.data);
+                       dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);
+
+               }
+       } else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) {
+               if (lm_session_key.data && lm_session_key.length >= 8 && 
+                   ntlmssp_state->lm_resp.data && ntlmssp_state->lm_resp.length == 24) {
+                       session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16);
+                       SMBsesskeygen_lmv1(lm_session_key.data, ntlmssp_state->lm_resp.data, 
+                                          session_key.data);
+                       dump_data_pw("LM session key:\n", session_key.data, session_key.length);
+               }
+       } else if (nt_session_key.data) {
+               session_key = nt_session_key;
+               dump_data_pw("unmodified session key:\n", session_key.data, session_key.length);
+       }
+
+       /* With KEY_EXCH, the client supplies the proposed session key, 
+          but encrypts it with the long-term key */
+       if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
+               if (!encrypted_session_key.data || encrypted_session_key.length != 16) {
+                       data_blob_free(&encrypted_session_key);
+                       DEBUG(1, ("Client-supplied KEY_EXCH session key was of invalid length (%u)!\n", 
+                                 encrypted_session_key.length));
+                       return NT_STATUS_INVALID_PARAMETER;
+               } else if (!session_key.data || session_key.length != 16) {
+                       DEBUG(5, ("server session key is invalid (len == %u), cannot do KEY_EXCH!\n", 
+                                 session_key.length));
+               } else {
+                       dump_data_pw("KEY_EXCH session key (enc):\n", encrypted_session_key.data, encrypted_session_key.length);
+                       SamOEMhash(encrypted_session_key.data, 
+                                  session_key.data, 
+                                  encrypted_session_key.length);
+                       ntlmssp_state->session_key = data_blob_talloc(ntlmssp_state->mem_ctx, 
+                                                                     encrypted_session_key.data, 
+                                                                     encrypted_session_key.length);
+                       dump_data_pw("KEY_EXCH session key:\n", session_key.data, session_key.length);
+               }
+       } else {
+               ntlmssp_state->session_key = session_key;
+       }
+
+       data_blob_free(&encrypted_session_key);
+       
+       /* allow arbitarily many authentications */
+       ntlmssp_state->expected_state = NTLMSSP_AUTH;
 
        return nt_status;
 }
@@ -316,8 +723,12 @@ NTSTATUS ntlmssp_server_start(NTLMSSP_STATE **ntlmssp_state)
                return NT_STATUS_NO_MEMORY;
        }
 
+       (*ntlmssp_state)->role = NTLMSSP_SERVER;
+
        (*ntlmssp_state)->mem_ctx = mem_ctx;
        (*ntlmssp_state)->get_challenge = get_challenge;
+       (*ntlmssp_state)->set_challenge = set_challenge;
+       (*ntlmssp_state)->may_set_challenge = may_set_challenge;
 
        (*ntlmssp_state)->get_global_myname = global_myname;
        (*ntlmssp_state)->get_domain = lp_workgroup;
@@ -325,73 +736,18 @@ NTSTATUS ntlmssp_server_start(NTLMSSP_STATE **ntlmssp_state)
 
        (*ntlmssp_state)->expected_state = NTLMSSP_NEGOTIATE;
 
-       return NT_STATUS_OK;
-}
-
-/**
- * End an NTLMSSP state machine
- * 
- * @param ntlmssp_state NTLMSSP State, free()ed by this function
- */
-
-NTSTATUS ntlmssp_server_end(NTLMSSP_STATE **ntlmssp_state)
-{
-       TALLOC_CTX *mem_ctx = (*ntlmssp_state)->mem_ctx;
-
-       data_blob_free(&(*ntlmssp_state)->chal);
-       data_blob_free(&(*ntlmssp_state)->lm_resp);
-       data_blob_free(&(*ntlmssp_state)->nt_resp);
+       (*ntlmssp_state)->ref_count = 1;
 
-       SAFE_FREE((*ntlmssp_state)->user);
-       SAFE_FREE((*ntlmssp_state)->domain);
-       SAFE_FREE((*ntlmssp_state)->workstation);
+       (*ntlmssp_state)->neg_flags = 
+               NTLMSSP_NEGOTIATE_128 |
+               NTLMSSP_NEGOTIATE_NTLM |
+               NTLMSSP_NEGOTIATE_NTLM2 |
+               NTLMSSP_NEGOTIATE_KEY_EXCH |
+               NTLMSSP_NEGOTIATE_SIGN;
 
-       talloc_destroy(mem_ctx);
-       *ntlmssp_state = NULL;
        return NT_STATUS_OK;
 }
 
-/**
- * Next state function for the NTLMSSP state machine
- * 
- * @param ntlmssp_state NTLMSSP State
- * @param request The request, as a DATA_BLOB
- * @param request The reply, as an allocated DATA_BLOB, caller to free.
- * @return Errors, NT_STATUS_MORE_PROCESSING_REQUIRED or NT_STATUS_OK. 
- */
-
-NTSTATUS ntlmssp_server_update(NTLMSSP_STATE *ntlmssp_state, 
-                              const DATA_BLOB request, DATA_BLOB *reply) 
-{
-       uint32 ntlmssp_command;
-       *reply = data_blob(NULL, 0);
-
-       if (request.length) {
-               if (!msrpc_parse(&request, "Cd",
-                                "NTLMSSP",
-                                &ntlmssp_command)) {
-                       return NT_STATUS_INVALID_PARAMETER;
-               }
-       } else {
-               /* 'datagram' mode - no neg packet */
-               ntlmssp_command = NTLMSSP_NEGOTIATE;
-       }
-
-       if (ntlmssp_command != ntlmssp_state->expected_state) {
-               DEBUG(1, ("got NTLMSSP command %u, expected %u\n", ntlmssp_command, ntlmssp_state->expected_state));
-               return NT_STATUS_INVALID_PARAMETER;
-       }
-
-       if (ntlmssp_command == NTLMSSP_NEGOTIATE) {
-               return ntlmssp_server_negotiate(ntlmssp_state, request, reply);
-       } else if (ntlmssp_command == NTLMSSP_AUTH) {
-               return ntlmssp_server_auth(ntlmssp_state, request, reply);
-       } else {
-               DEBUG(1, ("unknown NTLMSSP command %u, expected %u\n", ntlmssp_command, ntlmssp_state->expected_state));
-               return NT_STATUS_INVALID_PARAMETER;
-       }
-}
-
 /*********************************************************************
  Client side NTLMSSP
 *********************************************************************/
@@ -405,11 +761,13 @@ NTSTATUS ntlmssp_server_update(NTLMSSP_STATE *ntlmssp_state,
  * @return Errors or NT_STATUS_OK. 
  */
 
-static NTSTATUS ntlmssp_client_initial(struct ntlmssp_client_state *ntlmssp_state, 
+static NTSTATUS ntlmssp_client_initial(struct ntlmssp_state *ntlmssp_state, 
                                  DATA_BLOB reply, DATA_BLOB *next_request) 
 {
        if (ntlmssp_state->unicode) {
                ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
+       } else {
+               ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_OEM;
        }
        
        if (ntlmssp_state->use_ntlmv2) {
@@ -426,6 +784,8 @@ static NTSTATUS ntlmssp_client_initial(struct ntlmssp_client_state *ntlmssp_stat
                  ntlmssp_state->get_domain(), 
                  ntlmssp_state->get_global_myname());
 
+       ntlmssp_state->expected_state = NTLMSSP_CHALLENGE;
+
        return NT_STATUS_MORE_PROCESSING_REQUIRED;
 }
 
@@ -438,7 +798,7 @@ static NTSTATUS ntlmssp_client_initial(struct ntlmssp_client_state *ntlmssp_stat
  * @return Errors or NT_STATUS_OK. 
  */
 
-static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_state, 
+static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state, 
                                         const DATA_BLOB reply, DATA_BLOB *next_request) 
 {
        uint32 chal_flags, ntlmssp_command, unkn1, unkn2;
@@ -469,17 +829,16 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_st
        DEBUG(3, ("Got challenge flags:\n"));
        debug_ntlmssp_flags(chal_flags);
 
-       if (chal_flags & NTLMSSP_NEGOTIATE_UNICODE) {
+       ntlmssp_handle_neg_flags(ntlmssp_state, chal_flags, lp_client_lanman_auth());
+
+       if (ntlmssp_state->unicode) {
                if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) {
                        chal_parse_string = "CdUdbddB";
                } else {
                        chal_parse_string = "CdUdbdd";
                }
                auth_gen_string = "CdBBUUUBd";
-               ntlmssp_state->unicode = True;
-               ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
-               ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_OEM;
-       } else if (chal_flags & NTLMSSP_NEGOTIATE_OEM) {
+       } else {
                if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) {
                        chal_parse_string = "CdAdbddB";
                } else {
@@ -487,32 +846,6 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_st
                }
 
                auth_gen_string = "CdBBAAABd";
-
-               ntlmssp_state->unicode = False;
-               ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_UNICODE;
-               ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_OEM;
-       } else {
-               return NT_STATUS_INVALID_PARAMETER;
-       }
-
-       if (chal_flags & NTLMSSP_NEGOTIATE_LM_KEY && lp_client_lanman_auth()) {
-               /* server forcing us to use LM */
-               ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_LM_KEY;
-               ntlmssp_state->use_ntlmv2 = False;
-       } else {
-               ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
-       }
-
-       if (!(chal_flags & NTLMSSP_NEGOTIATE_NTLM2)) {
-               ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
-       }
-
-       if (!(chal_flags & NTLMSSP_NEGOTIATE_128)) {
-               ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_128;
-       }
-
-       if (!(chal_flags & NTLMSSP_NEGOTIATE_KEY_EXCH)) {
-               ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_KEY_EXCH;
        }
 
        DEBUG(3, ("NTLMSSP: Set final flags:\n"));
@@ -546,6 +879,7 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_st
 
                if (!struct_blob.length) {
                        /* be lazy, match win2k - we can't do NTLMv2 without it */
+                       DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n"));
                        return NT_STATUS_INVALID_PARAMETER;
                }
 
@@ -569,7 +903,7 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_st
                uchar nt_session_key[16];
                E_md4hash(ntlmssp_state->password, nt_hash);
                
-               lm_response = data_blob(NULL, 24);
+               lm_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24);
                generate_random_buffer(lm_response.data, 8, False);
                memset(lm_response.data+8, 0, 16);
 
@@ -580,16 +914,21 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_st
                MD5Update(&md5_session_nonce_ctx, challenge_blob.data, 8);
                MD5Update(&md5_session_nonce_ctx, lm_response.data, 8);
                MD5Final(session_nonce_hash, &md5_session_nonce_ctx);
+
+               DEBUG(5, ("NTLMSSP challenge set by NTLM2\n"));
+               DEBUG(5, ("challenge is: \n"));
+               dump_data(5, session_nonce_hash, 8);
                
-               nt_response = data_blob(NULL, 24);
+               nt_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24);
                SMBNTencrypt(ntlmssp_state->password,
                             session_nonce_hash,
                             nt_response.data);
 
-               session_key = data_blob(NULL, 16);
+               session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16);
 
                SMBsesskeygen_ntv1(nt_hash, NULL, nt_session_key);
                hmac_md5(nt_session_key, session_nonce, sizeof(session_nonce), session_key.data);
+               dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);
        } else {
                
                
@@ -600,22 +939,24 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_st
                
                /* lanman auth is insecure, it may be disabled */
                if (lp_client_lanman_auth()) {
-                       lm_response = data_blob(NULL, 24);
+                       lm_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24);
                        SMBencrypt(ntlmssp_state->password,challenge_blob.data,
                                   lm_response.data);
-                       }
+               }
                
-               nt_response = data_blob(NULL, 24);
+               nt_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24);
                SMBNTencrypt(ntlmssp_state->password,challenge_blob.data,
                             nt_response.data);
                
-               session_key = data_blob(NULL, 16);
+               session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16);
                if ((ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) 
                    && lp_client_lanman_auth()) {
                        SMBsesskeygen_lmv1(lm_hash, lm_response.data, 
                                           session_key.data);
+                       dump_data_pw("LM session key\n", session_key.data, session_key.length);
                } else {
                        SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data);
+                       dump_data_pw("NT session key:\n", session_key.data, session_key.length);
                }
        }
        data_blob_free(&struct_blob);
@@ -627,9 +968,12 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_st
                
                generate_random_buffer(client_session_key, sizeof(client_session_key), False);  
                encrypted_session_key = data_blob(client_session_key, sizeof(client_session_key));
+               dump_data_pw("KEY_EXCH session key:\n", encrypted_session_key.data, encrypted_session_key.length);
+
                SamOEMhash(encrypted_session_key.data, session_key.data, encrypted_session_key.length);
                data_blob_free(&session_key);
-               session_key = data_blob(client_session_key, sizeof(client_session_key));
+               session_key = data_blob_talloc(ntlmssp_state->mem_ctx, client_session_key, sizeof(client_session_key));
+               dump_data_pw("KEY_EXCH session key (enc):\n", encrypted_session_key.data, encrypted_session_key.length);
        }
 
        /* this generates the actual auth packet */
@@ -644,28 +988,24 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_st
                       encrypted_session_key.data, encrypted_session_key.length,
                       ntlmssp_state->neg_flags)) {
                
-               data_blob_free(&lm_response);
-               data_blob_free(&nt_response);
-               data_blob_free(&session_key);
                return NT_STATUS_NO_MEMORY;
        }
 
        data_blob_free(&encrypted_session_key);
 
        data_blob_free(&ntlmssp_state->chal);
-       data_blob_free(&ntlmssp_state->lm_resp);
-       data_blob_free(&ntlmssp_state->nt_resp);
-       data_blob_free(&ntlmssp_state->session_key);
 
        ntlmssp_state->chal = challenge_blob;
        ntlmssp_state->lm_resp = lm_response;
        ntlmssp_state->nt_resp = nt_response;
        ntlmssp_state->session_key = session_key;
 
+       ntlmssp_state->expected_state = NTLMSSP_UNKNOWN;
+
        return NT_STATUS_MORE_PROCESSING_REQUIRED;
 }
 
-NTSTATUS ntlmssp_client_start(NTLMSSP_CLIENT_STATE **ntlmssp_state)
+NTSTATUS ntlmssp_client_start(NTLMSSP_STATE **ntlmssp_state)
 {
        TALLOC_CTX *mem_ctx;
 
@@ -678,6 +1018,8 @@ NTSTATUS ntlmssp_client_start(NTLMSSP_CLIENT_STATE **ntlmssp_state)
                return NT_STATUS_NO_MEMORY;
        }
 
+       (*ntlmssp_state)->role = NTLMSSP_CLIENT;
+
        (*ntlmssp_state)->mem_ctx = mem_ctx;
 
        (*ntlmssp_state)->get_global_myname = global_myname;
@@ -687,6 +1029,10 @@ NTSTATUS ntlmssp_client_start(NTLMSSP_CLIENT_STATE **ntlmssp_state)
 
        (*ntlmssp_state)->use_ntlmv2 = lp_client_ntlmv2_auth();
 
+       (*ntlmssp_state)->expected_state = NTLMSSP_INITIAL;
+
+       (*ntlmssp_state)->ref_count = 1;
+
        (*ntlmssp_state)->neg_flags = 
                NTLMSSP_NEGOTIATE_128 |
                NTLMSSP_NEGOTIATE_NTLM |
@@ -700,101 +1046,6 @@ NTSTATUS ntlmssp_client_start(NTLMSSP_CLIENT_STATE **ntlmssp_state)
                NTLMSSP_NEGOTIATE_SIGN |
                NTLMSSP_REQUEST_TARGET;
 
-       (*ntlmssp_state)->ref_count = 1;
-
-       return NT_STATUS_OK;
-}
-
-NTSTATUS ntlmssp_client_end(NTLMSSP_CLIENT_STATE **ntlmssp_state)
-{
-       TALLOC_CTX *mem_ctx = (*ntlmssp_state)->mem_ctx;
-
-       (*ntlmssp_state)->ref_count--;
-
-       if ((*ntlmssp_state)->ref_count == 0) {
-               data_blob_free(&(*ntlmssp_state)->chal);
-               data_blob_free(&(*ntlmssp_state)->lm_resp);
-               data_blob_free(&(*ntlmssp_state)->nt_resp);
-               data_blob_free(&(*ntlmssp_state)->session_key);
-               data_blob_free(&(*ntlmssp_state)->stored_response);
-               talloc_destroy(mem_ctx);
-       }
-
-       *ntlmssp_state = NULL;
        return NT_STATUS_OK;
 }
 
-NTSTATUS ntlmssp_client_update(NTLMSSP_CLIENT_STATE *ntlmssp_state, 
-                              DATA_BLOB reply, DATA_BLOB *next_request) 
-{
-       NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
-       uint32 ntlmssp_command;
-       *next_request = data_blob(NULL, 0);
-
-       if (!reply.length) {
-               /* If there is a cached reply, use it - otherwise this is the first packet */
-               if (!ntlmssp_state->stored_response.length) {
-                       return ntlmssp_client_initial(ntlmssp_state, reply, next_request);
-               }
-               
-               reply = ntlmssp_state->stored_response;
-       }
-
-       if (!msrpc_parse(&reply, "Cd",
-                        "NTLMSSP",
-                        &ntlmssp_command)) {
-               return NT_STATUS_INVALID_PARAMETER;
-       }
-
-       if (ntlmssp_command == NTLMSSP_CHALLENGE) {
-               nt_status = ntlmssp_client_challenge(ntlmssp_state, reply, next_request);
-       }
-       if (ntlmssp_state->stored_response.length) {
-               data_blob_free(&ntlmssp_state->stored_response);
-       }
-       return nt_status;
-}
-
-NTSTATUS ntlmssp_set_username(NTLMSSP_CLIENT_STATE *ntlmssp_state, const char *user) 
-{
-       ntlmssp_state->user = talloc_strdup(ntlmssp_state->mem_ctx, user);
-       if (!ntlmssp_state->user) {
-               return NT_STATUS_NO_MEMORY;
-       }
-       return NT_STATUS_OK;
-}
-
-NTSTATUS ntlmssp_set_password(NTLMSSP_CLIENT_STATE *ntlmssp_state, const char *password) 
-{
-       if (!password) {
-               ntlmssp_state->password = NULL;
-       } else {
-               ntlmssp_state->password = talloc_strdup(ntlmssp_state->mem_ctx, password);
-               if (!ntlmssp_state->password) {
-                       return NT_STATUS_NO_MEMORY;
-               }
-       }
-       return NT_STATUS_OK;
-}
-
-NTSTATUS ntlmssp_set_domain(NTLMSSP_CLIENT_STATE *ntlmssp_state, const char *domain) 
-{
-       ntlmssp_state->domain = talloc_strdup(ntlmssp_state->mem_ctx, domain);
-       if (!ntlmssp_state->domain) {
-               return NT_STATUS_NO_MEMORY;
-       }
-       return NT_STATUS_OK;
-}
-
-/**
- *  Store a DATA_BLOB containing an NTLMSSP response, for use later.
- *  This 'keeps' the data blob - the caller must *not* free it.
- */
-
-NTSTATUS ntlmssp_client_store_response(NTLMSSP_CLIENT_STATE *ntlmssp_state,
-                                      DATA_BLOB response) 
-{
-       data_blob_free(&ntlmssp_state->stored_response);
-       ntlmssp_state->stored_response = response;
-       return NT_STATUS_OK;
-}
index b136dacf5a2549792b30498ab8dbd58437be5740..3444db030689ba6194eeeec49d61371ef920dee8 100644 (file)
@@ -31,7 +31,7 @@
   format specifiers are:
 
   U = unicode string (input is unix string)
-  a = address (input is BOOL unicode, char *unix_string)
+  a = address (input is char *unix_string)
       (1 byte type, 1 byte length, unicode/ASCII string, all inline)
   A = ASCII string (input is unix string)
   B = data blob (pointer + length)
@@ -49,7 +49,6 @@ BOOL msrpc_gen(DATA_BLOB *blob,
        uint8 *b;
        int head_size=0, data_size=0;
        int head_ofs, data_ofs;
-       BOOL unicode;
 
        /* first scan the format to work out the header and body size */
        va_start(ap, format);
@@ -66,14 +65,9 @@ BOOL msrpc_gen(DATA_BLOB *blob,
                        data_size += str_ascii_charnum(s);
                        break;
                case 'a':
-                       unicode = va_arg(ap, BOOL);
                        n = va_arg(ap, int);
                        s = va_arg(ap, char *);
-                       if (unicode) {
-                               data_size += (str_charnum(s) * 2) + 4;
-                       } else {
-                               data_size += (str_ascii_charnum(s)) + 4;
-                       }
+                       data_size += (str_charnum(s) * 2) + 4;
                        break;
                case 'B':
                        b = va_arg(ap, uint8 *);
@@ -124,27 +118,16 @@ BOOL msrpc_gen(DATA_BLOB *blob,
                        data_ofs += n;
                        break;
                case 'a':
-                       unicode = va_arg(ap, BOOL);
                        n = va_arg(ap, int);
                        SSVAL(blob->data, data_ofs, n); data_ofs += 2;
                        s = va_arg(ap, char *);
-                       if (unicode) {
-                               n = str_charnum(s);
-                               SSVAL(blob->data, data_ofs, n*2); data_ofs += 2;
-                               if (0 < n) {
-                                       push_string(NULL, blob->data+data_ofs, s, n*2,
-                                                   STR_UNICODE|STR_NOALIGN);
-                               }
-                               data_ofs += n*2;
-                       } else {
-                               n = str_ascii_charnum(s);
-                               SSVAL(blob->data, data_ofs, n); data_ofs += 2;
-                               if (0 < n) {
-                                       push_string(NULL, blob->data+data_ofs, s, n,
-                                                   STR_ASCII|STR_NOALIGN);
-                               }
-                               data_ofs += n;
+                       n = str_charnum(s);
+                       SSVAL(blob->data, data_ofs, n*2); data_ofs += 2;
+                       if (0 < n) {
+                               push_string(NULL, blob->data+data_ofs, s, n*2,
+                                           STR_UNICODE|STR_NOALIGN);
                        }
+                       data_ofs += n*2;
                        break;
 
                case 'B':
index 153c234d1f84b2e080a946efc6b4f1bacc33727b..ea1a7037c9ccb5af0aef247b9d86a7b8fb136838 100644 (file)
@@ -102,7 +102,7 @@ enum ntlmssp_direction {
        NTLMSSP_RECEIVE
 };
 
-static NTSTATUS ntlmssp_make_packet_signature(NTLMSSP_CLIENT_STATE *ntlmssp_state,
+static NTSTATUS ntlmssp_make_packet_signature(NTLMSSP_STATE *ntlmssp_state,
                                              const uchar *data, size_t length, 
                                              enum ntlmssp_direction direction,
                                              DATA_BLOB *sig) 
@@ -113,7 +113,7 @@ static NTSTATUS ntlmssp_make_packet_signature(NTLMSSP_CLIENT_STATE *ntlmssp_stat
                uchar digest[16];
                SIVAL(seq_num, 0, ntlmssp_state->ntlmssp_seq_num);
 
-               hmac_md5_init_limK_to_64((const unsigned char *)(ntlmssp_state->cli_sign_const), 16, &ctx);
+               hmac_md5_init_limK_to_64((const unsigned char *)(ntlmssp_state->send_sign_const), 16, &ctx);
                hmac_md5_update((const unsigned char *)seq_num, 4, &ctx);
                hmac_md5_update(data, length, &ctx);
                hmac_md5_final(digest, &ctx);
@@ -124,10 +124,10 @@ static NTSTATUS ntlmssp_make_packet_signature(NTLMSSP_CLIENT_STATE *ntlmssp_stat
                }
                switch (direction) {
                case NTLMSSP_SEND:
-                       NTLMSSPcalc_ap(ntlmssp_state->cli_sign_hash,  sig->data+4, sig->length-4);
+                       NTLMSSPcalc_ap(ntlmssp_state->send_sign_hash,  sig->data+4, sig->length-4);
                        break;
                case NTLMSSP_RECEIVE:
-                       NTLMSSPcalc_ap(ntlmssp_state->srv_sign_hash,  sig->data+4, sig->length-4);
+                       NTLMSSPcalc_ap(ntlmssp_state->recv_sign_hash,  sig->data+4, sig->length-4);
                        break;
                }
        } else {
@@ -144,9 +144,9 @@ static NTSTATUS ntlmssp_make_packet_signature(NTLMSSP_CLIENT_STATE *ntlmssp_stat
        return NT_STATUS_OK;
 }
 
-NTSTATUS ntlmssp_client_sign_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
-                                          const uchar *data, size_t length, 
-                                          DATA_BLOB *sig) 
+NTSTATUS ntlmssp_sign_packet(NTLMSSP_STATE *ntlmssp_state,
+                                   const uchar *data, size_t length, 
+                                   DATA_BLOB *sig) 
 {
        NTSTATUS nt_status = ntlmssp_make_packet_signature(ntlmssp_state, data, length, NTLMSSP_SEND, sig);
 
@@ -161,9 +161,9 @@ NTSTATUS ntlmssp_client_sign_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
  *
  */
 
-NTSTATUS ntlmssp_client_check_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
-                                    const uchar *data, size_t length, 
-                                    const DATA_BLOB *sig) 
+NTSTATUS ntlmssp_check_packet(NTLMSSP_STATE *ntlmssp_state,
+                             const uchar *data, size_t length, 
+                             const DATA_BLOB *sig) 
 {
        DATA_BLOB local_sig;
        NTSTATUS nt_status;
@@ -204,11 +204,11 @@ NTSTATUS ntlmssp_client_check_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
  *
  */
 
-NTSTATUS ntlmssp_client_seal_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
-                                   uchar *data, size_t length,
-                                   DATA_BLOB *sig)
+NTSTATUS ntlmssp_seal_packet(NTLMSSP_STATE *ntlmssp_state,
+                            uchar *data, size_t length,
+                            DATA_BLOB *sig)
 {      
-       DEBUG(10,("ntlmssp_client_seal_data: seal\n"));
+       DEBUG(10,("ntlmssp_seal_data: seal\n"));
        dump_data_pw("ntlmssp clear data\n", data, length);
        if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
                HMACMD5Context ctx;
@@ -216,7 +216,7 @@ NTSTATUS ntlmssp_client_seal_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
                uchar digest[16];
                SIVAL(seq_num, 0, ntlmssp_state->ntlmssp_seq_num);
 
-               hmac_md5_init_limK_to_64((const unsigned char *)(ntlmssp_state->cli_sign_const), 16, &ctx);
+               hmac_md5_init_limK_to_64((const unsigned char *)(ntlmssp_state->send_sign_const), 16, &ctx);
                hmac_md5_update((const unsigned char *)seq_num, 4, &ctx);
                hmac_md5_update(data, length, &ctx);
                hmac_md5_final(digest, &ctx);
@@ -227,13 +227,13 @@ NTSTATUS ntlmssp_client_seal_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
                }
 
                dump_data_pw("ntlmssp client sealing hash:\n", 
-                            ntlmssp_state->cli_seal_hash,
-                            sizeof(ntlmssp_state->cli_seal_hash));
-               NTLMSSPcalc_ap(ntlmssp_state->cli_seal_hash, data, length);
+                            ntlmssp_state->send_seal_hash,
+                            sizeof(ntlmssp_state->send_seal_hash));
+               NTLMSSPcalc_ap(ntlmssp_state->send_seal_hash, data, length);
                dump_data_pw("ntlmssp client signing hash:\n", 
-                            ntlmssp_state->cli_sign_hash,
-                            sizeof(ntlmssp_state->cli_sign_hash));
-               NTLMSSPcalc_ap(ntlmssp_state->cli_sign_hash,  sig->data+4, sig->length-4);
+                            ntlmssp_state->send_sign_hash,
+                            sizeof(ntlmssp_state->send_sign_hash));
+               NTLMSSPcalc_ap(ntlmssp_state->send_sign_hash,  sig->data+4, sig->length-4);
        } else {
                uint32 crc;
                crc = crc32_calc_buffer((const char *)data, length);
@@ -266,14 +266,14 @@ NTSTATUS ntlmssp_client_seal_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
  *
  */
 
-NTSTATUS ntlmssp_client_unseal_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
+NTSTATUS ntlmssp_unseal_packet(NTLMSSP_STATE *ntlmssp_state,
                                      uchar *data, size_t length,
                                      DATA_BLOB *sig)
 {
-       DEBUG(10,("ntlmssp_client_unseal_data: seal\n"));
+       DEBUG(10,("ntlmssp__unseal_data: seal\n"));
        dump_data_pw("ntlmssp sealed data\n", data, length);
        if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
-               NTLMSSPcalc_ap(ntlmssp_state->srv_seal_hash, data, length);
+               NTLMSSPcalc_ap(ntlmssp_state->recv_seal_hash, data, length);
        } else {
                dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
                             sizeof(ntlmssp_state->ntlmssp_hash));
@@ -281,13 +281,13 @@ NTSTATUS ntlmssp_client_unseal_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
        }
        dump_data_pw("ntlmssp clear data\n", data, length);
 
-       return ntlmssp_client_check_packet(ntlmssp_state, data, length, sig);
+       return ntlmssp_check_packet(ntlmssp_state, data, length, sig);
 }
 
 /**
    Initialise the state for NTLMSSP signing.
 */
-NTSTATUS ntlmssp_client_sign_init(NTLMSSP_CLIENT_STATE *ntlmssp_state)
+NTSTATUS ntlmssp_sign_init(NTLMSSP_STATE *ntlmssp_state)
 {
        unsigned char p24[24];
        ZERO_STRUCT(p24);
@@ -297,34 +297,54 @@ NTSTATUS ntlmssp_client_sign_init(NTLMSSP_CLIENT_STATE *ntlmssp_state)
 
        if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2)
        {
+               const char *send_sign_const;
+               const char *send_seal_const;
+               const char *recv_sign_const;
+               const char *recv_seal_const;
+
+               switch (ntlmssp_state->role) {
+               case NTLMSSP_CLIENT:
+                       send_sign_const = CLI_SIGN;
+                       send_seal_const = CLI_SEAL;
+                       recv_sign_const = SRV_SIGN;
+                       recv_seal_const = SRV_SEAL;
+                       break;
+               case NTLMSSP_SERVER:
+                       send_sign_const = SRV_SIGN;
+                       send_seal_const = SRV_SEAL;
+                       recv_sign_const = CLI_SIGN;
+                       recv_seal_const = CLI_SEAL;
+                       break;
+               }
+
+               calc_ntlmv2_hash(ntlmssp_state->send_sign_hash, 
+                                ntlmssp_state->send_sign_const, 
+                                ntlmssp_state->session_key, send_sign_const);
+               dump_data_pw("NTLMSSP send sign hash:\n", 
+                            ntlmssp_state->send_sign_hash, 
+                            sizeof(ntlmssp_state->send_sign_hash));
+
+               calc_ntlmv2_hash(ntlmssp_state->send_seal_hash, 
+                                ntlmssp_state->send_seal_const, 
+                                ntlmssp_state->session_key, send_seal_const);
+               dump_data_pw("NTLMSSP send sesl hash:\n", 
+                            ntlmssp_state->send_seal_hash, 
+                            sizeof(ntlmssp_state->send_seal_hash));
+
+               calc_ntlmv2_hash(ntlmssp_state->recv_sign_hash, 
+                                ntlmssp_state->recv_sign_const, 
+                                ntlmssp_state->session_key, send_sign_const);
+               dump_data_pw("NTLMSSP receive sign hash:\n", 
+                            ntlmssp_state->recv_sign_hash, 
+                            sizeof(ntlmssp_state->recv_sign_hash));
+
+               calc_ntlmv2_hash(ntlmssp_state->recv_seal_hash, 
+                                ntlmssp_state->recv_seal_const, 
+                                ntlmssp_state->session_key, send_seal_const);
+               dump_data_pw("NTLMSSP receive seal hash:\n", 
+                            ntlmssp_state->recv_sign_hash, 
+                            sizeof(ntlmssp_state->recv_sign_hash));
 
-               calc_ntlmv2_hash(ntlmssp_state->cli_sign_hash, 
-                                ntlmssp_state->cli_sign_const, 
-                                ntlmssp_state->session_key, CLI_SIGN);
-               dump_data_pw("NTLMSSP client sign hash:\n", 
-                            ntlmssp_state->cli_sign_hash, 
-                            sizeof(ntlmssp_state->cli_sign_hash));
-
-               calc_ntlmv2_hash(ntlmssp_state->cli_seal_hash, 
-                                ntlmssp_state->cli_seal_const, 
-                                ntlmssp_state->session_key, CLI_SEAL);
-               dump_data_pw("NTLMSSP client sesl hash:\n", 
-                            ntlmssp_state->cli_seal_hash, 
-                            sizeof(ntlmssp_state->cli_seal_hash));
-
-               calc_ntlmv2_hash(ntlmssp_state->srv_sign_hash, 
-                                ntlmssp_state->srv_sign_const, 
-                                ntlmssp_state->session_key, SRV_SIGN);
-               dump_data_pw("NTLMSSP server sign hash:\n", 
-                            ntlmssp_state->srv_sign_hash, 
-                            sizeof(ntlmssp_state->srv_sign_hash));
-
-               calc_ntlmv2_hash(ntlmssp_state->srv_seal_hash, 
-                                ntlmssp_state->srv_seal_const, 
-                                ntlmssp_state->session_key, SRV_SEAL);
-               dump_data_pw("NTLMSSP server seal hash:\n", 
-                            ntlmssp_state->cli_sign_hash, 
-                            sizeof(ntlmssp_state->cli_sign_hash));
        } 
        else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) {
                if (!ntlmssp_state->session_key.data || ntlmssp_state->session_key.length < 8) {
index 91509f0fb81d6cb3a10f5b3f3bd8782d6bf8dca3..eec991072ddfbfe4130cb93fddddead4bf482531 100644 (file)
@@ -405,11 +405,11 @@ static void simple_free_signing_context(struct smb_sign_info *si)
  SMB signing - Simple implementation - setup the MAC key.
 ************************************************************/
 
-BOOL cli_simple_set_signing(struct cli_state *cli, const uchar user_session_key[16], const DATA_BLOB response)
+BOOL cli_simple_set_signing(struct cli_state *cli, const DATA_BLOB user_session_key, const DATA_BLOB response)
 {
        struct smb_basic_signing_context *data;
 
-       if (!user_session_key)
+       if (!user_session_key.length)
                return False;
 
        if (!cli_set_smb_signing_common(cli)) {
@@ -425,21 +425,23 @@ BOOL cli_simple_set_signing(struct cli_state *cli, const uchar user_session_key[
 
        cli->sign_info.signing_context = data;
        
-       data->mac_key = data_blob(NULL, response.length + 16);
+       data->mac_key = data_blob(NULL, response.length + user_session_key.length);
 
-       memcpy(&data->mac_key.data[0], user_session_key, 16);
+       memcpy(&data->mac_key.data[0], user_session_key.data, user_session_key.length);
 
        DEBUG(10, ("cli_simple_set_signing: user_session_key\n"));
-       dump_data(10, (const char *)user_session_key, 16);
+       dump_data(10, (const char *)user_session_key.data, user_session_key.length);
 
        if (response.length) {
-               memcpy(&data->mac_key.data[16],response.data, response.length);
+               memcpy(&data->mac_key.data[user_session_key.length],response.data, response.length);
                DEBUG(10, ("cli_simple_set_signing: response_data\n"));
                dump_data(10, (const char *)response.data, response.length);
        } else {
                DEBUG(10, ("cli_simple_set_signing: NULL response_data\n"));
        }
 
+       dump_data_pw("MAC ssession key is:\n", data->mac_key.data, data->mac_key.length);
+
        /* Initialise the sequence number */
        data->send_seq_num = 0;
 
@@ -928,11 +930,11 @@ data->send_seq_num = %u\n",
  Turn on signing from this packet onwards. 
 ************************************************************/
 
-void srv_set_signing(const uchar user_session_key[16], const DATA_BLOB response)
+void srv_set_signing(const DATA_BLOB user_session_key, const DATA_BLOB response)
 {
        struct smb_basic_signing_context *data;
 
-       if (!user_session_key)
+       if (!user_session_key.length)
                return;
 
        if (!srv_sign_info.negotiated_smb_signing && !srv_sign_info.mandatory_signing) {
@@ -957,11 +959,13 @@ void srv_set_signing(const uchar user_session_key[16], const DATA_BLOB response)
 
        srv_sign_info.signing_context = data;
        
-       data->mac_key = data_blob(NULL, response.length + 16);
+       data->mac_key = data_blob(NULL, response.length + user_session_key.length);
 
-       memcpy(&data->mac_key.data[0], user_session_key, 16);
+       memcpy(&data->mac_key.data[0], user_session_key.data, user_session_key.length);
        if (response.length)
-               memcpy(&data->mac_key.data[16],response.data, response.length);
+               memcpy(&data->mac_key.data[user_session_key.length],response.data, response.length);
+
+       dump_data_pw("MAC ssession key is:\n", data->mac_key.data, data->mac_key.length);
 
        /* Initialise the sequence number */
        data->send_seq_num = 0;
index ec31bb5dbaabe8552421e497ecfc24100d226163..2d02a2339436c3474432cd6c83c70c8b0ae92f7b 100644 (file)
@@ -331,9 +331,9 @@ DATA_BLOB NTLMv2_generate_names_blob(const char *hostname,
        DATA_BLOB names_blob = data_blob(NULL, 0);
        
        msrpc_gen(&names_blob, "aaa", 
-                 True, NTLMSSP_NAME_TYPE_DOMAIN, domain,
-                 True, NTLMSSP_NAME_TYPE_SERVER, hostname,
-                 True, 0, "");
+                 NTLMSSP_NAME_TYPE_DOMAIN, domain,
+                 NTLMSSP_NAME_TYPE_SERVER, hostname,
+                 0, "");
        return names_blob;
 }
 
index 4bf5a304590dd25640706536e02af39fbdfe8ae4..ac9cd8f332931d329d42ce52b16af3970ac68d47 100644 (file)
@@ -179,10 +179,9 @@ static NTSTATUS cm_open_connection(const char *domain, const int pipe_index,
 
                                result = NT_STATUS_OK;
 
-                               if (!cli_session_setup_spnego(new_conn->cli, machine_krb5_principal, 
+                               if (!NT_STATUS_IS_OK(result = cli_session_setup_spnego(new_conn->cli, machine_krb5_principal, 
                                                              machine_password, 
-                                                             domain)) {
-                                       result = cli_nt_error(new_conn->cli);
+                                                             domain))) {
                                        DEBUG(4,("failed kerberos session setup with %s\n", nt_errstr(result)));
                                        if (NT_STATUS_IS_OK(result)) 
                                                result = NT_STATUS_UNSUCCESSFUL;
index d43dca29c5410d922fae2fc21026f38e519df1c3..d849a6d5a92c09a31291caa6547725107c0c127b 100644 (file)
@@ -225,9 +225,15 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
        DATA_BLOB lm_resp, nt_resp;
 
        if (!state->privileged) {
-               DEBUG(2, ("winbindd_pam_auth_crap: non-privileged access denied!\n"));
+               char *error_string = NULL;
+               DEBUG(2, ("winbindd_pam_auth_crap: non-privileged access denied.  !\n"));
+               DEBUGADD(2, ("winbindd_pam_auth_crap: Ensure permissions on %s are set correctly.\n", 
+                            get_winbind_priv_pipe_dir()));
                /* send a better message than ACCESS_DENIED */
-               push_utf8_fstring(state->response.data.auth.error_string, "winbind client not authorized to use winbindd_pam_auth_crap");
+               asprintf(&error_string, "winbind client not authorized to use winbindd_pam_auth_crap.  Ensure permissions on %s are set correctly.",
+                        get_winbind_priv_pipe_dir());
+               push_utf8_fstring(state->response.data.auth.error_string, error_string);
+               SAFE_FREE(error_string);
                result =  NT_STATUS_ACCESS_DENIED;
                goto done;
        }
index 97bc4c65b76c68985580c0709bbc859242f9d9d9..70ac4603034a6f57eb7a0d863c3a2c1046351e0a 100644 (file)
@@ -654,11 +654,17 @@ NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli, TALLOC_CTX *mem_c
        ZERO_STRUCT(netlogon_sess_key);
        memcpy(netlogon_sess_key, cli->sess_key, 8);
        
-       if (memcmp(zeros, info3->user_sess_key, 16) != 0)
+       if (memcmp(zeros, info3->user_sess_key, 16) != 0) {
                SamOEMhash(info3->user_sess_key, netlogon_sess_key, 16);
-               
-       if (memcmp(zeros, info3->padding, 16) != 0)
+       } else {
+               memset(info3->user_sess_key, '\0', 16);
+       }
+
+       if (memcmp(zeros, info3->padding, 16) != 0) {
                SamOEMhash(info3->padding, netlogon_sess_key, 16);
+       } else {
+               memset(info3->padding, '\0', 16);
+       }
 
         /* Return results */
 
index fdd9d3c3b1aa66600fde2d451df8a8ce14413686..aca0494dbddeab7540e724db466640c49bba6810 100644 (file)
@@ -264,13 +264,16 @@ static BOOL rpc_auth_pipe(struct cli_state *cli, prs_struct *rdata,
                           later use */
 
                        DATA_BLOB ntlmssp_verf = data_blob(NULL, auth_len);
-                       
+                       BOOL store_ok;
+
                        /* save the reply away, for use a little later */
                        prs_copy_data_out((char *)ntlmssp_verf.data, &auth_verf, auth_len);
 
+                       store_ok = (NT_STATUS_IS_OK(ntlmssp_store_response(cli->ntlmssp_pipe_state, 
+                                                                          ntlmssp_verf)));
 
-                       return (NT_STATUS_IS_OK(ntlmssp_client_store_response(cli->ntlmssp_pipe_state, 
-                                                                             ntlmssp_verf)));
+                       data_blob_free(&ntlmssp_verf);
+                       return store_ok;
                } 
                else if (cli->pipe_auth_flags & AUTH_PIPE_NETSEC) {
                        /* nothing to do here - we don't seem to be able to 
@@ -307,12 +310,12 @@ static BOOL rpc_auth_pipe(struct cli_state *cli, prs_struct *rdata,
                                DEBUG(1, ("Can't unseal - data_len < 0!!\n"));
                                return False;
                        }
-                       nt_status = ntlmssp_client_unseal_packet(cli->ntlmssp_pipe_state, 
+                       nt_status = ntlmssp_unseal_packet(cli->ntlmssp_pipe_state, 
                                                                 (unsigned char *)reply_data, data_len,
                                                                 &sig);
                } 
                else if (cli->pipe_auth_flags & AUTH_PIPE_SIGN) {
-                       nt_status = ntlmssp_client_check_packet(cli->ntlmssp_pipe_state, 
+                       nt_status = ntlmssp_check_packet(cli->ntlmssp_pipe_state, 
                                                                (const unsigned char *)reply_data, data_len,
                                                                &sig);
                }
@@ -674,9 +677,9 @@ static NTSTATUS create_rpc_bind_req(struct cli_state *cli, prs_struct *rpc_out,
                DATA_BLOB request;
 
                DEBUG(5, ("Processing NTLMSSP Negotiate\n"));
-               nt_status = ntlmssp_client_update(cli->ntlmssp_pipe_state,
-                                                 null_blob,
-                                                 &request);
+               nt_status = ntlmssp_update(cli->ntlmssp_pipe_state,
+                                          null_blob,
+                                          &request);
 
                if (!NT_STATUS_EQUAL(nt_status, 
                                     NT_STATUS_MORE_PROCESSING_REQUIRED)) {
@@ -777,9 +780,9 @@ static NTSTATUS create_rpc_bind_resp(struct cli_state *cli,
 
        /* The response is picked up from the internal cache,
           where it was placed by the rpc_auth_pipe() code */
-       nt_status = ntlmssp_client_update(cli->ntlmssp_pipe_state,
-                                         ntlmssp_null_response,
-                                         &ntlmssp_reply);
+       nt_status = ntlmssp_update(cli->ntlmssp_pipe_state,
+                                  ntlmssp_null_response,
+                                  &ntlmssp_reply);
        
        if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
                return nt_status;
@@ -820,7 +823,7 @@ static NTSTATUS create_rpc_bind_resp(struct cli_state *cli,
        }
 
        if (cli->pipe_auth_flags & AUTH_PIPE_SIGN) {
-               nt_status = ntlmssp_client_sign_init(cli->ntlmssp_pipe_state);
+               nt_status = ntlmssp_sign_init(cli->ntlmssp_pipe_state);
                
                if (!NT_STATUS_IS_OK(nt_status)) {
                        return nt_status;
@@ -994,7 +997,7 @@ BOOL rpc_api_pipe_req(struct cli_state *cli, uint8 op_num,
                                 */
                                if (cli->pipe_auth_flags & AUTH_PIPE_SEAL) {
                                        
-                                       nt_status = ntlmssp_client_seal_packet(cli->ntlmssp_pipe_state,
+                                       nt_status = ntlmssp_seal_packet(cli->ntlmssp_pipe_state,
                                                                               (unsigned char*)prs_data_p(&sec_blob),
                                                                               data_and_padding_size,
                                                                               &sign_blob);
@@ -1005,7 +1008,7 @@ BOOL rpc_api_pipe_req(struct cli_state *cli, uint8 op_num,
                                } 
                                else if (cli->pipe_auth_flags & AUTH_PIPE_SIGN) {
                                        
-                                       nt_status = ntlmssp_client_sign_packet(cli->ntlmssp_pipe_state,
+                                       nt_status = ntlmssp_sign_packet(cli->ntlmssp_pipe_state,
                                                                               (unsigned char*)prs_data_p(&sec_blob),
                                                                               data_and_padding_size, &sign_blob);
                                        if (!NT_STATUS_IS_OK(nt_status)) {
index e5e67f39dc9a7b0164c7446e7506f8b919df96a1..9bab816b8147366274aa2197f9030b2cb4124a37 100644 (file)
@@ -1341,7 +1341,7 @@ NTSTATUS cli_samr_create_dom_user(struct cli_state *cli, TALLOC_CTX *mem_ctx,
 
 NTSTATUS cli_samr_set_userinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
                                POLICY_HND *user_pol, uint16 switch_value,
-                               uchar sess_key[16], SAM_USERINFO_CTR *ctr)
+                               DATA_BLOB sess_key, SAM_USERINFO_CTR *ctr)
 {
        prs_struct qbuf, rbuf;
        SAMR_Q_SET_USERINFO q;
@@ -1353,6 +1353,11 @@ NTSTATUS cli_samr_set_userinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        ZERO_STRUCT(q);
        ZERO_STRUCT(r);
 
+       if (sess_key.length != 16) {
+               DEBUG(1, ("Cannot handle user session key of length [%u]\n", sess_key.length));
+               return NT_STATUS_NO_USER_SESSION_KEY;
+       }
+
        /* Initialise parse structures */
 
        prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
@@ -1393,7 +1398,7 @@ NTSTATUS cli_samr_set_userinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
 
 NTSTATUS cli_samr_set_userinfo2(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
                                 POLICY_HND *user_pol, uint16 switch_value,
-                                uchar sess_key[16], SAM_USERINFO_CTR *ctr)
+                                DATA_BLOB sess_key, SAM_USERINFO_CTR *ctr)
 {
        prs_struct qbuf, rbuf;
        SAMR_Q_SET_USERINFO2 q;
@@ -1402,6 +1407,11 @@ NTSTATUS cli_samr_set_userinfo2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
 
        DEBUG(10,("cli_samr_set_userinfo2\n"));
 
+       if (sess_key.length != 16) {
+               DEBUG(1, ("Cannot handle user session key of length [%u]\n", sess_key.length));
+               return NT_STATUS_NO_USER_SESSION_KEY;
+       }
+
        ZERO_STRUCT(q);
        ZERO_STRUCT(r);
 
index 3b096e088ab2aa19dbd62bbf4178d14e94970645..ad0a91e7ea5998f42fe3b57c4fc2e03b34dae67a 100644 (file)
@@ -1265,7 +1265,8 @@ void init_net_user_info3(TALLOC_CTX *ctx, NET_USER_INFO_3 *usr,
                         
                         uint16 logon_count, uint16 bad_pw_count,
                         uint32 num_groups, const DOM_GID *gids,
-                        uint32 user_flgs, uchar sess_key[16],
+                        uint32 user_flgs, uchar nt_session_key[16],
+                        uchar lm_session_key[16],
                         const char *logon_srv, const char *logon_dom,
                         const DOM_SID *dom_sid, const char *other_sids)
 {
@@ -1307,8 +1308,8 @@ void init_net_user_info3(TALLOC_CTX *ctx, NET_USER_INFO_3 *usr,
        usr->buffer_groups = 1; /* indicates fill in groups, below, even if there are none */
        usr->user_flgs = user_flgs;
 
-       if (sess_key != NULL)
-               memcpy(usr->user_sess_key, sess_key, sizeof(usr->user_sess_key));
+       if (nt_session_key != NULL)
+               memcpy(usr->user_sess_key, nt_session_key, sizeof(usr->user_sess_key));
        else
                memset((char *)usr->user_sess_key, '\0', sizeof(usr->user_sess_key));
 
@@ -1316,6 +1317,10 @@ void init_net_user_info3(TALLOC_CTX *ctx, NET_USER_INFO_3 *usr,
 
        memset((char *)usr->padding, '\0', sizeof(usr->padding));
 
+       if (lm_session_key != NULL) 
+               memcpy(usr->padding, lm_session_key, sizeof(usr->user_sess_key));
+
+
        num_other_sids = init_dom_sid2s(ctx, other_sids, &usr->other_sids);
 
        usr->num_other_sids = num_other_sids;
index 20adf0c7561b1c8cebbda4e94700ff2c9b003574..19665383627c8f38e6689ece821cc1aa60e576a6 100644 (file)
@@ -6302,7 +6302,7 @@ NTSTATUS make_samr_userinfo_ctr_usr21(TALLOC_CTX *ctx, SAM_USERINFO_CTR * ctr,
 inits a SAM_USERINFO_CTR structure.
 ********************************************************************/
 
-void init_samr_userinfo_ctr(SAM_USERINFO_CTR * ctr, uchar * sess_key,
+void init_samr_userinfo_ctr(SAM_USERINFO_CTR * ctr, DATA_BLOB sess_key,
                            uint16 switch_value, void *info)
 {
        DEBUG(5, ("init_samr_userinfo_ctr\n"));
@@ -6312,13 +6312,13 @@ void init_samr_userinfo_ctr(SAM_USERINFO_CTR * ctr, uchar * sess_key,
 
        switch (switch_value) {
        case 0x18:
-               SamOEMhash(ctr->info.id24->pass, sess_key, 516);
-               dump_data(100, (char *)sess_key, 16);
+               SamOEMhash(ctr->info.id24->pass, sess_key.data, 516);
+               dump_data(100, (char *)sess_key.data, 16);
                dump_data(100, (char *)ctr->info.id24->pass, 516);
                break;
        case 0x17:
-               SamOEMhash(ctr->info.id23->pass, sess_key, 516);
-               dump_data(100, (char *)sess_key, 16);
+               SamOEMhash(ctr->info.id23->pass, sess_key.data, 516);
+               dump_data(100, (char *)sess_key.data, 16);
                dump_data(100, (char *)ctr->info.id23->pass, 516);
                break;
        default:
@@ -6503,7 +6503,7 @@ inits a SAMR_Q_SET_USERINFO structure.
 ********************************************************************/
 
 void init_samr_q_set_userinfo(SAMR_Q_SET_USERINFO * q_u,
-                             POLICY_HND *hnd,  unsigned char sess_key[16],
+                             POLICY_HND *hnd, DATA_BLOB sess_key,
                              uint16 switch_value, void *info)
 {
        DEBUG(5, ("init_samr_q_set_userinfo\n"));
@@ -6577,7 +6577,7 @@ inits a SAMR_Q_SET_USERINFO2 structure.
 ********************************************************************/
 
 void init_samr_q_set_userinfo2(SAMR_Q_SET_USERINFO2 * q_u,
-                              POLICY_HND *hnd, unsigned char sess_key[16],
+                              POLICY_HND *hnd, DATA_BLOB sess_key,
                               uint16 switch_value, SAM_USERINFO_CTR * ctr)
 {
        DEBUG(5, ("init_samr_q_set_userinfo2\n"));
@@ -6591,9 +6591,9 @@ void init_samr_q_set_userinfo2(SAMR_Q_SET_USERINFO2 * q_u,
 
        switch (switch_value) {
        case 0x12:
-               SamOEMhash(ctr->info.id12->lm_pwd, sess_key, 16);
-               SamOEMhash(ctr->info.id12->nt_pwd, sess_key, 16);
-               dump_data(100, (char *)sess_key, 16);
+               SamOEMhash(ctr->info.id12->lm_pwd, sess_key.data, 16);
+               SamOEMhash(ctr->info.id12->nt_pwd, sess_key.data, 16);
+               dump_data(100, (char *)sess_key.data, 16);
                dump_data(100, (char *)ctr->info.id12->lm_pwd, 16);
                dump_data(100, (char *)ctr->info.id12->nt_pwd, 16);
                break;
index e6d005b157526063e89dfdf8aa3c3342e58521af..e8bc6345dee964ced45ccbc11a421c1640356428 100644 (file)
@@ -683,7 +683,8 @@ NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *
                pstring my_name;
                fstring user_sid_string;
                fstring group_sid_string;
-               uchar user_sess_key[16];
+               uchar nt_session_key[16];
+               uchar lm_session_key[16];
                uchar netlogon_sess_key[16];
 
                sampw = server_info->sam_account;
@@ -718,10 +719,18 @@ NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *
 
                ZERO_STRUCT(netlogon_sess_key);
                memcpy(netlogon_sess_key, p->dc.sess_key, 8);
-               memcpy(user_sess_key, server_info->session_key, sizeof(user_sess_key));
-               SamOEMhash(user_sess_key, netlogon_sess_key, 16);
+               if (server_info->nt_session_key.length) {
+                       memcpy(nt_session_key, server_info->nt_session_key.data, 
+                              MIN(sizeof(nt_session_key), server_info->nt_session_key.length));
+                       SamOEMhash(nt_session_key, netlogon_sess_key, 16);
+               }
+               if (server_info->lm_session_key.length) {
+                       memcpy(lm_session_key, server_info->lm_session_key.data, 
+                              MIN(sizeof(lm_session_key), server_info->lm_session_key.length));
+                       SamOEMhash(lm_session_key, netlogon_sess_key, 16);
+               }
                ZERO_STRUCT(netlogon_sess_key);
-
+               
                init_net_user_info3(p->mem_ctx, usr_info, 
                                    user_rid,
                                    group_rid,   
@@ -743,14 +752,16 @@ NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *
                                    num_gids,    /* uint32 num_groups */
                                    gids    , /* DOM_GID *gids */
                                    0x20    , /* uint32 user_flgs (?) */
-                                   user_sess_key,
+                                   server_info->nt_session_key.length ? nt_session_key : NULL,
+                                   server_info->lm_session_key.length ? lm_session_key : NULL,
                                    my_name     , /* char *logon_srv */
                                    pdb_get_domain(sampw),
                                    &domain_sid,     /* DOM_SID *dom_sid */  
                                    /* Should be users domain sid, not servers - for trusted domains */
                                  
                                    NULL); /* char *other_sids */
-               ZERO_STRUCT(user_sess_key);
+               ZERO_STRUCT(nt_session_key);
+               ZERO_STRUCT(lm_session_key);
        }
        free_server_info(&server_info);
        return status;
index 96261c665f7455bf24d8ff2e5c4a375fcbd4645d..fa24efe589bcb21601b852e88cdecb216cf7058d 100644 (file)
@@ -420,9 +420,15 @@ failed authentication on named pipe %s.\n", domain, user_name, wks, p->name ));
         * Set up the sign/seal data.
         */
 
-       {
+       if (server_info->lm_session_key.length != 16) {
+               DEBUG(1,("api_pipe_ntlmssp_verify: User [%s]\\[%s] from machine %s \
+succeeded authentication on named pipe %s, but session key was of incorrect length [%u].\n", 
+                        domain, user_name, wks, p->name, server_info->lm_session_key.length));
+               free_server_info(&server_info);
+               return False;
+       } else {
                uchar p24[24];
-               NTLMSSPOWFencrypt(server_info->first_8_lm_hash, lm_owf, p24);
+               NTLMSSPOWFencrypt(server_info->lm_session_key.data, lm_owf, p24);
                {
                        unsigned char j = 0;
                        int ind;
@@ -468,7 +474,7 @@ failed authentication on named pipe %s.\n", domain, user_name, wks, p->name ));
         * Store the UNIX credential data (uid/gid pair) in the pipe structure.
         */
 
-       memcpy(p->session_key, server_info->session_key, sizeof(p->session_key));
+       p->session_key = data_blob(server_info->lm_session_key.data, server_info->lm_session_key.length);
 
        p->pipe_user.uid = server_info->uid;
        p->pipe_user.gid = server_info->gid;
index 57e45d477fef2ce3e0e182abf4ad3b2a519af435..a9fd9ec652f90640cc9fdcf3d7645d49e522b5f2 100644 (file)
@@ -342,7 +342,7 @@ static void *make_internal_rpc_pipe_p(char *pipe_name,
        
        /* Store the session key and NT_TOKEN */
        if (vuser) {
-               memcpy(p->session_key, vuser->session_key, sizeof(p->session_key));
+               p->session_key = data_blob(vuser->session_key.data, vuser->session_key.length);
                p->pipe_user.nt_user_token = dup_nt_token(vuser->nt_user_token);
        }
 
index 1cfa8b285381044fb7554abdcc4ac118e42aec68..1debf90d23d3cb822d32fe74f655f6b2d4a0d66d 100644 (file)
@@ -2953,7 +2953,13 @@ NTSTATUS _samr_set_userinfo(pipes_struct *p, SAMR_Q_SET_USERINFO *q_u, SAMR_R_SE
                        break;
 
                case 24:
-                       SamOEMhash(ctr->info.id24->pass, p->session_key, 516);
+                       if (p->session_key.length != 16) {
+                               /* we may have no session key at all, 
+                                  and we don't know how to do the SamOEMhash 
+                                  for length != 16 */
+                               return NT_STATUS_NO_USER_SESSION_KEY;
+                       }
+                       SamOEMhash(ctr->info.id24->pass, p->session_key.data, 516);
 
                        dump_data(100, (char *)ctr->info.id24->pass, 516);
 
@@ -2971,7 +2977,10 @@ NTSTATUS _samr_set_userinfo(pipes_struct *p, SAMR_Q_SET_USERINFO *q_u, SAMR_R_SE
                         * info level and W2K SP2 drops down to level 23... JRA.
                         */
 
-                       SamOEMhash(ctr->info.id25->pass, p->session_key, 532);
+                       if (p->session_key.length != 16) {
+                               return NT_STATUS_NO_USER_SESSION_KEY;
+                       }
+                       SamOEMhash(ctr->info.id25->pass, p->session_key.data, 532);
 
                        dump_data(100, (char *)ctr->info.id25->pass, 532);
 
@@ -2982,7 +2991,10 @@ NTSTATUS _samr_set_userinfo(pipes_struct *p, SAMR_Q_SET_USERINFO *q_u, SAMR_R_SE
                        return NT_STATUS_INVALID_INFO_CLASS;
 
                case 23:
-                       SamOEMhash(ctr->info.id23->pass, p->session_key, 516);
+                       if (p->session_key.length != 16) {
+                               return NT_STATUS_NO_USER_SESSION_KEY;
+                       }
+                       SamOEMhash(ctr->info.id23->pass, p->session_key.data, 516);
 
                        dump_data(100, (char *)ctr->info.id23->pass, 516);
 
index 958ed663e672008ffa2bed169c4c46bbe15f4aa0..494d9ecd4396582705a6076e73131f6912dcca5f 100644 (file)
@@ -77,6 +77,8 @@ void invalidate_vuid(uint16 vuid)
 
        free_server_info(&vuser->server_info);
 
+       data_blob_free(&vuser->session_key);
+
        DLIST_REMOVE(validated_users, vuser);
 
        /* clear the vuid from the 'cache' on each connection, and
@@ -109,25 +111,36 @@ void invalidate_all_vuids(void)
  *  @param server_info The token returned from the authentication process. 
  *   (now 'owned' by register_vuid)
  *
+ *  @param session_key The User session key for the login session (now also 'owned' by register_vuid)
+ *
+ *  @param respose_blob The NT challenge-response, if available.  (May be freed after this call)
+ *
+ *  @param smb_name The untranslated name of the user
+ *
  *  @return Newly allocated vuid, biased by an offset. (This allows us to
  *   tell random client vuid's (normally zero) from valid vuids.)
  *
  */
 
-int register_vuid(auth_serversupplied_info *server_info, DATA_BLOB response_blob, const char *smb_name)
+int register_vuid(auth_serversupplied_info *server_info, DATA_BLOB session_key, DATA_BLOB response_blob, const char *smb_name)
 {
        user_struct *vuser = NULL;
 
        /* Ensure no vuid gets registered in share level security. */
-       if(lp_security() == SEC_SHARE)
+       if(lp_security() == SEC_SHARE) {
+               data_blob_free(&session_key);
                return UID_FIELD_INVALID;
+       }
 
        /* Limit allowed vuids to 16bits - VUID_OFFSET. */
-       if (num_validated_vuids >= 0xFFFF-VUID_OFFSET)
+       if (num_validated_vuids >= 0xFFFF-VUID_OFFSET) {
+               data_blob_free(&session_key);
                return UID_FIELD_INVALID;
+       }
 
        if((vuser = (user_struct *)malloc( sizeof(user_struct) )) == NULL) {
                DEBUG(0,("Failed to malloc users struct!\n"));
+               data_blob_free(&session_key);
                return UID_FIELD_INVALID;
        }
 
@@ -156,6 +169,7 @@ int register_vuid(auth_serversupplied_info *server_info, DATA_BLOB response_blob
        if (vuser->n_groups) {
                if (!(vuser->groups = memdup(server_info->groups, sizeof(gid_t) * vuser->n_groups))) {
                        DEBUG(0,("register_vuid: failed to memdup vuser->groups\n"));
+                       data_blob_free(&session_key);
                        free(vuser);
                        free_server_info(&server_info);
                        return UID_FIELD_INVALID;
@@ -197,7 +211,7 @@ int register_vuid(auth_serversupplied_info *server_info, DATA_BLOB response_blob
                }
        }
 
-       memcpy(vuser->session_key, server_info->session_key, sizeof(vuser->session_key));
+       vuser->session_key = session_key;
 
        DEBUG(10,("register_vuid: (%u,%u) %s %s %s guest=%d\n", 
                  (unsigned int)vuser->uid, 
@@ -211,6 +225,7 @@ int register_vuid(auth_serversupplied_info *server_info, DATA_BLOB response_blob
        } else {
                DEBUG(1, ("server_info does not contain a user_token - cannot continue\n"));
                free_server_info(&server_info);
+               data_blob_free(&session_key);
                SAFE_FREE(vuser->homedir);
                SAFE_FREE(vuser->unix_homedir);
                SAFE_FREE(vuser->logon_script);
index 314ffbb4a9b9a58819dfebb67e38afb8d270a78b..64c25db2ab0ea6f409b334736cc5ba6cd6e3119b 100644 (file)
@@ -149,7 +149,7 @@ static int reply_spnego_kerberos(connection_struct *conn,
        DATA_BLOB auth_data;
        DATA_BLOB ap_rep, ap_rep_wrapped, response;
        auth_serversupplied_info *server_info = NULL;
-       uint8 session_key[16];
+       DATA_BLOB session_key;
        uint8 tok_id[2];
        BOOL foreign = False;
        DATA_BLOB nullblob = data_blob(NULL, 0);
@@ -164,7 +164,7 @@ static int reply_spnego_kerberos(connection_struct *conn,
                return ERROR_NT(NT_STATUS_LOGON_FAILURE);
        }
 
-       ret = ads_verify_ticket(lp_realm(), &ticket, &client, &auth_data, &ap_rep, session_key);
+       ret = ads_verify_ticket(lp_realm(), &ticket, &client, &auth_data, &ap_rep, &session_key);
 
        data_blob_free(&ticket);
 
@@ -223,11 +223,8 @@ static int reply_spnego_kerberos(connection_struct *conn,
                return ERROR_NT(ret);
        }
 
-       /* Copy out the session key from the AP_REQ. */
-       memcpy(server_info->session_key, session_key, sizeof(session_key));
-
        /* register_vuid keeps the server info */
-       sess_vuid = register_vuid(server_info, nullblob, user);
+       sess_vuid = register_vuid(server_info, session_key, nullblob, user);
 
        free(user);
 
@@ -297,9 +294,10 @@ static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *out
        if (NT_STATUS_IS_OK(nt_status)) {
                int sess_vuid;
                DATA_BLOB nullblob = data_blob(NULL, 0);
+               DATA_BLOB session_key = data_blob((*auth_ntlmssp_state)->ntlmssp_state->session_key.data, (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
 
                /* register_vuid keeps the server info */
-               sess_vuid = register_vuid(server_info, nullblob, (*auth_ntlmssp_state)->ntlmssp_state->user);
+               sess_vuid = register_vuid(server_info, session_key, nullblob, (*auth_ntlmssp_state)->ntlmssp_state->user);
                (*auth_ntlmssp_state)->server_info = NULL;
 
                if (sess_vuid == -1) {
@@ -566,6 +564,8 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
        NTSTATUS nt_status;
 
        BOOL doencrypt = global_encrypted_passwords_negotiated;
+
+       DATA_BLOB session_key;
        
        START_PROFILE(SMBsesssetupX);
 
@@ -766,18 +766,28 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
 
        free_user_info(&user_info);
        
-       data_blob_free(&lm_resp);
-       data_blob_clear_free(&plaintext_password);
-       
        if (!NT_STATUS_IS_OK(nt_status)) {
                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));
        }
 
+       if (server_info->nt_session_key.data) {
+               session_key = data_blob(server_info->nt_session_key.data, server_info->nt_session_key.length);
+       } else if (server_info->lm_session_key.length >= 8 && lm_resp.length == 24) {
+               session_key = data_blob(NULL, 16);
+               SMBsesskeygen_lmv1(server_info->lm_session_key.data, lm_resp.data, 
+                                  session_key.data);
+       }
+
+       data_blob_free(&lm_resp);
+       data_blob_clear_free(&plaintext_password);
+       
        /* it's ok - setup a reply */
        set_message(outbuf,3,0,True);
        if (Protocol >= PROTOCOL_NT1) {
@@ -795,7 +805,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
           to a uid can get through without a password, on the same VC */
 
        /* register_vuid keeps the server info */
-       sess_vuid = register_vuid(server_info, nt_resp, sub_user);
+       sess_vuid = register_vuid(server_info, session_key, nt_resp, sub_user);
        data_blob_free(&nt_resp);
 
        if (sess_vuid == -1) {
index 13b9550347db7ce97269d1ae02f18e555a8a3fe0..4461f163dd5d01765e1a1a63e50f3801ea5da569 100644 (file)
 
 #define SQUID_BUFFER_SIZE 2010
 
-enum squid_mode {
+enum stdio_helper_mode {
        SQUID_2_4_BASIC,
        SQUID_2_5_BASIC,
        SQUID_2_5_NTLMSSP,
        GSS_SPNEGO,
-       GSS_SPNEGO_CLIENT
+       GSS_SPNEGO_CLIENT,
+       NUM_HELPER_MODES
+};
+
+typedef void (*stdio_helper_function)(enum stdio_helper_mode stdio_helper_mode, 
+                                    char *buf, int length);
+
+static void manage_squid_basic_request (enum stdio_helper_mode stdio_helper_mode, 
+                                       char *buf, int length);
+
+static void manage_squid_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode, 
+                                         char *buf, int length);
+
+static void manage_gss_spnego_request (enum stdio_helper_mode stdio_helper_mode, 
+                                      char *buf, int length);
+
+static void manage_gss_spnego_client_request (enum stdio_helper_mode stdio_helper_mode, 
+                                             char *buf, int length);
+
+static const struct {
+       enum stdio_helper_mode mode;
+       const char *name;
+       stdio_helper_function fn;
+} stdio_helper_protocols[] = {
+       { SQUID_2_4_BASIC, "squid-2.4-basic", manage_squid_basic_request},
+       { SQUID_2_5_BASIC, "squid-2.5-basic", manage_squid_basic_request},
+       { SQUID_2_5_NTLMSSP, "squid-2.5-ntlmssp", manage_squid_ntlmssp_request},
+       { GSS_SPNEGO, "gss-spnego", manage_gss_spnego_request},
+       { GSS_SPNEGO_CLIENT, "gss-spnego-client", manage_gss_spnego_client_request},
+       { NUM_HELPER_MODES, NULL, NULL}
 };
-       
 
 extern int winbindd_fd;
 
@@ -96,7 +124,7 @@ static const char *get_winbind_domain(void)
 
        if (winbindd_request(WINBINDD_DOMAIN_NAME, NULL, &response) !=
            NSS_STATUS_SUCCESS) {
-               d_printf("could not obtain winbind domain name!\n");
+               DEBUG(0, ("could not obtain winbind domain name!\n"));
                return NULL;
        }
 
@@ -122,7 +150,7 @@ static const char *get_winbind_netbios_name(void)
 
        if (winbindd_request(WINBINDD_NETBIOS_NAME, NULL, &response) !=
            NSS_STATUS_SUCCESS) {
-               d_printf("could not obtain winbind netbios name!\n");
+               DEBUG(0, ("could not obtain winbind netbios name!\n"));
                return NULL;
        }
 
@@ -264,20 +292,42 @@ static NTSTATUS contact_winbind_auth_crap(const char *username,
        return nt_status;
 }
                                   
-static NTSTATUS winbind_pw_check(struct ntlmssp_state *ntlmssp_state) 
+static NTSTATUS winbind_pw_check(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *nt_session_key, DATA_BLOB *lm_session_key
 {
-       return contact_winbind_auth_crap(ntlmssp_state->user, ntlmssp_state->domain,
-                                        ntlmssp_state->workstation,
-                                        &ntlmssp_state->chal,
-                                        &ntlmssp_state->lm_resp,
-                                        &ntlmssp_state->nt_resp, 
-                                        0,
-                                        NULL, 
-                                        NULL, 
-                                        NULL);
+       static const char zeros[16];
+       NTSTATUS nt_status;
+       char *error_string;
+       uint8 lm_key[8]; 
+       uint8 nt_key[16]; 
+       
+       nt_status = contact_winbind_auth_crap(ntlmssp_state->user, ntlmssp_state->domain,
+                                             ntlmssp_state->workstation,
+                                             &ntlmssp_state->chal,
+                                             &ntlmssp_state->lm_resp,
+                                             &ntlmssp_state->nt_resp, 
+                                             WBFLAG_PAM_LMKEY | WBFLAG_PAM_NTKEY,
+                                             lm_key, nt_key, 
+                                             &error_string);
+
+       if (NT_STATUS_IS_OK(nt_status)) {
+               if (memcmp(lm_key, zeros, 8) != 0) {
+                       *lm_session_key = data_blob(NULL, 16);
+                       memcpy(lm_session_key->data, lm_key, 8);
+                       memset(lm_session_key->data+8, '\0', 8);
+               }
+               
+               if (memcmp(nt_key, zeros, 16) != 0) {
+                       *nt_session_key = data_blob(nt_key, 16);
+               }
+       } else {
+               DEBUG(NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED) ? 0 : 3, 
+                     ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n", 
+                      ntlmssp_state->domain, ntlmssp_state->user, ntlmssp_state->workstation, error_string ? error_string : "unknown error (NULL)"));
+       }
+       return nt_status;
 }
 
-static void manage_squid_ntlmssp_request(enum squid_mode squid_mode, 
+static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode, 
                                         char *buf, int length) 
 {
        static NTLMSSP_STATE *ntlmssp_state = NULL;
@@ -295,7 +345,7 @@ static void manage_squid_ntlmssp_request(enum squid_mode squid_mode,
        } else if (strcmp(buf, "YR") == 0) {
                request = data_blob(NULL, 0);
                if (ntlmssp_state)
-                       ntlmssp_server_end(&ntlmssp_state);
+                       ntlmssp_end(&ntlmssp_state);
        } else {
                DEBUG(1, ("NTLMSSP query [%s] invalid", buf));
                x_fprintf(x_stdout, "BH\n");
@@ -312,7 +362,7 @@ static void manage_squid_ntlmssp_request(enum squid_mode squid_mode,
        DEBUG(10, ("got NTLMSSP packet:\n"));
        dump_data(10, (const char *)request.data, request.length);
 
-       nt_status = ntlmssp_server_update(ntlmssp_state, request, &reply);
+       nt_status = ntlmssp_update(ntlmssp_state, request, &reply);
        
        if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
                char *reply_base64 = base64_encode_data_blob(reply);
@@ -320,6 +370,9 @@ static void manage_squid_ntlmssp_request(enum squid_mode squid_mode,
                SAFE_FREE(reply_base64);
                data_blob_free(&reply);
                DEBUG(10, ("NTLMSSP challenge\n"));
+       } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) {
+               x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
+               DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status)));
        } else if (!NT_STATUS_IS_OK(nt_status)) {
                x_fprintf(x_stdout, "NA %s\n", nt_errstr(nt_status));
                DEBUG(10, ("NTLMSSP %s\n", nt_errstr(nt_status)));
@@ -331,7 +384,7 @@ static void manage_squid_ntlmssp_request(enum squid_mode squid_mode,
        data_blob_free(&request);
 }
 
-static void manage_squid_basic_request(enum squid_mode squid_mode, 
+static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode, 
                                       char *buf, int length) 
 {
        char *user, *pass;      
@@ -346,7 +399,7 @@ static void manage_squid_basic_request(enum squid_mode squid_mode,
        *pass='\0';
        pass++;
        
-       if (squid_mode == SQUID_2_5_BASIC) {
+       if (stdio_helper_mode == SQUID_2_5_BASIC) {
                rfc1738_unescape(user);
                rfc1738_unescape(pass);
        }
@@ -409,7 +462,7 @@ static void offer_gss_spnego_mechs(void) {
        return;
 }
 
-static void manage_gss_spnego_request(enum squid_mode squid_mode,
+static void manage_gss_spnego_request(enum stdio_helper_mode stdio_helper_mode, 
                                      char *buf, int length) 
 {
        static NTLMSSP_STATE *ntlmssp_state = NULL;
@@ -470,9 +523,7 @@ static void manage_gss_spnego_request(enum squid_mode squid_mode,
        if (request.type == SPNEGO_NEG_TOKEN_INIT) {
 
                /* Second request from Client. This is where the
-                  client offers its mechanism to use. We currently
-                  only support NTLMSSP, the decision for Kerberos
-                  would be taken here. */
+                  client offers its mechanism to use. */
 
                if ( (request.negTokenInit.mechTypes == NULL) ||
                     (request.negTokenInit.mechTypes[0] == NULL) ) {
@@ -493,7 +544,7 @@ static void manage_gss_spnego_request(enum squid_mode squid_mode,
                                DEBUG(1, ("Client wants a new NTLMSSP challenge, but "
                                          "already got one\n"));
                                x_fprintf(x_stdout, "BH\n");
-                               ntlmssp_server_end(&ntlmssp_state);
+                               ntlmssp_end(&ntlmssp_state);
                                return;
                        }
 
@@ -510,7 +561,7 @@ static void manage_gss_spnego_request(enum squid_mode squid_mode,
                        response.negTokenTarg.supportedMech = strdup(OID_NTLMSSP);
                        response.negTokenTarg.mechListMIC = data_blob(NULL, 0);
 
-                       status = ntlmssp_server_update(ntlmssp_state,
+                       status = ntlmssp_update(ntlmssp_state,
                                                       request.negTokenInit.mechToken,
                                                       &response.negTokenTarg.responseToken);
                }
@@ -521,7 +572,7 @@ static void manage_gss_spnego_request(enum squid_mode squid_mode,
                        char *principal;
                        DATA_BLOB auth_data;
                        DATA_BLOB ap_rep;
-                       uint8 session_key[16];
+                       DATA_BLOB session_key;
 
                        if ( request.negTokenInit.mechToken.data == NULL ) {
                                DEBUG(1, ("Client did not provide Kerberos data\n"));
@@ -537,7 +588,7 @@ static void manage_gss_spnego_request(enum squid_mode squid_mode,
                        status = ads_verify_ticket(lp_realm(),
                                                   &request.negTokenInit.mechToken,
                                                   &principal, &auth_data, &ap_rep,
-                                                  session_key);
+                                                  &session_key);
 
                        /* Now in "principal" we have the name we are
                            authenticated as. */
@@ -583,7 +634,7 @@ static void manage_gss_spnego_request(enum squid_mode squid_mode,
                        return;
                }
 
-               status = ntlmssp_server_update(ntlmssp_state,
+               status = ntlmssp_update(ntlmssp_state,
                                               request.negTokenTarg.responseToken,
                                               &response.negTokenTarg.responseToken);
 
@@ -594,7 +645,7 @@ static void manage_gss_spnego_request(enum squid_mode squid_mode,
                if (NT_STATUS_IS_OK(status)) {
                        user = strdup(ntlmssp_state->user);
                        domain = strdup(ntlmssp_state->domain);
-                       ntlmssp_server_end(&ntlmssp_state);
+                       ntlmssp_end(&ntlmssp_state);
                }
        }
 
@@ -638,7 +689,7 @@ static void manage_gss_spnego_request(enum squid_mode squid_mode,
        return;
 }
 
-static NTLMSSP_CLIENT_STATE *client_ntlmssp_state = NULL;
+static NTLMSSP_STATE *client_ntlmssp_state = NULL;
 
 static BOOL manage_client_ntlmssp_init(SPNEGO_DATA spnego)
 {
@@ -677,7 +728,7 @@ static BOOL manage_client_ntlmssp_init(SPNEGO_DATA spnego)
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(1, ("Could not start NTLMSSP client: %s\n",
                          nt_errstr(status)));
-               ntlmssp_client_end(&client_ntlmssp_state);
+               ntlmssp_end(&client_ntlmssp_state);
                return False;
        }
 
@@ -686,7 +737,7 @@ static BOOL manage_client_ntlmssp_init(SPNEGO_DATA spnego)
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(1, ("Could not set username: %s\n",
                          nt_errstr(status)));
-               ntlmssp_client_end(&client_ntlmssp_state);
+               ntlmssp_end(&client_ntlmssp_state);
                return False;
        }
 
@@ -695,7 +746,7 @@ static BOOL manage_client_ntlmssp_init(SPNEGO_DATA spnego)
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(1, ("Could not set domain: %s\n",
                          nt_errstr(status)));
-               ntlmssp_client_end(&client_ntlmssp_state);
+               ntlmssp_end(&client_ntlmssp_state);
                return False;
        }
 
@@ -704,7 +755,7 @@ static BOOL manage_client_ntlmssp_init(SPNEGO_DATA spnego)
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(1, ("Could not set password: %s\n",
                          nt_errstr(status)));
-               ntlmssp_client_end(&client_ntlmssp_state);
+               ntlmssp_end(&client_ntlmssp_state);
                return False;
        }
 
@@ -713,13 +764,13 @@ static BOOL manage_client_ntlmssp_init(SPNEGO_DATA spnego)
        spnego.negTokenInit.reqFlags = 0;
        spnego.negTokenInit.mechListMIC = null_blob;
 
-       status = ntlmssp_client_update(client_ntlmssp_state, null_blob,
+       status = ntlmssp_update(client_ntlmssp_state, null_blob,
                                       &spnego.negTokenInit.mechToken);
 
        if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
                DEBUG(1, ("Expected MORE_PROCESSING_REQUIRED, got: %s\n",
                          nt_errstr(status)));
-               ntlmssp_client_end(&client_ntlmssp_state);
+               ntlmssp_end(&client_ntlmssp_state);
                return False;
        }
 
@@ -746,23 +797,23 @@ static void manage_client_ntlmssp_targ(SPNEGO_DATA spnego)
        if (client_ntlmssp_state == NULL) {
                DEBUG(1, ("Got NTLMSSP tArg without a client state\n"));
                x_fprintf(x_stdout, "BH\n");
-               ntlmssp_client_end(&client_ntlmssp_state);
+               ntlmssp_end(&client_ntlmssp_state);
                return;
        }
 
        if (spnego.negTokenTarg.negResult == SPNEGO_REJECT) {
                x_fprintf(x_stdout, "NA\n");
-               ntlmssp_client_end(&client_ntlmssp_state);
+               ntlmssp_end(&client_ntlmssp_state);
                return;
        }
 
        if (spnego.negTokenTarg.negResult == SPNEGO_ACCEPT_COMPLETED) {
                x_fprintf(x_stdout, "AF\n");
-               ntlmssp_client_end(&client_ntlmssp_state);
+               ntlmssp_end(&client_ntlmssp_state);
                return;
        }
 
-       status = ntlmssp_client_update(client_ntlmssp_state,
+       status = ntlmssp_update(client_ntlmssp_state,
                                       spnego.negTokenTarg.responseToken,
                                       &request);
                
@@ -772,7 +823,7 @@ static void manage_client_ntlmssp_targ(SPNEGO_DATA spnego)
                          nt_errstr(status)));
                x_fprintf(x_stdout, "BH\n");
                data_blob_free(&request);
-               ntlmssp_client_end(&client_ntlmssp_state);
+               ntlmssp_end(&client_ntlmssp_state);
                return;
        }
 
@@ -798,7 +849,7 @@ static BOOL manage_client_krb5_init(SPNEGO_DATA spnego)
 {
        char *principal;
        DATA_BLOB tkt, to_server;
-       unsigned char session_key_krb5[16];
+       DATA_BLOB session_key_krb5;
        SPNEGO_DATA reply;
        char *reply_base64;
        
@@ -822,7 +873,7 @@ static BOOL manage_client_krb5_init(SPNEGO_DATA spnego)
               spnego.negTokenInit.mechListMIC.length);
        principal[spnego.negTokenInit.mechListMIC.length] = '\0';
 
-       tkt = cli_krb5_get_ticket(principal, 0, session_key_krb5);
+       tkt = cli_krb5_get_ticket(principal, 0, &session_key_krb5);
 
        if (tkt.data == NULL) {
 
@@ -845,9 +896,11 @@ static BOOL manage_client_krb5_init(SPNEGO_DATA spnego)
                        return True;
                }
 
-               tkt = cli_krb5_get_ticket(principal, 0, session_key_krb5);
+               tkt = cli_krb5_get_ticket(principal, 0, &session_key_krb5);
        }
 
+       data_blob_free(&session_key_krb5);
+
        ZERO_STRUCT(reply);
 
        reply.type = SPNEGO_NEG_TOKEN_INIT;
@@ -896,7 +949,7 @@ static void manage_client_krb5_targ(SPNEGO_DATA spnego)
 
 #endif
 
-static void manage_gss_spnego_client_request(enum squid_mode squid_mode,
+static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper_mode, 
                                             char *buf, int length) 
 {
        DATA_BLOB request;
@@ -1000,7 +1053,7 @@ static void manage_gss_spnego_client_request(enum squid_mode squid_mode,
                                x_fprintf(x_stdout, "BH\n");
                        }
 
-                       ntlmssp_client_end(&client_ntlmssp_state);
+                       ntlmssp_end(&client_ntlmssp_state);
                        goto out;
                }
 
@@ -1029,7 +1082,7 @@ static void manage_gss_spnego_client_request(enum squid_mode squid_mode,
        return;
 }
 
-static void manage_squid_request(enum squid_mode squid_mode
+static void manage_squid_request(enum stdio_helper_mode helper_mode, stdio_helper_function fn
 {
        char buf[SQUID_BUFFER_SIZE+1];
        int length;
@@ -1066,24 +1119,16 @@ static void manage_squid_request(enum squid_mode squid_mode)
                return;
        }
        
-       if (squid_mode == SQUID_2_5_BASIC || squid_mode == SQUID_2_4_BASIC) {
-               manage_squid_basic_request(squid_mode, buf, length);
-       } else if (squid_mode == SQUID_2_5_NTLMSSP) {
-               manage_squid_ntlmssp_request(squid_mode, buf, length);
-       } else if (squid_mode == GSS_SPNEGO) {
-               manage_gss_spnego_request(squid_mode, buf, length);
-       } else if (squid_mode == GSS_SPNEGO_CLIENT) {
-               manage_gss_spnego_client_request(squid_mode, buf, length);
-       }
+       fn(helper_mode, buf, length);
 }
 
 
-static void squid_stream(enum squid_mode squid_mode) {
+static void squid_stream(enum stdio_helper_mode stdio_mode, stdio_helper_function fn) {
        /* initialize FDescs */
        x_setbuf(x_stdout, NULL);
        x_setbuf(x_stderr, NULL);
        while(1) {
-               manage_squid_request(squid_mode);
+               manage_squid_request(stdio_mode, fn);
        }
 }
 
@@ -2019,20 +2064,15 @@ enum {
        }
 
        if (helper_protocol) {
-               if (strcmp(helper_protocol, "squid-2.5-ntlmssp")== 0) {
-                       squid_stream(SQUID_2_5_NTLMSSP);
-               } else if (strcmp(helper_protocol, "squid-2.5-basic")== 0) {
-                       squid_stream(SQUID_2_5_BASIC);
-               } else if (strcmp(helper_protocol, "squid-2.4-basic")== 0) {
-                       squid_stream(SQUID_2_4_BASIC);
-               } else if (strcmp(helper_protocol, "gss-spnego")== 0) {
-                       squid_stream(GSS_SPNEGO);
-               } else if (strcmp(helper_protocol, "gss-spnego-client") == 0) {
-                       squid_stream(GSS_SPNEGO_CLIENT);
-               } else {
-                       x_fprintf(x_stderr, "unknown helper protocol [%s]\n", helper_protocol);
-                       exit(1);
+               int i;
+               for (i=0; i<NUM_HELPER_MODES; i++) {
+                       if (strcmp(helper_protocol, stdio_helper_protocols[i].name) == 0) {
+                               squid_stream(stdio_helper_protocols[i].mode, stdio_helper_protocols[i].fn);
+                               exit(0);
+                       }
                }
+               x_fprintf(x_stderr, "unknown helper protocol [%s]\n", helper_protocol);
+               exit(1);
        }
 
        if (!opt_username) {