summaryrefslogtreecommitdiff
path: root/source4/auth
diff options
context:
space:
mode:
Diffstat (limited to 'source4/auth')
-rw-r--r--source4/auth/credentials/config.mk3
-rw-r--r--source4/auth/credentials/credentials.c13
-rw-r--r--source4/auth/credentials/credentials_ntlm.c191
-rw-r--r--source4/auth/ntlmssp/ntlmssp_client.c175
4 files changed, 243 insertions, 139 deletions
diff --git a/source4/auth/credentials/config.mk b/source4/auth/credentials/config.mk
index 65505d87bf..74f3f07bef 100644
--- a/source4/auth/credentials/config.mk
+++ b/source4/auth/credentials/config.mk
@@ -3,7 +3,8 @@
[SUBSYSTEM::CREDENTIALS]
INIT_OBJ_FILES = auth/credentials/credentials.o
ADD_OBJ_FILES = auth/credentials/credentials_files.o \
- auth/credentials/credentials_krb5.o
+ auth/credentials/credentials_krb5.o \
+ auth/credentials/credentials_ntlm.o
REQUIRED_SUBSYSTEMS = \
HEIMDAL
# End SUBSYSTEM GENSEC
diff --git a/source4/auth/credentials/credentials.c b/source4/auth/credentials/credentials.c
index 11b413b1c6..38c9ba30e8 100644
--- a/source4/auth/credentials/credentials.c
+++ b/source4/auth/credentials/credentials.c
@@ -293,19 +293,6 @@ BOOL cli_credentials_set_domain_callback(struct cli_credentials *cred,
return False;
}
-void cli_credentials_get_ntlm_username_domain(struct cli_credentials *cred, TALLOC_CTX *mem_ctx,
- const char **username,
- const char **domain)
-{
- if (cred->principal_obtained > cred->username_obtained) {
- *domain = talloc_strdup(mem_ctx, "");
- *username = cli_credentials_get_principal(cred, mem_ctx);
- } else {
- *domain = cli_credentials_get_domain(cred);
- *username = cli_credentials_get_username(cred);
- }
-}
-
/**
* Obtain the Kerberos realm for this credentials context.
* @param cred credentials context
diff --git a/source4/auth/credentials/credentials_ntlm.c b/source4/auth/credentials/credentials_ntlm.c
new file mode 100644
index 0000000000..0dfd106a3c
--- /dev/null
+++ b/source4/auth/credentials/credentials_ntlm.c
@@ -0,0 +1,191 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ User credentials handling
+
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2001-2005
+ Copyright (C) Stefan Metzmacher 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "lib/ldb/include/ldb.h"
+#include "librpc/gen_ndr/ndr_samr.h" /* for struct samrPassword */
+#include "lib/crypto/crypto.h"
+
+void cli_credentials_get_ntlm_username_domain(struct cli_credentials *cred, TALLOC_CTX *mem_ctx,
+ const char **username,
+ const char **domain)
+{
+ if (cred->principal_obtained > cred->username_obtained) {
+ *domain = talloc_strdup(mem_ctx, "");
+ *username = cli_credentials_get_principal(cred, mem_ctx);
+ } else {
+ *domain = cli_credentials_get_domain(cred);
+ *username = cli_credentials_get_username(cred);
+ }
+}
+
+NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred, TALLOC_CTX *mem_ctx,
+ int *flags,
+ DATA_BLOB challenge, DATA_BLOB target_info,
+ DATA_BLOB *_lm_response, DATA_BLOB *_nt_response,
+ DATA_BLOB *_lm_session_key, DATA_BLOB *_session_key)
+{
+ const char *user, *domain;
+ DATA_BLOB lm_response, nt_response;
+ DATA_BLOB lm_session_key, session_key;
+ const struct samr_Password *nt_hash;
+ lm_session_key = data_blob(NULL, 0);
+
+ nt_hash = cli_credentials_get_nt_hash(cred, mem_ctx);
+
+ cli_credentials_get_ntlm_username_domain(cred, mem_ctx, &user, &domain);
+
+ if (!nt_hash) {
+ static const uint8_t zeros[16];
+ /* do nothing - blobs are zero length */
+
+ /* session key is all zeros */
+ session_key = data_blob_talloc(mem_ctx, zeros, 16);
+ lm_session_key = data_blob_talloc(mem_ctx, zeros, 16);
+
+ lm_response = data_blob(NULL, 0);
+ nt_response = data_blob(NULL, 0);
+
+ /* not doing NLTM2 without a password */
+ *flags &= ~CLI_CRED_NTLM2;
+ } else if (*flags & CLI_CRED_NTLMv2_AUTH) {
+
+ if (!target_info.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;
+ }
+
+ /* TODO: if the remote server is standalone, then we should replace 'domain'
+ with the server name as supplied above */
+
+ if (!SMBNTLMv2encrypt_hash(mem_ctx,
+ user,
+ domain,
+ nt_hash->hash, &challenge,
+ &target_info,
+ &lm_response, &nt_response,
+ NULL, &session_key)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* LM Key is incompatible... */
+ *flags &= ~CLI_CRED_LANMAN_AUTH;
+ } else if (*flags & CLI_CRED_NTLM2) {
+ struct MD5Context md5_session_nonce_ctx;
+ uint8_t session_nonce[16];
+ uint8_t session_nonce_hash[16];
+ uint8_t user_session_key[16];
+
+ lm_response = data_blob_talloc(mem_ctx, NULL, 24);
+ generate_random_buffer(lm_response.data, 8);
+ memset(lm_response.data+8, 0, 16);
+
+ memcpy(session_nonce, challenge.data, 8);
+ memcpy(&session_nonce[8], lm_response.data, 8);
+
+ MD5Init(&md5_session_nonce_ctx);
+ MD5Update(&md5_session_nonce_ctx, challenge.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_talloc(mem_ctx, NULL, 24);
+ SMBOWFencrypt(nt_hash->hash,
+ session_nonce_hash,
+ nt_response.data);
+
+ session_key = data_blob_talloc(mem_ctx, NULL, 16);
+
+ 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... */
+ *flags &= ~CLI_CRED_LANMAN_AUTH;
+ } else {
+ nt_response = data_blob_talloc(mem_ctx, NULL, 24);
+ SMBOWFencrypt(nt_hash->hash, challenge.data,
+ nt_response.data);
+
+ session_key = data_blob_talloc(mem_ctx, NULL, 16);
+ 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.
+ We may also not have a password */
+ if (*flags & CLI_CRED_LANMAN_AUTH) {
+ const char *password;
+ password = cli_credentials_get_password(cred);
+ if (!password) {
+ lm_response = nt_response;
+ } else {
+ uint8_t lm_hash[16];
+ lm_response = data_blob_talloc(mem_ctx, NULL, 24);
+ if (!SMBencrypt(password,challenge.data,
+ lm_response.data)) {
+ /* If the LM password was too long (and therefore the LM hash being
+ of the first 14 chars only), don't send it.
+
+ We don't have any better options but to send the NT response
+ */
+ data_blob_free(&lm_response);
+ lm_response = nt_response;
+ /* LM Key is incompatible with 'long' passwords */
+ *flags &= ~CLI_CRED_LANMAN_AUTH;
+ } else {
+ E_deshash(password, lm_hash);
+ lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
+ memcpy(lm_session_key.data, lm_hash, 8);
+ memset(&lm_session_key.data[8], '\0', 8);
+
+ if (!(*flags & CLI_CRED_NTLM_AUTH)) {
+ session_key = lm_session_key;
+ }
+ }
+ }
+ } else {
+ /* LM Key is incompatible... */
+ lm_response = nt_response;
+ *flags &= ~CLI_CRED_LANMAN_AUTH;
+ }
+ }
+ if (_lm_response) {
+ *_lm_response = lm_response;
+ }
+ if (_nt_response) {
+ *_nt_response = nt_response;
+ }
+ if (_lm_session_key) {
+ *_lm_session_key = lm_session_key;
+ }
+ if (_session_key) {
+ *_session_key = session_key;
+ }
+ return NT_STATUS_OK;
+}
+
diff --git a/source4/auth/ntlmssp/ntlmssp_client.c b/source4/auth/ntlmssp/ntlmssp_client.c
index 7801e0208d..3f781825e3 100644
--- a/source4/auth/ntlmssp/ntlmssp_client.c
+++ b/source4/auth/ntlmssp/ntlmssp_client.c
@@ -26,7 +26,6 @@
#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
@@ -90,22 +89,25 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
uint32_t chal_flags, ntlmssp_command, unkn1, unkn2;
DATA_BLOB server_domain_blob;
DATA_BLOB challenge_blob;
- DATA_BLOB struct_blob = data_blob(NULL, 0);
+ DATA_BLOB target_info = data_blob(NULL, 0);
char *server_domain;
const char *chal_parse_string;
const char *auth_gen_string;
- uint8_t lm_hash[16];
DATA_BLOB lm_response = data_blob(NULL, 0);
DATA_BLOB nt_response = data_blob(NULL, 0);
DATA_BLOB session_key = data_blob(NULL, 0);
DATA_BLOB lm_session_key = data_blob(NULL, 0);
DATA_BLOB encrypted_session_key = data_blob(NULL, 0);
NTSTATUS nt_status;
+ int flags = 0;
+ const char *user, *domain;
- const struct samr_Password *nt_hash;
- const char *user, *domain, *password;
+ TALLOC_CTX *mem_ctx = talloc_new(out_mem_ctx);
+ if (!mem_ctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
- if (!msrpc_parse(out_mem_ctx,
+ if (!msrpc_parse(mem_ctx,
&in, "CdBd",
"NTLMSSP",
&ntlmssp_command,
@@ -113,6 +115,7 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
&chal_flags)) {
DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#1)\n"));
dump_data(2, in.data, in.length);
+ talloc_free(mem_ctx);
return NT_STATUS_INVALID_PARAMETER;
}
@@ -144,7 +147,7 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
DEBUG(3, ("NTLMSSP: Set final flags:\n"));
debug_ntlmssp_flags(gensec_ntlmssp_state->neg_flags);
- if (!msrpc_parse(out_mem_ctx,
+ if (!msrpc_parse(mem_ctx,
&in, chal_parse_string,
"NTLMSSP",
&ntlmssp_command,
@@ -152,143 +155,58 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
&chal_flags,
&challenge_blob, 8,
&unkn1, &unkn2,
- &struct_blob)) {
+ &target_info)) {
DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#2)\n"));
dump_data(2, in.data, in.length);
+ talloc_free(mem_ctx);
return NT_STATUS_INVALID_PARAMETER;
}
gensec_ntlmssp_state->server_domain = server_domain;
if (challenge_blob.length != 8) {
+ talloc_free(mem_ctx);
return NT_STATUS_INVALID_PARAMETER;
}
- cli_credentials_get_ntlm_username_domain(gensec_security->credentials, out_mem_ctx,
+ cli_credentials_get_ntlm_username_domain(gensec_security->credentials, mem_ctx,
&user, &domain);
- nt_hash = cli_credentials_get_nt_hash(gensec_security->credentials, out_mem_ctx);
-
- if (!nt_hash) {
- static const uint8_t zeros[16];
- /* do nothing - blobs are zero length */
-
- /* session key is all zeros */
- session_key = data_blob_talloc(gensec_ntlmssp_state, zeros, 16);
- lm_session_key = data_blob_talloc(gensec_ntlmssp_state, zeros, 16);
-
- lm_response = data_blob(NULL, 0);
- nt_response = data_blob(NULL, 0);
-
- /* not doing NLTM2 without a password */
- gensec_ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
- } else if (gensec_ntlmssp_state->use_ntlmv2) {
-
- 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;
- }
-
- /* TODO: if the remote server is standalone, then we should replace 'domain'
- with the server name as supplied above */
-
- if (!SMBNTLMv2encrypt_hash(gensec_ntlmssp_state,
- 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;
- }
+ if (gensec_ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+ flags |= CLI_CRED_NTLM2;
+ }
+ if (gensec_ntlmssp_state->use_ntlmv2) {
+ flags |= CLI_CRED_NTLMv2_AUTH;
+ }
+ if (gensec_ntlmssp_state->use_nt_response) {
+ flags |= CLI_CRED_NTLM_AUTH;
+ }
+ if (lp_client_lanman_auth()) {
+ flags |= CLI_CRED_LANMAN_AUTH;
+ }
- /* LM Key is incompatible... */
- gensec_ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
+ nt_status = cli_credentials_get_ntlm_response(gensec_security->credentials, mem_ctx,
+ &flags, challenge_blob, target_info,
+ &lm_response, &nt_response,
+ &lm_session_key, &session_key);
- } else if (gensec_ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
- struct MD5Context md5_session_nonce_ctx;
- uint8_t session_nonce[16];
- uint8_t session_nonce_hash[16];
- uint8_t user_session_key[16];
-
- lm_response = data_blob_talloc(gensec_ntlmssp_state, NULL, 24);
- generate_random_buffer(lm_response.data, 8);
- memset(lm_response.data+8, 0, 16);
-
- memcpy(session_nonce, challenge_blob.data, 8);
- memcpy(&session_nonce[8], lm_response.data, 8);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
- MD5Init(&md5_session_nonce_ctx);
- 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_talloc(gensec_ntlmssp_state, NULL, 24);
- SMBOWFencrypt(nt_hash->hash,
- session_nonce_hash,
- nt_response.data);
-
- session_key = data_blob_talloc(gensec_ntlmssp_state, NULL, 16);
-
- 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);
-
+ if (!(flags & CLI_CRED_LANMAN_AUTH)) {
/* LM Key is incompatible... */
gensec_ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
- } else {
- if (gensec_ntlmssp_state->use_nt_response) {
- nt_response = data_blob_talloc(gensec_ntlmssp_state, NULL, 24);
- SMBOWFencrypt(nt_hash->hash, challenge_blob.data,
- nt_response.data);
-
- session_key = data_blob_talloc(gensec_ntlmssp_state, NULL, 16);
- 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. We may also not have a password */
- if (lp_client_lanman_auth()) {
- password = cli_credentials_get_password(gensec_security->credentials);
- if (!password) {
- lm_response = nt_response;
- } else {
- lm_response = data_blob_talloc(gensec_ntlmssp_state, NULL, 24);
- if (!SMBencrypt(password,challenge_blob.data,
- lm_response.data)) {
- /* If the LM password was too long (and therefore the LM hash being
- of the first 14 chars only), don't send it */
- data_blob_free(&lm_response);
-
- /* LM Key is incompatible with 'long' passwords */
- gensec_ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
- } else {
- E_deshash(password, lm_hash);
- lm_session_key = data_blob_talloc(gensec_ntlmssp_state, NULL, 16);
- memcpy(lm_session_key.data, lm_hash, 8);
- memset(&lm_session_key.data[8], '\0', 8);
-
- if (!gensec_ntlmssp_state->use_nt_response) {
- session_key = lm_session_key;
- }
- }
- }
- } else {
- /* LM Key is incompatible... */
- gensec_ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
- }
+ if (!(flags & CLI_CRED_NTLM2)) {
+ /* NTLM2 is incompatible... */
+ gensec_ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
}
if ((gensec_ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY)
&& lp_client_lanman_auth() && lm_session_key.length == 16) {
- DATA_BLOB new_session_key = data_blob_talloc(gensec_ntlmssp_state, NULL, 16);
+ DATA_BLOB new_session_key = data_blob_talloc(mem_ctx, NULL, 16);
if (lm_response.length == 24) {
SMBsesskeygen_lm_sess_key(lm_session_key.data, lm_response.data,
new_session_key.data);
@@ -318,11 +236,11 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
dump_data_pw("KEY_EXCH session key (enc):\n", encrypted_session_key.data, encrypted_session_key.length);
/* Mark the new session key as the 'real' session key */
- session_key = data_blob_talloc(gensec_ntlmssp_state, client_session_key, sizeof(client_session_key));
+ session_key = data_blob_talloc(mem_ctx, client_session_key, sizeof(client_session_key));
}
/* this generates the actual auth packet */
- if (!msrpc_gen(out_mem_ctx,
+ if (!msrpc_gen(mem_ctx,
out, auth_gen_string,
"NTLMSSP",
NTLMSSP_AUTH,
@@ -333,18 +251,23 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
cli_credentials_get_workstation(gensec_security->credentials),
encrypted_session_key.data, encrypted_session_key.length,
gensec_ntlmssp_state->neg_flags)) {
-
+ talloc_free(mem_ctx);
return NT_STATUS_NO_MEMORY;
}
gensec_ntlmssp_state->session_key = session_key;
+ talloc_steal(gensec_ntlmssp_state, session_key.data);
+
+ talloc_steal(out_mem_ctx, out->data);
/* The client might be using 56 or 40 bit weakened keys */
ntlmssp_weaken_keys(gensec_ntlmssp_state);
gensec_ntlmssp_state->chal = challenge_blob;
gensec_ntlmssp_state->lm_resp = lm_response;
+ talloc_steal(gensec_ntlmssp_state->lm_resp.data, lm_response.data);
gensec_ntlmssp_state->nt_resp = nt_response;
+ talloc_steal(gensec_ntlmssp_state->nt_resp.data, nt_response.data);
gensec_ntlmssp_state->expected_state = NTLMSSP_DONE;
@@ -353,10 +276,12 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(1, ("Could not setup NTLMSSP signing/sealing system (error was: %s)\n",
nt_errstr(nt_status)));
+ talloc_free(mem_ctx);
return nt_status;
}
}
+ talloc_free(mem_ctx);
return NT_STATUS_OK;
}
@@ -378,7 +303,7 @@ NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security)
gensec_ntlmssp_state->use_nt_response = lp_parm_bool(-1, "ntlmssp_client", "send_nt_reponse", True);
- gensec_ntlmssp_state->allow_lm_key = (lp_lanman_auth()
+ gensec_ntlmssp_state->allow_lm_key = (lp_client_lanman_auth()
&& lp_parm_bool(-1, "ntlmssp_client", "allow_lm_key", False));
gensec_ntlmssp_state->use_ntlmv2 = lp_client_ntlmv2_auth();