summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/auth/ntlmssp/ntlmssp_client.c43
-rw-r--r--source4/include/credentials.h2
-rw-r--r--source4/lib/credentials.c80
-rw-r--r--source4/librpc/rpc/dcerpc_schannel.c7
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;