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"
29 #include "auth/credentials/credentials_internal.h"
31 #include "lib/crypto/gnutls_helpers.h"
32 #include <gnutls/gnutls.h>
33 #include <gnutls/crypto.h>
36 #define DBGC_CLASS DBGC_AUTH
38 _PUBLIC_ NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred, TALLOC_CTX *mem_ctx,
41 const NTTIME *server_timestamp,
42 DATA_BLOB target_info,
43 DATA_BLOB *_lm_response, DATA_BLOB *_nt_response,
44 DATA_BLOB *_lm_session_key, DATA_BLOB *_session_key)
46 TALLOC_CTX *frame = talloc_stackframe();
47 const char *user = NULL;
48 const char *domain = NULL;
49 DATA_BLOB lm_response = data_blob_null;
50 DATA_BLOB nt_response = data_blob_null;
51 DATA_BLOB lm_session_key = data_blob_null;
52 DATA_BLOB session_key = data_blob_null;
53 const struct samr_Password *nt_hash = NULL;
55 if (cred->use_kerberos == CRED_MUST_USE_KERBEROS) {
57 return NT_STATUS_INVALID_PARAMETER_MIX;
60 /* We may already have an NTLM response we prepared earlier.
61 * This is used for NTLM pass-though authentication */
62 if (cred->nt_response.data || cred->lm_response.data) {
63 if (cred->nt_response.length != 0) {
64 nt_response = data_blob_dup_talloc(frame,
66 if (nt_response.data == NULL) {
68 return NT_STATUS_NO_MEMORY;
71 if (cred->lm_response.length != 0) {
72 lm_response = data_blob_dup_talloc(frame,
74 if (lm_response.data == NULL) {
76 return NT_STATUS_NO_MEMORY;
80 if (cred->lm_response.data == NULL) {
81 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
86 nt_hash = cli_credentials_get_nt_hash(cred, frame);
88 cli_credentials_get_ntlm_username_domain(cred, frame, &user, &domain);
91 return NT_STATUS_NO_MEMORY;
95 return NT_STATUS_NO_MEMORY;
98 /* If we are sending a username@realm login (see function
99 * above), then we will not send LM, it will not be
101 if (cred->principal_obtained > cred->username_obtained) {
102 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
105 /* Likewise if we are a machine account (avoid protocol downgrade attacks) */
106 if (cred->machine_account) {
107 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
111 /* do nothing - blobs are zero length */
113 /* session key is all zeros */
114 session_key = data_blob_talloc_zero(frame, 16);
115 if (session_key.data == NULL) {
117 return NT_STATUS_NO_MEMORY;
119 lm_session_key = data_blob_talloc_zero(frame, 16);
120 if (lm_session_key.data == NULL) {
122 return NT_STATUS_NO_MEMORY;
125 /* not doing NTLM2 without a password */
126 *flags &= ~CLI_CRED_NTLM2;
127 } else if (*flags & CLI_CRED_NTLMv2_AUTH) {
129 if (!target_info.length) {
130 /* be lazy, match win2k - we can't do NTLMv2 without it */
131 DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n"));
133 return NT_STATUS_INVALID_PARAMETER;
136 /* TODO: if the remote server is standalone, then we should replace 'domain'
137 with the server name as supplied above */
139 if (!SMBNTLMv2encrypt_hash(frame,
142 nt_hash->hash, &challenge,
143 server_timestamp, &target_info,
144 &lm_response, &nt_response,
145 NULL, &session_key)) {
147 return NT_STATUS_NO_MEMORY;
150 /* LM Key is incompatible... */
151 *flags &= ~CLI_CRED_LANMAN_AUTH;
152 if (lm_response.length != 0) {
154 * We should not expose the lm key.
156 memset(lm_response.data, 0, lm_response.length);
158 } else if (*flags & CLI_CRED_NTLM2) {
159 uint8_t session_nonce[16];
160 uint8_t session_nonce_hash[16];
161 uint8_t user_session_key[16];
164 lm_response = data_blob_talloc_zero(frame, 24);
165 if (lm_response.data == NULL) {
167 return NT_STATUS_NO_MEMORY;
169 generate_random_buffer(lm_response.data, 8);
171 memcpy(session_nonce, challenge.data, 8);
172 memcpy(&session_nonce[8], lm_response.data, 8);
174 rc = gnutls_hash_fast(GNUTLS_DIG_MD5,
176 sizeof(session_nonce),
179 return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED);
182 DEBUG(5, ("NTLMSSP challenge set by NTLM2\n"));
183 DEBUG(5, ("challenge is: \n"));
184 dump_data(5, session_nonce_hash, 8);
186 nt_response = data_blob_talloc_zero(frame, 24);
187 if (nt_response.data == NULL) {
189 return NT_STATUS_NO_MEMORY;
191 SMBOWFencrypt(nt_hash->hash,
195 ZERO_ARRAY(session_nonce_hash);
197 session_key = data_blob_talloc_zero(frame, 16);
198 if (session_key.data == NULL) {
200 return NT_STATUS_NO_MEMORY;
203 SMBsesskeygen_ntv1(nt_hash->hash, user_session_key);
205 rc = gnutls_hmac_fast(GNUTLS_MAC_MD5,
207 sizeof(user_session_key),
209 sizeof(session_nonce),
212 return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED);
215 ZERO_ARRAY(user_session_key);
217 dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);
219 /* LM Key is incompatible... */
220 *flags &= ~CLI_CRED_LANMAN_AUTH;
222 const char *password = cli_credentials_get_password(cred);
226 nt_response = data_blob_talloc_zero(frame, 24);
227 if (nt_response.data == NULL) {
229 return NT_STATUS_NO_MEMORY;
231 SMBOWFencrypt(nt_hash->hash, challenge.data,
234 session_key = data_blob_talloc_zero(frame, 16);
235 if (session_key.data == NULL) {
237 return NT_STATUS_NO_MEMORY;
239 SMBsesskeygen_ntv1(nt_hash->hash, session_key.data);
240 dump_data_pw("NT session key:\n", session_key.data, session_key.length);
242 /* lanman auth is insecure, it may be disabled.
243 We may also not have a password */
245 if (password != NULL) {
246 do_lm = E_deshash(password, lm_hash);
249 if (*flags & CLI_CRED_LANMAN_AUTH && do_lm) {
250 lm_response = data_blob_talloc_zero(frame, 24);
251 if (lm_response.data == NULL) {
252 ZERO_STRUCT(lm_hash);
254 return NT_STATUS_NO_MEMORY;
257 SMBencrypt_hash(lm_hash,
261 /* just copy the nt_response */
262 lm_response = data_blob_dup_talloc(frame, nt_response);
263 if (lm_response.data == NULL) {
264 ZERO_STRUCT(lm_hash);
266 return NT_STATUS_NO_MEMORY;
271 lm_session_key = data_blob_talloc_zero(frame, 16);
272 if (lm_session_key.data == NULL) {
273 ZERO_STRUCT(lm_hash);
275 return NT_STATUS_NO_MEMORY;
277 memcpy(lm_session_key.data, lm_hash, 8);
279 if (!(*flags & CLI_CRED_NTLM_AUTH)) {
280 memcpy(session_key.data, lm_session_key.data, 16);
282 ZERO_STRUCT(lm_hash);
287 if (_lm_response != NULL) {
288 talloc_steal(mem_ctx, lm_response.data);
289 *_lm_response = lm_response;
291 data_blob_clear(&lm_response);
293 if (_nt_response != NULL) {
294 talloc_steal(mem_ctx, nt_response.data);
295 *_nt_response = nt_response;
297 data_blob_clear(&nt_response);
299 if (_lm_session_key != NULL) {
300 talloc_steal(mem_ctx, lm_session_key.data);
301 *_lm_session_key = lm_session_key;
303 data_blob_clear(&lm_session_key);
305 if (_session_key != NULL) {
306 talloc_steal(mem_ctx, session_key.data);
307 *_session_key = session_key;
309 data_blob_clear(&session_key);
316 * Set a utf16 password on the credentials context, including an indication
317 * of 'how' the password was obtained
319 * This is required because the nt_hash is calculated over the raw utf16 blob,
320 * which might not be completely valid utf16, which means the conversion
321 * from CH_UTF16MUNGED to CH_UTF8 might loose information.
323 _PUBLIC_ bool cli_credentials_set_utf16_password(struct cli_credentials *cred,
324 const DATA_BLOB *password_utf16,
325 enum credentials_obtained obtained)
327 cred->password_will_be_nt_hash = false;
329 if (password_utf16 == NULL) {
330 return cli_credentials_set_password(cred, NULL, obtained);
333 if (obtained >= cred->password_obtained) {
334 struct samr_Password *nt_hash = NULL;
335 char *password_talloc = NULL;
336 size_t password_len = 0;
339 nt_hash = talloc(cred, struct samr_Password);
340 if (nt_hash == NULL) {
344 ok = convert_string_talloc(cred,
345 CH_UTF16MUNGED, CH_UTF8,
346 password_utf16->data,
347 password_utf16->length,
348 (void *)&password_talloc,
351 TALLOC_FREE(nt_hash);
355 ok = cli_credentials_set_password(cred, password_talloc, obtained);
356 TALLOC_FREE(password_talloc);
358 TALLOC_FREE(nt_hash);
362 mdfour(nt_hash->hash, password_utf16->data, password_utf16->length);
363 cred->nt_hash = nt_hash;
371 * Set a old utf16 password on the credentials context.
373 * This is required because the nt_hash is calculated over the raw utf16 blob,
374 * which might not be completely valid utf16, which means the conversion
375 * from CH_UTF16MUNGED to CH_UTF8 might loose information.
377 _PUBLIC_ bool cli_credentials_set_old_utf16_password(struct cli_credentials *cred,
378 const DATA_BLOB *password_utf16)
380 struct samr_Password *nt_hash = NULL;
381 char *password_talloc = NULL;
382 size_t password_len = 0;
385 if (password_utf16 == NULL) {
386 return cli_credentials_set_old_password(cred, NULL, CRED_SPECIFIED);
389 nt_hash = talloc(cred, struct samr_Password);
390 if (nt_hash == NULL) {
394 ok = convert_string_talloc(cred,
395 CH_UTF16MUNGED, CH_UTF8,
396 password_utf16->data,
397 password_utf16->length,
398 (void *)&password_talloc,
401 TALLOC_FREE(nt_hash);
405 ok = cli_credentials_set_old_password(cred, password_talloc, CRED_SPECIFIED);
406 TALLOC_FREE(password_talloc);
408 TALLOC_FREE(nt_hash);
412 mdfour(nt_hash->hash, password_utf16->data, password_utf16->length);
413 cred->old_nt_hash = nt_hash;
417 _PUBLIC_ void cli_credentials_set_password_will_be_nt_hash(struct cli_credentials *cred,
421 * We set this here and the next cli_credentials_set_password()
422 * that resets the password or password callback
425 * cli_credentials_set_nt_hash() and
426 * cli_credentials_set_utf16_password() will reset this
429 cred->password_will_be_nt_hash = val;
432 _PUBLIC_ bool cli_credentials_set_nt_hash(struct cli_credentials *cred,
433 const struct samr_Password *nt_hash,
434 enum credentials_obtained obtained)
436 cred->password_will_be_nt_hash = false;
438 if (obtained >= cred->password_obtained) {
439 cli_credentials_set_password(cred, NULL, obtained);
441 cred->nt_hash = talloc(cred, struct samr_Password);
442 if (cred->nt_hash == NULL) {
445 *cred->nt_hash = *nt_hash;
447 cred->nt_hash = NULL;
455 _PUBLIC_ bool cli_credentials_set_old_nt_hash(struct cli_credentials *cred,
456 const struct samr_Password *nt_hash)
458 cli_credentials_set_old_password(cred, NULL, CRED_SPECIFIED);
460 cred->old_nt_hash = talloc(cred, struct samr_Password);
461 if (cred->old_nt_hash == NULL) {
464 *cred->old_nt_hash = *nt_hash;
466 cred->old_nt_hash = NULL;
472 _PUBLIC_ bool cli_credentials_set_ntlm_response(struct cli_credentials *cred,
473 const DATA_BLOB *lm_response,
474 const DATA_BLOB *nt_response,
475 enum credentials_obtained obtained)
477 if (obtained >= cred->password_obtained) {
478 cli_credentials_set_password(cred, NULL, obtained);
480 cred->nt_response = data_blob_talloc(cred, nt_response->data, nt_response->length);
481 talloc_steal(cred, cred->nt_response.data);
484 cred->lm_response = data_blob_talloc(cred, lm_response->data, lm_response->length);