2 Unix SMB/CIFS implementation.
4 User credentials handling
6 Copyright (C) Andrew Tridgell 2001
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2001-2005
8 Copyright (C) Stefan Metzmacher 2005
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "librpc/gen_ndr/samr.h" /* for struct samrPassword */
26 #include "lib/crypto/crypto.h"
27 #include "libcli/auth/libcli_auth.h"
28 #include "auth/credentials/credentials.h"
30 void cli_credentials_get_ntlm_username_domain(struct cli_credentials *cred, TALLOC_CTX *mem_ctx,
31 const char **username,
34 if (cred->principal_obtained > cred->username_obtained) {
35 *domain = talloc_strdup(mem_ctx, "");
36 *username = cli_credentials_get_principal(cred, mem_ctx);
38 *domain = cli_credentials_get_domain(cred);
39 *username = cli_credentials_get_username(cred);
43 NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred, TALLOC_CTX *mem_ctx,
45 DATA_BLOB challenge, DATA_BLOB target_info,
46 DATA_BLOB *_lm_response, DATA_BLOB *_nt_response,
47 DATA_BLOB *_lm_session_key, DATA_BLOB *_session_key)
49 const char *user, *domain;
50 DATA_BLOB lm_response, nt_response;
51 DATA_BLOB lm_session_key, session_key;
52 const struct samr_Password *nt_hash;
53 lm_session_key = data_blob(NULL, 0);
55 nt_hash = cli_credentials_get_nt_hash(cred, mem_ctx);
57 cli_credentials_get_ntlm_username_domain(cred, mem_ctx, &user, &domain);
59 /* If we are sending a username@realm login (see function
60 * above), then we will not send LM, it will not be
62 if (cred->principal_obtained > cred->username_obtained) {
63 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
66 /* Likewise if we are a machine account (avoid protocol downgrade attacks) */
67 if (cred->machine_account) {
68 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
71 if (cred->use_kerberos == CRED_MUST_USE_KERBEROS) {
72 return NT_STATUS_ACCESS_DENIED;
76 static const uint8_t zeros[16];
77 /* do nothing - blobs are zero length */
79 /* session key is all zeros */
80 session_key = data_blob_talloc(mem_ctx, zeros, 16);
81 lm_session_key = data_blob_talloc(mem_ctx, zeros, 16);
83 lm_response = data_blob(NULL, 0);
84 nt_response = data_blob(NULL, 0);
86 /* not doing NTLM2 without a password */
87 *flags &= ~CLI_CRED_NTLM2;
88 } else if (*flags & CLI_CRED_NTLMv2_AUTH) {
90 if (!target_info.length) {
91 /* be lazy, match win2k - we can't do NTLMv2 without it */
92 DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n"));
93 return NT_STATUS_INVALID_PARAMETER;
96 /* TODO: if the remote server is standalone, then we should replace 'domain'
97 with the server name as supplied above */
99 if (!SMBNTLMv2encrypt_hash(mem_ctx,
102 nt_hash->hash, &challenge,
104 &lm_response, &nt_response,
105 NULL, &session_key)) {
106 return NT_STATUS_NO_MEMORY;
109 /* LM Key is incompatible... */
110 *flags &= ~CLI_CRED_LANMAN_AUTH;
111 } else if (*flags & CLI_CRED_NTLM2) {
112 struct MD5Context md5_session_nonce_ctx;
113 uint8_t session_nonce[16];
114 uint8_t session_nonce_hash[16];
115 uint8_t user_session_key[16];
117 lm_response = data_blob_talloc(mem_ctx, NULL, 24);
118 generate_random_buffer(lm_response.data, 8);
119 memset(lm_response.data+8, 0, 16);
121 memcpy(session_nonce, challenge.data, 8);
122 memcpy(&session_nonce[8], lm_response.data, 8);
124 MD5Init(&md5_session_nonce_ctx);
125 MD5Update(&md5_session_nonce_ctx, challenge.data, 8);
126 MD5Update(&md5_session_nonce_ctx, lm_response.data, 8);
127 MD5Final(session_nonce_hash, &md5_session_nonce_ctx);
129 DEBUG(5, ("NTLMSSP challenge set by NTLM2\n"));
130 DEBUG(5, ("challenge is: \n"));
131 dump_data(5, session_nonce_hash, 8);
133 nt_response = data_blob_talloc(mem_ctx, NULL, 24);
134 SMBOWFencrypt(nt_hash->hash,
138 session_key = data_blob_talloc(mem_ctx, NULL, 16);
140 SMBsesskeygen_ntv1(nt_hash->hash, user_session_key);
141 hmac_md5(user_session_key, session_nonce, sizeof(session_nonce), session_key.data);
142 dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);
144 /* LM Key is incompatible... */
145 *flags &= ~CLI_CRED_LANMAN_AUTH;
148 nt_response = data_blob_talloc(mem_ctx, NULL, 24);
149 SMBOWFencrypt(nt_hash->hash, challenge.data,
152 session_key = data_blob_talloc(mem_ctx, NULL, 16);
153 SMBsesskeygen_ntv1(nt_hash->hash, session_key.data);
154 dump_data_pw("NT session key:\n", session_key.data, session_key.length);
156 /* lanman auth is insecure, it may be disabled.
157 We may also not have a password */
158 if (*flags & CLI_CRED_LANMAN_AUTH) {
159 const char *password;
160 password = cli_credentials_get_password(cred);
162 lm_response = nt_response;
164 lm_response = data_blob_talloc(mem_ctx, NULL, 24);
165 if (!SMBencrypt(password,challenge.data,
167 /* If the LM password was too long (and therefore the LM hash being
168 of the first 14 chars only), don't send it.
170 We don't have any better options but to send the NT response
172 data_blob_free(&lm_response);
173 lm_response = nt_response;
174 /* LM Key is incompatible with 'long' passwords */
175 *flags &= ~CLI_CRED_LANMAN_AUTH;
177 E_deshash(password, lm_hash);
178 lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
179 memcpy(lm_session_key.data, lm_hash, 8);
180 memset(&lm_session_key.data[8], '\0', 8);
182 if (!(*flags & CLI_CRED_NTLM_AUTH)) {
183 session_key = lm_session_key;
188 const char *password;
190 /* LM Key is incompatible... */
191 lm_response = nt_response;
192 *flags &= ~CLI_CRED_LANMAN_AUTH;
194 password = cli_credentials_get_password(cred);
196 E_deshash(password, lm_hash);
197 lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
198 memcpy(lm_session_key.data, lm_hash, 8);
199 memset(&lm_session_key.data[8], '\0', 8);
204 *_lm_response = lm_response;
207 *_nt_response = nt_response;
209 if (_lm_session_key) {
210 *_lm_session_key = lm_session_key;
213 *_session_key = session_key;