diff options
Diffstat (limited to 'source4')
-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; |