Revert "script/release.sh: use 8 byte gpg key ids"
[Samba.git] / auth / credentials / credentials_ntlm.c
blob0abbb5c020da878901167985f78133b1c3052b22
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"
29 #include "auth/credentials/credentials_internal.h"
31 _PUBLIC_ NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred, TALLOC_CTX *mem_ctx,
32 int *flags,
33 DATA_BLOB challenge,
34 const NTTIME *server_timestamp,
35 DATA_BLOB target_info,
36 DATA_BLOB *_lm_response, DATA_BLOB *_nt_response,
37 DATA_BLOB *_lm_session_key, DATA_BLOB *_session_key)
39 const char *user, *domain;
40 DATA_BLOB lm_response, nt_response;
41 DATA_BLOB lm_session_key, session_key;
42 const struct samr_Password *nt_hash;
43 lm_session_key = data_blob(NULL, 0);
45 /* We may already have an NTLM response we prepared earlier.
46 * This is used for NTLM pass-though authentication */
47 if (cred->nt_response.data || cred->lm_response.data) {
48 *_nt_response = cred->nt_response;
49 *_lm_response = cred->lm_response;
51 if (!cred->lm_response.data) {
52 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
54 *_lm_session_key = data_blob(NULL, 0);
55 *_session_key = data_blob(NULL, 0);
56 return NT_STATUS_OK;
59 nt_hash = cli_credentials_get_nt_hash(cred, mem_ctx);
61 cli_credentials_get_ntlm_username_domain(cred, mem_ctx, &user, &domain);
63 /* If we are sending a username@realm login (see function
64 * above), then we will not send LM, it will not be
65 * accepted */
66 if (cred->principal_obtained > cred->username_obtained) {
67 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
70 /* Likewise if we are a machine account (avoid protocol downgrade attacks) */
71 if (cred->machine_account) {
72 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
75 if (cred->use_kerberos == CRED_MUST_USE_KERBEROS) {
76 return NT_STATUS_ACCESS_DENIED;
79 if (!nt_hash) {
80 static const uint8_t zeros[16];
81 /* do nothing - blobs are zero length */
83 /* session key is all zeros */
84 session_key = data_blob_talloc(mem_ctx, zeros, 16);
85 lm_session_key = data_blob_talloc(mem_ctx, zeros, 16);
87 lm_response = data_blob(NULL, 0);
88 nt_response = data_blob(NULL, 0);
90 /* not doing NTLM2 without a password */
91 *flags &= ~CLI_CRED_NTLM2;
92 } else if (*flags & CLI_CRED_NTLMv2_AUTH) {
94 if (!target_info.length) {
95 /* be lazy, match win2k - we can't do NTLMv2 without it */
96 DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n"));
97 return NT_STATUS_INVALID_PARAMETER;
100 /* TODO: if the remote server is standalone, then we should replace 'domain'
101 with the server name as supplied above */
103 if (!SMBNTLMv2encrypt_hash(mem_ctx,
104 user,
105 domain,
106 nt_hash->hash, &challenge,
107 server_timestamp, &target_info,
108 &lm_response, &nt_response,
109 NULL, &session_key)) {
110 return NT_STATUS_NO_MEMORY;
113 /* LM Key is incompatible... */
114 *flags &= ~CLI_CRED_LANMAN_AUTH;
115 if (lm_response.length != 0) {
117 * We should not expose the lm key.
119 memset(lm_response.data, 0, lm_response.length);
121 } else if (*flags & CLI_CRED_NTLM2) {
122 MD5_CTX md5_session_nonce_ctx;
123 uint8_t session_nonce[16];
124 uint8_t session_nonce_hash[16];
125 uint8_t user_session_key[16];
127 lm_response = data_blob_talloc(mem_ctx, NULL, 24);
128 generate_random_buffer(lm_response.data, 8);
129 memset(lm_response.data+8, 0, 16);
131 memcpy(session_nonce, challenge.data, 8);
132 memcpy(&session_nonce[8], lm_response.data, 8);
134 MD5Init(&md5_session_nonce_ctx);
135 MD5Update(&md5_session_nonce_ctx, challenge.data, 8);
136 MD5Update(&md5_session_nonce_ctx, lm_response.data, 8);
137 MD5Final(session_nonce_hash, &md5_session_nonce_ctx);
139 DEBUG(5, ("NTLMSSP challenge set by NTLM2\n"));
140 DEBUG(5, ("challenge is: \n"));
141 dump_data(5, session_nonce_hash, 8);
143 nt_response = data_blob_talloc(mem_ctx, NULL, 24);
144 SMBOWFencrypt(nt_hash->hash,
145 session_nonce_hash,
146 nt_response.data);
148 session_key = data_blob_talloc(mem_ctx, NULL, 16);
150 SMBsesskeygen_ntv1(nt_hash->hash, user_session_key);
151 hmac_md5(user_session_key, session_nonce, sizeof(session_nonce), session_key.data);
152 dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);
154 /* LM Key is incompatible... */
155 *flags &= ~CLI_CRED_LANMAN_AUTH;
156 } else {
157 uint8_t lm_hash[16];
158 nt_response = data_blob_talloc(mem_ctx, NULL, 24);
159 SMBOWFencrypt(nt_hash->hash, challenge.data,
160 nt_response.data);
162 session_key = data_blob_talloc(mem_ctx, NULL, 16);
163 SMBsesskeygen_ntv1(nt_hash->hash, session_key.data);
164 dump_data_pw("NT session key:\n", session_key.data, session_key.length);
166 /* lanman auth is insecure, it may be disabled.
167 We may also not have a password */
168 if (*flags & CLI_CRED_LANMAN_AUTH) {
169 const char *password;
170 password = cli_credentials_get_password(cred);
171 if (!password) {
172 lm_response = nt_response;
173 } else {
174 lm_response = data_blob_talloc(mem_ctx, NULL, 24);
175 if (!SMBencrypt(password,challenge.data,
176 lm_response.data)) {
177 /* If the LM password was too long (and therefore the LM hash being
178 of the first 14 chars only), don't send it.
180 We don't have any better options but to send the NT response
182 data_blob_free(&lm_response);
183 lm_response = nt_response;
184 /* LM Key is incompatible with 'long' passwords */
185 *flags &= ~CLI_CRED_LANMAN_AUTH;
186 } else if (E_deshash(password, lm_hash)) {
187 lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
188 memcpy(lm_session_key.data, lm_hash, 8);
189 memset(&lm_session_key.data[8], '\0', 8);
191 if (!(*flags & CLI_CRED_NTLM_AUTH)) {
192 session_key = lm_session_key;
196 } else {
197 const char *password;
199 /* LM Key is incompatible... */
200 lm_response = nt_response;
201 *flags &= ~CLI_CRED_LANMAN_AUTH;
203 password = cli_credentials_get_password(cred);
204 if (password && E_deshash(password, lm_hash)) {
205 lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
206 memcpy(lm_session_key.data, lm_hash, 8);
207 memset(&lm_session_key.data[8], '\0', 8);
211 if (_lm_response) {
212 *_lm_response = lm_response;
214 if (_nt_response) {
215 *_nt_response = nt_response;
217 if (_lm_session_key) {
218 *_lm_session_key = lm_session_key;
220 if (_session_key) {
221 *_session_key = session_key;
223 return NT_STATUS_OK;
227 * Set a utf16 password on the credentials context, including an indication
228 * of 'how' the password was obtained
230 * This is required because the nt_hash is calculated over the raw utf16 blob,
231 * which might not be completely valid utf16, which means the conversion
232 * from CH_UTF16MUNGED to CH_UTF8 might loose information.
234 _PUBLIC_ bool cli_credentials_set_utf16_password(struct cli_credentials *cred,
235 const DATA_BLOB *password_utf16,
236 enum credentials_obtained obtained)
238 if (password_utf16 == NULL) {
239 return cli_credentials_set_password(cred, NULL, obtained);
242 if (obtained >= cred->password_obtained) {
243 struct samr_Password *nt_hash = NULL;
244 char *password_talloc = NULL;
245 size_t password_len = 0;
246 bool ok;
248 nt_hash = talloc(cred, struct samr_Password);
249 if (nt_hash == NULL) {
250 return false;
253 ok = convert_string_talloc(cred,
254 CH_UTF16MUNGED, CH_UTF8,
255 password_utf16->data,
256 password_utf16->length,
257 (void *)&password_talloc,
258 &password_len);
259 if (!ok) {
260 TALLOC_FREE(nt_hash);
261 return false;
264 ok = cli_credentials_set_password(cred, password_talloc, obtained);
265 TALLOC_FREE(password_talloc);
266 if (!ok) {
267 TALLOC_FREE(nt_hash);
268 return false;
271 mdfour(nt_hash->hash, password_utf16->data, password_utf16->length);
272 cred->nt_hash = nt_hash;
273 return true;
276 return false;
280 * Set a old utf16 password on the credentials context.
282 * This is required because the nt_hash is calculated over the raw utf16 blob,
283 * which might not be completely valid utf16, which means the conversion
284 * from CH_UTF16MUNGED to CH_UTF8 might loose information.
286 _PUBLIC_ bool cli_credentials_set_old_utf16_password(struct cli_credentials *cred,
287 const DATA_BLOB *password_utf16)
289 struct samr_Password *nt_hash = NULL;
290 char *password_talloc = NULL;
291 size_t password_len = 0;
292 bool ok;
294 if (password_utf16 == NULL) {
295 return cli_credentials_set_old_password(cred, NULL, CRED_SPECIFIED);
298 nt_hash = talloc(cred, struct samr_Password);
299 if (nt_hash == NULL) {
300 return false;
303 ok = convert_string_talloc(cred,
304 CH_UTF16MUNGED, CH_UTF8,
305 password_utf16->data,
306 password_utf16->length,
307 (void *)&password_talloc,
308 &password_len);
309 if (!ok) {
310 TALLOC_FREE(nt_hash);
311 return false;
314 ok = cli_credentials_set_old_password(cred, password_talloc, CRED_SPECIFIED);
315 TALLOC_FREE(password_talloc);
316 if (!ok) {
317 TALLOC_FREE(nt_hash);
318 return false;
321 mdfour(nt_hash->hash, password_utf16->data, password_utf16->length);
322 cred->old_nt_hash = nt_hash;
323 return true;
326 _PUBLIC_ bool cli_credentials_set_nt_hash(struct cli_credentials *cred,
327 const struct samr_Password *nt_hash,
328 enum credentials_obtained obtained)
330 if (obtained >= cred->password_obtained) {
331 cli_credentials_set_password(cred, NULL, obtained);
332 if (nt_hash) {
333 cred->nt_hash = talloc(cred, struct samr_Password);
334 if (cred->nt_hash == NULL) {
335 return false;
337 *cred->nt_hash = *nt_hash;
338 } else {
339 cred->nt_hash = NULL;
341 return true;
344 return false;
347 _PUBLIC_ bool cli_credentials_set_old_nt_hash(struct cli_credentials *cred,
348 const struct samr_Password *nt_hash)
350 cli_credentials_set_old_password(cred, NULL, CRED_SPECIFIED);
351 if (nt_hash) {
352 cred->old_nt_hash = talloc(cred, struct samr_Password);
353 if (cred->old_nt_hash == NULL) {
354 return false;
356 *cred->old_nt_hash = *nt_hash;
357 } else {
358 cred->old_nt_hash = NULL;
361 return true;
364 _PUBLIC_ bool cli_credentials_set_ntlm_response(struct cli_credentials *cred,
365 const DATA_BLOB *lm_response,
366 const DATA_BLOB *nt_response,
367 enum credentials_obtained obtained)
369 if (obtained >= cred->password_obtained) {
370 cli_credentials_set_password(cred, NULL, obtained);
371 if (nt_response) {
372 cred->nt_response = data_blob_talloc(cred, nt_response->data, nt_response->length);
373 talloc_steal(cred, cred->nt_response.data);
375 if (nt_response) {
376 cred->lm_response = data_blob_talloc(cred, lm_response->data, lm_response->length);
378 return true;
381 return false;