torture: Reproducer for 64c0367
[Samba/gebeck_regimport.git] / auth / credentials / credentials_ntlm.c
blob2d6d6f6c55e6800019662d6e7fd1a00ce648a5d1
1 /*
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/>.
24 #include "includes.h"
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 _PUBLIC_ NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred, TALLOC_CTX *mem_ctx,
31 int *flags,
32 DATA_BLOB challenge, DATA_BLOB target_info,
33 DATA_BLOB *_lm_response, DATA_BLOB *_nt_response,
34 DATA_BLOB *_lm_session_key, DATA_BLOB *_session_key)
36 const char *user, *domain;
37 DATA_BLOB lm_response, nt_response;
38 DATA_BLOB lm_session_key, session_key;
39 const struct samr_Password *nt_hash;
40 lm_session_key = data_blob(NULL, 0);
42 /* We may already have an NTLM response we prepared earlier.
43 * This is used for NTLM pass-though authentication */
44 if (cred->nt_response.data || cred->lm_response.data) {
45 *_nt_response = cred->nt_response;
46 *_lm_response = cred->lm_response;
48 if (!cred->lm_response.data) {
49 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
51 *_lm_session_key = data_blob(NULL, 0);
52 *_session_key = data_blob(NULL, 0);
53 return NT_STATUS_OK;
56 nt_hash = cli_credentials_get_nt_hash(cred, mem_ctx);
58 cli_credentials_get_ntlm_username_domain(cred, mem_ctx, &user, &domain);
60 /* If we are sending a username@realm login (see function
61 * above), then we will not send LM, it will not be
62 * accepted */
63 if (cred->principal_obtained > cred->username_obtained) {
64 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
67 /* Likewise if we are a machine account (avoid protocol downgrade attacks) */
68 if (cred->machine_account) {
69 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
72 if (cred->use_kerberos == CRED_MUST_USE_KERBEROS) {
73 return NT_STATUS_ACCESS_DENIED;
76 if (!nt_hash) {
77 static const uint8_t zeros[16];
78 /* do nothing - blobs are zero length */
80 /* session key is all zeros */
81 session_key = data_blob_talloc(mem_ctx, zeros, 16);
82 lm_session_key = data_blob_talloc(mem_ctx, zeros, 16);
84 lm_response = data_blob(NULL, 0);
85 nt_response = data_blob(NULL, 0);
87 /* not doing NTLM2 without a password */
88 *flags &= ~CLI_CRED_NTLM2;
89 } else if (*flags & CLI_CRED_NTLMv2_AUTH) {
91 if (!target_info.length) {
92 /* be lazy, match win2k - we can't do NTLMv2 without it */
93 DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n"));
94 return NT_STATUS_INVALID_PARAMETER;
97 /* TODO: if the remote server is standalone, then we should replace 'domain'
98 with the server name as supplied above */
100 if (!SMBNTLMv2encrypt_hash(mem_ctx,
101 user,
102 domain,
103 nt_hash->hash, &challenge,
104 &target_info,
105 &lm_response, &nt_response,
106 NULL, &session_key)) {
107 return NT_STATUS_NO_MEMORY;
110 /* LM Key is incompatible... */
111 *flags &= ~CLI_CRED_LANMAN_AUTH;
112 } else if (*flags & CLI_CRED_NTLM2) {
113 struct MD5Context md5_session_nonce_ctx;
114 uint8_t session_nonce[16];
115 uint8_t session_nonce_hash[16];
116 uint8_t user_session_key[16];
118 lm_response = data_blob_talloc(mem_ctx, NULL, 24);
119 generate_random_buffer(lm_response.data, 8);
120 memset(lm_response.data+8, 0, 16);
122 memcpy(session_nonce, challenge.data, 8);
123 memcpy(&session_nonce[8], lm_response.data, 8);
125 MD5Init(&md5_session_nonce_ctx);
126 MD5Update(&md5_session_nonce_ctx, challenge.data, 8);
127 MD5Update(&md5_session_nonce_ctx, lm_response.data, 8);
128 MD5Final(session_nonce_hash, &md5_session_nonce_ctx);
130 DEBUG(5, ("NTLMSSP challenge set by NTLM2\n"));
131 DEBUG(5, ("challenge is: \n"));
132 dump_data(5, session_nonce_hash, 8);
134 nt_response = data_blob_talloc(mem_ctx, NULL, 24);
135 SMBOWFencrypt(nt_hash->hash,
136 session_nonce_hash,
137 nt_response.data);
139 session_key = data_blob_talloc(mem_ctx, NULL, 16);
141 SMBsesskeygen_ntv1(nt_hash->hash, user_session_key);
142 hmac_md5(user_session_key, session_nonce, sizeof(session_nonce), session_key.data);
143 dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);
145 /* LM Key is incompatible... */
146 *flags &= ~CLI_CRED_LANMAN_AUTH;
147 } else {
148 uint8_t lm_hash[16];
149 nt_response = data_blob_talloc(mem_ctx, NULL, 24);
150 SMBOWFencrypt(nt_hash->hash, challenge.data,
151 nt_response.data);
153 session_key = data_blob_talloc(mem_ctx, NULL, 16);
154 SMBsesskeygen_ntv1(nt_hash->hash, session_key.data);
155 dump_data_pw("NT session key:\n", session_key.data, session_key.length);
157 /* lanman auth is insecure, it may be disabled.
158 We may also not have a password */
159 if (*flags & CLI_CRED_LANMAN_AUTH) {
160 const char *password;
161 password = cli_credentials_get_password(cred);
162 if (!password) {
163 lm_response = nt_response;
164 } else {
165 lm_response = data_blob_talloc(mem_ctx, NULL, 24);
166 if (!SMBencrypt(password,challenge.data,
167 lm_response.data)) {
168 /* If the LM password was too long (and therefore the LM hash being
169 of the first 14 chars only), don't send it.
171 We don't have any better options but to send the NT response
173 data_blob_free(&lm_response);
174 lm_response = nt_response;
175 /* LM Key is incompatible with 'long' passwords */
176 *flags &= ~CLI_CRED_LANMAN_AUTH;
177 } else if (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;
187 } else {
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);
195 if (password && E_deshash(password, lm_hash)) {
196 lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
197 memcpy(lm_session_key.data, lm_hash, 8);
198 memset(&lm_session_key.data[8], '\0', 8);
202 if (_lm_response) {
203 *_lm_response = lm_response;
205 if (_nt_response) {
206 *_nt_response = nt_response;
208 if (_lm_session_key) {
209 *_lm_session_key = lm_session_key;
211 if (_session_key) {
212 *_session_key = session_key;
214 return NT_STATUS_OK;
217 _PUBLIC_ bool cli_credentials_set_nt_hash(struct cli_credentials *cred,
218 const struct samr_Password *nt_hash,
219 enum credentials_obtained obtained)
221 if (obtained >= cred->password_obtained) {
222 cli_credentials_set_password(cred, NULL, obtained);
223 if (nt_hash) {
224 cred->nt_hash = talloc(cred, struct samr_Password);
225 *cred->nt_hash = *nt_hash;
226 } else {
227 cred->nt_hash = NULL;
229 return true;
232 return false;
235 _PUBLIC_ bool cli_credentials_set_ntlm_response(struct cli_credentials *cred,
236 const DATA_BLOB *lm_response,
237 const DATA_BLOB *nt_response,
238 enum credentials_obtained obtained)
240 if (obtained >= cred->password_obtained) {
241 cli_credentials_set_password(cred, NULL, obtained);
242 if (nt_response) {
243 cred->nt_response = data_blob_talloc(cred, nt_response->data, nt_response->length);
244 talloc_steal(cred, cred->nt_response.data);
246 if (nt_response) {
247 cred->lm_response = data_blob_talloc(cred, lm_response->data, lm_response->length);
249 return true;
252 return false;