diff options
author | Andrew Bartlett <abartlet@samba.org> | 2005-06-17 13:12:13 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 13:18:23 -0500 |
commit | 5b19286df08d6cf10654d6e20c323ba44f7d2054 (patch) | |
tree | 922bdf3301089611449f501e83e3489881427021 | |
parent | a4bb5ae30c1abcf385f02493e778755b09710d95 (diff) | |
download | samba-5b19286df08d6cf10654d6e20c323ba44f7d2054.tar.gz samba-5b19286df08d6cf10654d6e20c323ba44f7d2054.tar.bz2 samba-5b19286df08d6cf10654d6e20c323ba44f7d2054.zip |
r7690: Move the NT hash generation into the credentials system, rather than
in all the callers. This also allows us to be more flexible in the
type of password we store.
Andrew Bartlett
(This used to be commit 00b8588c68526e1d86fda0bd81c0b86f690b62c3)
-rw-r--r-- | source4/auth/ntlmssp/ntlmssp_client.c | 43 | ||||
-rw-r--r-- | source4/include/credentials.h | 2 | ||||
-rw-r--r-- | source4/lib/credentials.c | 80 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc_schannel.c | 7 |
4 files changed, 96 insertions, 36 deletions
diff --git a/source4/auth/ntlmssp/ntlmssp_client.c b/source4/auth/ntlmssp/ntlmssp_client.c index 8bbeb74490..23fe8f5cc9 100644 --- a/source4/auth/ntlmssp/ntlmssp_client.c +++ b/source4/auth/ntlmssp/ntlmssp_client.c @@ -26,6 +26,7 @@ #include "auth/auth.h" #include "auth/ntlmssp/ntlmssp.h" #include "lib/crypto/crypto.h" +#include "librpc/gen_ndr/ndr_samr.h" /* for struct samrPassword */ /********************************************************************* Client side NTLMSSP @@ -101,6 +102,7 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security, DATA_BLOB encrypted_session_key = data_blob(NULL, 0); NTSTATUS nt_status; + const struct samr_Password *nt_hash; const char *user, *domain, *password; if (!msrpc_parse(out_mem_ctx, @@ -174,9 +176,10 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security, domain = cli_credentials_get_domain(gensec_security->credentials); } + nt_hash = cli_credentials_get_nt_hash(gensec_security->credentials, out_mem_ctx); password = cli_credentials_get_password(gensec_security->credentials); - if (!password) { + if (!nt_hash) { static const uint8_t zeros[16]; /* do nothing - blobs are zero length */ @@ -200,12 +203,12 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security, /* TODO: if the remote server is standalone, then we should replace 'domain' with the server name as supplied above */ - if (!SMBNTLMv2encrypt(user, - domain, - password, &challenge_blob, - &struct_blob, - &lm_response, &nt_response, - NULL, &session_key)) { + if (!SMBNTLMv2encrypt_hash(user, + domain, + nt_hash->hash, &challenge_blob, + &struct_blob, + &lm_response, &nt_response, + NULL, &session_key)) { data_blob_free(&challenge_blob); data_blob_free(&struct_blob); return NT_STATUS_NO_MEMORY; @@ -216,11 +219,9 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security, } else if (gensec_ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { struct MD5Context md5_session_nonce_ctx; - uint8_t nt_hash[16]; uint8_t session_nonce[16]; uint8_t session_nonce_hash[16]; uint8_t user_session_key[16]; - E_md4hash(password, nt_hash); lm_response = data_blob_talloc(gensec_ntlmssp_state, NULL, 24); generate_random_buffer(lm_response.data, 8); @@ -239,33 +240,31 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security, dump_data(5, session_nonce_hash, 8); nt_response = data_blob_talloc(gensec_ntlmssp_state, NULL, 24); - SMBNTencrypt(password, - session_nonce_hash, - nt_response.data); - + SMBOWFencrypt(nt_hash->hash, + session_nonce_hash, + nt_response.data); + session_key = data_blob_talloc(gensec_ntlmssp_state, NULL, 16); - SMBsesskeygen_ntv1(nt_hash, user_session_key); + SMBsesskeygen_ntv1(nt_hash->hash, user_session_key); hmac_md5(user_session_key, session_nonce, sizeof(session_nonce), session_key.data); dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length); /* LM Key is incompatible... */ gensec_ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; } else { - uint8_t nt_hash[16]; - if (gensec_ntlmssp_state->use_nt_response) { nt_response = data_blob_talloc(gensec_ntlmssp_state, NULL, 24); - SMBNTencrypt(password,challenge_blob.data, - nt_response.data); - E_md4hash(password, nt_hash); + SMBOWFencrypt(nt_hash->hash, challenge_blob.data, + nt_response.data); + session_key = data_blob_talloc(gensec_ntlmssp_state, NULL, 16); - SMBsesskeygen_ntv1(nt_hash, session_key.data); + SMBsesskeygen_ntv1(nt_hash->hash, session_key.data); dump_data_pw("NT session key:\n", session_key.data, session_key.length); } - /* lanman auth is insecure, it may be disabled */ - if (lp_client_lanman_auth()) { + /* lanman auth is insecure, it may be disabled. We may also not have a password */ + if (lp_client_lanman_auth() && password) { lm_response = data_blob_talloc(gensec_ntlmssp_state, NULL, 24); if (!SMBencrypt(password,challenge_blob.data, lm_response.data)) { diff --git a/source4/include/credentials.h b/source4/include/credentials.h index 309fff056e..511b775795 100644 --- a/source4/include/credentials.h +++ b/source4/include/credentials.h @@ -45,6 +45,8 @@ struct cli_credentials { const char *domain; const char *realm; + struct samr_Password *nt_hash; + const char *(*workstation_cb) (struct cli_credentials *); const char *(*password_cb) (struct cli_credentials *); const char *(*username_cb) (struct cli_credentials *); diff --git a/source4/lib/credentials.c b/source4/lib/credentials.c index 1dbb536f9e..aaaa2cf05d 100644 --- a/source4/lib/credentials.c +++ b/source4/lib/credentials.c @@ -24,6 +24,7 @@ #include "system/filesys.h" #include "include/secrets.h" #include "lib/ldb/include/ldb.h" +#include "librpc/gen_ndr/ndr_samr.h" /* for struct samrPassword */ /** * Create a new credentials structure @@ -101,6 +102,46 @@ BOOL cli_credentials_set_password(struct cli_credentials *cred, const char *val, if (obtained >= cred->password_obtained) { cred->password = talloc_strdup(cred, val); cred->password_obtained = obtained; + + cred->nt_hash = NULL; + return True; + } + + return False; +} + +/** + * Obtain the password for this credentials context. + * @param cred credentials context + * @retval If set, the cleartext password, otherwise NULL + */ +const struct samr_Password *cli_credentials_get_nt_hash(struct cli_credentials *cred, + TALLOC_CTX *mem_ctx) +{ + const char *password = cli_credentials_get_password(cred); + + if (password) { + struct samr_Password *nt_hash = talloc(mem_ctx, struct samr_Password); + if (!nt_hash) { + return NULL; + } + + E_md4hash(password, nt_hash->hash); + + return nt_hash; + } else { + return cred->nt_hash; + } +} + +BOOL cli_credentials_set_nt_hash(struct cli_credentials *cred, + const struct samr_Password *nt_hash, + enum credentials_obtained obtained) +{ + if (obtained >= cred->password_obtained) { + cli_credentials_set_password(cred, NULL, obtained); + cred->nt_hash = talloc(cred, struct samr_Password); + *cred->nt_hash = *nt_hash; return True; } @@ -462,6 +503,7 @@ NTSTATUS cli_credentials_set_machine_account(struct cli_credentials *cred) "flatname", "realm", "secureChannelType", + "ntPwdHash", NULL }; @@ -500,14 +542,9 @@ NTSTATUS cli_credentials_set_machine_account(struct cli_credentials *cred) } password = ldb_msg_find_string(msgs[0], "secret", NULL); - if (!password) { - DEBUG(1, ("Could not find 'secret' in join record to domain: %s\n", - cli_credentials_get_domain(cred))); - talloc_free(mem_ctx); - return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; - } - + machine_account = ldb_msg_find_string(msgs[0], "samAccountName", NULL); + if (!machine_account) { DEBUG(1, ("Could not find 'samAccountName' in join record to domain: %s\n", cli_credentials_get_domain(cred))); @@ -516,14 +553,32 @@ NTSTATUS cli_credentials_set_machine_account(struct cli_credentials *cred) } sct = ldb_msg_find_int(msgs[0], "secureChannelType", 0); - if (sct) { - cli_credentials_set_secure_channel_type(cred, sct); - } else { + if (!sct) { DEBUG(1, ("Domain join for acocunt %s did not have a secureChannelType set!\n", machine_account)); return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; } + if (!password) { + const struct ldb_val *nt_password_hash = ldb_msg_find_ldb_val(msgs[0], "ntPwdHash"); + struct samr_Password hash; + ZERO_STRUCT(hash); + if (nt_password_hash) { + memcpy(hash.hash, nt_password_hash->data, + MIN(nt_password_hash->length, sizeof(hash.hash))); + + cli_credentials_set_nt_hash(cred, &hash, CRED_SPECIFIED); + } else { + + DEBUG(1, ("Could not find 'secret' in join record to domain: %s\n", + cli_credentials_get_domain(cred))); + talloc_free(mem_ctx); + return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + } + } + + cli_credentials_set_secure_channel_type(cred, sct); + domain = ldb_msg_find_string(msgs[0], "flatname", NULL); if (domain) { cli_credentials_set_domain(cred, domain, CRED_SPECIFIED); @@ -535,7 +590,10 @@ NTSTATUS cli_credentials_set_machine_account(struct cli_credentials *cred) } cli_credentials_set_username(cred, machine_account, CRED_SPECIFIED); - cli_credentials_set_password(cred, password, CRED_SPECIFIED); + if (password) { + cli_credentials_set_password(cred, password, CRED_SPECIFIED); + } + talloc_free(mem_ctx); return NT_STATUS_OK; diff --git a/source4/librpc/rpc/dcerpc_schannel.c b/source4/librpc/rpc/dcerpc_schannel.c index 1b83b2ec0b..ae4ce94269 100644 --- a/source4/librpc/rpc/dcerpc_schannel.c +++ b/source4/librpc/rpc/dcerpc_schannel.c @@ -38,7 +38,7 @@ static NTSTATUS dcerpc_schannel_key(TALLOC_CTX *tmp_ctx, struct netr_ServerReqChallenge r; struct netr_ServerAuthenticate2 a; struct netr_Credential credentials1, credentials2, credentials3; - struct samr_Password mach_pwd; + const struct samr_Password *mach_pwd; uint32_t negotiate_flags; struct creds_CredentialState *creds; creds = talloc(tmp_ctx, struct creds_CredentialState); @@ -103,9 +103,10 @@ static NTSTATUS dcerpc_schannel_key(TALLOC_CTX *tmp_ctx, /* step 3 - authenticate on the netlogon pipe */ - E_md4hash(cli_credentials_get_password(credentials), mach_pwd.hash); + mach_pwd = cli_credentials_get_nt_hash(credentials, tmp_ctx); + creds_client_init(creds, &credentials1, &credentials2, - &mach_pwd, &credentials3, + mach_pwd, &credentials3, negotiate_flags); a.in.server_name = r.in.server_name; |