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;
56 if (cred->kerberos_state == CRED_USE_KERBEROS_REQUIRED) {
58 return NT_STATUS_INVALID_PARAMETER_MIX;
61 /* We may already have an NTLM response we prepared earlier.
62 * This is used for NTLM pass-though authentication */
63 if (cred->nt_response.data || cred->lm_response.data) {
64 if (cred->nt_response.length != 0) {
65 nt_response = data_blob_dup_talloc(frame,
67 if (nt_response.data == NULL) {
69 return NT_STATUS_NO_MEMORY;
72 if (cred->nt_session_key.length != 0) {
73 session_key = data_blob_dup_talloc(frame,
74 cred->nt_session_key);
75 if (session_key.data == NULL) {
77 return NT_STATUS_NO_MEMORY;
80 if (cred->lm_response.length != 0) {
81 lm_response = data_blob_dup_talloc(frame,
83 if (lm_response.data == NULL) {
85 return NT_STATUS_NO_MEMORY;
88 if (cred->lm_session_key.length != 0) {
89 lm_session_key = data_blob_dup_talloc(frame,
90 cred->lm_session_key);
91 if (lm_session_key.data == NULL) {
93 return NT_STATUS_NO_MEMORY;
97 if (cred->lm_response.data == NULL) {
98 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
103 nt_hash = cli_credentials_get_nt_hash(cred, frame);
105 cli_credentials_get_ntlm_username_domain(cred, frame, &user, &domain);
108 return NT_STATUS_NO_MEMORY;
110 if (domain == NULL) {
112 return NT_STATUS_NO_MEMORY;
115 /* If we are sending a username@realm login (see function
116 * above), then we will not send LM, it will not be
118 if (cred->principal_obtained > cred->username_obtained) {
119 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
122 /* Likewise if we are a machine account (avoid protocol downgrade attacks) */
123 if (cred->machine_account) {
124 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
128 /* do nothing - blobs are zero length */
130 /* session key is all zeros */
131 session_key = data_blob_talloc_zero(frame, 16);
132 if (session_key.data == NULL) {
134 return NT_STATUS_NO_MEMORY;
136 session_key.data[0] = 'X';
137 lm_session_key = data_blob_talloc_zero(frame, 16);
138 if (lm_session_key.data == NULL) {
140 return NT_STATUS_NO_MEMORY;
143 /* not doing NTLM2 without a password */
144 *flags &= ~CLI_CRED_NTLM2;
145 } else if (*flags & CLI_CRED_NTLMv2_AUTH) {
147 if (!target_info.length) {
148 /* be lazy, match win2k - we can't do NTLMv2 without it */
149 DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n"));
151 return NT_STATUS_INVALID_PARAMETER;
154 /* TODO: if the remote server is standalone, then we should replace 'domain'
155 with the server name as supplied above */
157 if (!SMBNTLMv2encrypt_hash(frame,
160 nt_hash->hash, &challenge,
161 server_timestamp, &target_info,
162 &lm_response, &nt_response,
163 NULL, &session_key)) {
165 return NT_STATUS_NO_MEMORY;
168 /* LM Key is incompatible... */
169 *flags &= ~CLI_CRED_LANMAN_AUTH;
170 if (lm_response.length != 0) {
172 * We should not expose the lm key.
174 memset(lm_response.data, 0, lm_response.length);
176 } else if (*flags & CLI_CRED_NTLM2) {
177 uint8_t session_nonce[16];
178 uint8_t session_nonce_hash[16];
179 uint8_t user_session_key[16];
181 lm_response = data_blob_talloc_zero(frame, 24);
182 if (lm_response.data == NULL) {
184 return NT_STATUS_NO_MEMORY;
186 generate_random_buffer(lm_response.data, 8);
188 memcpy(session_nonce, challenge.data, 8);
189 memcpy(&session_nonce[8], lm_response.data, 8);
191 rc = gnutls_hash_fast(GNUTLS_DIG_MD5,
193 sizeof(session_nonce),
196 return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED);
199 DEBUG(5, ("NTLMSSP challenge set by NTLM2\n"));
200 DEBUG(5, ("challenge is: \n"));
201 dump_data(5, session_nonce_hash, 8);
203 nt_response = data_blob_talloc_zero(frame, 24);
204 if (nt_response.data == NULL) {
206 return NT_STATUS_NO_MEMORY;
208 rc = SMBOWFencrypt(nt_hash->hash,
213 return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
216 ZERO_ARRAY(session_nonce_hash);
218 session_key = data_blob_talloc_zero(frame, 16);
219 if (session_key.data == NULL) {
221 return NT_STATUS_NO_MEMORY;
224 SMBsesskeygen_ntv1(nt_hash->hash, user_session_key);
226 rc = gnutls_hmac_fast(GNUTLS_MAC_MD5,
228 sizeof(user_session_key),
230 sizeof(session_nonce),
233 return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED);
236 ZERO_ARRAY(user_session_key);
238 dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);
240 /* LM Key is incompatible... */
241 *flags &= ~CLI_CRED_LANMAN_AUTH;
243 const char *password = cli_credentials_get_password(cred);
247 nt_response = data_blob_talloc_zero(frame, 24);
248 if (nt_response.data == NULL) {
250 return NT_STATUS_NO_MEMORY;
252 rc = SMBOWFencrypt(nt_hash->hash, challenge.data,
256 return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
259 session_key = data_blob_talloc_zero(frame, 16);
260 if (session_key.data == NULL) {
262 return NT_STATUS_NO_MEMORY;
264 SMBsesskeygen_ntv1(nt_hash->hash, session_key.data);
265 dump_data_pw("NT session key:\n", session_key.data, session_key.length);
267 /* lanman auth is insecure, it may be disabled.
268 We may also not have a password */
270 if (password != NULL) {
271 do_lm = E_deshash(password, lm_hash);
274 if (*flags & CLI_CRED_LANMAN_AUTH && do_lm) {
275 lm_response = data_blob_talloc_zero(frame, 24);
276 if (lm_response.data == NULL) {
277 ZERO_STRUCT(lm_hash);
279 return NT_STATUS_NO_MEMORY;
282 rc = SMBencrypt_hash(lm_hash,
286 ZERO_STRUCT(lm_hash);
288 return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
291 /* just copy the nt_response */
292 lm_response = data_blob_dup_talloc(frame, nt_response);
293 if (lm_response.data == NULL) {
294 ZERO_STRUCT(lm_hash);
296 return NT_STATUS_NO_MEMORY;
301 lm_session_key = data_blob_talloc_zero(frame, 16);
302 if (lm_session_key.data == NULL) {
303 ZERO_STRUCT(lm_hash);
305 return NT_STATUS_NO_MEMORY;
307 memcpy(lm_session_key.data, lm_hash, 8);
309 if (!(*flags & CLI_CRED_NTLM_AUTH)) {
310 memcpy(session_key.data, lm_session_key.data, 16);
312 ZERO_STRUCT(lm_hash);
317 if (_lm_response != NULL) {
318 talloc_steal(mem_ctx, lm_response.data);
319 *_lm_response = lm_response;
321 data_blob_clear(&lm_response);
323 if (_nt_response != NULL) {
324 talloc_steal(mem_ctx, nt_response.data);
325 *_nt_response = nt_response;
327 data_blob_clear(&nt_response);
329 if (_lm_session_key != NULL) {
330 talloc_steal(mem_ctx, lm_session_key.data);
331 *_lm_session_key = lm_session_key;
333 data_blob_clear(&lm_session_key);
335 if (_session_key != NULL) {
336 talloc_steal(mem_ctx, session_key.data);
337 *_session_key = session_key;
339 data_blob_clear(&session_key);
346 * Set a utf16 password on the credentials context, including an indication
347 * of 'how' the password was obtained
349 * This is required because the nt_hash is calculated over the raw utf16 blob,
350 * which might not be completely valid utf16, which means the conversion
351 * from CH_UTF16MUNGED to CH_UTF8 might loose information.
353 _PUBLIC_ bool cli_credentials_set_utf16_password(struct cli_credentials *cred,
354 const DATA_BLOB *password_utf16,
355 enum credentials_obtained obtained)
357 cred->password_will_be_nt_hash = false;
359 if (password_utf16 == NULL) {
360 return cli_credentials_set_password(cred, NULL, obtained);
363 if (obtained >= cred->password_obtained) {
364 struct samr_Password *nt_hash = NULL;
365 char *password_talloc = NULL;
366 size_t password_len = 0;
369 nt_hash = talloc(cred, struct samr_Password);
370 if (nt_hash == NULL) {
374 ok = convert_string_talloc(cred,
375 CH_UTF16MUNGED, CH_UTF8,
376 password_utf16->data,
377 password_utf16->length,
378 (void *)&password_talloc,
381 TALLOC_FREE(nt_hash);
385 ok = cli_credentials_set_password(cred, password_talloc, obtained);
386 TALLOC_FREE(password_talloc);
388 TALLOC_FREE(nt_hash);
392 mdfour(nt_hash->hash, password_utf16->data, password_utf16->length);
393 cred->nt_hash = nt_hash;
401 * Set a old utf16 password on the credentials context.
403 * This is required because the nt_hash is calculated over the raw utf16 blob,
404 * which might not be completely valid utf16, which means the conversion
405 * from CH_UTF16MUNGED to CH_UTF8 might loose information.
407 _PUBLIC_ bool cli_credentials_set_old_utf16_password(struct cli_credentials *cred,
408 const DATA_BLOB *password_utf16)
410 struct samr_Password *nt_hash = NULL;
411 char *password_talloc = NULL;
412 size_t password_len = 0;
415 if (password_utf16 == NULL) {
416 return cli_credentials_set_old_password(cred, NULL, CRED_SPECIFIED);
419 nt_hash = talloc(cred, struct samr_Password);
420 if (nt_hash == NULL) {
424 ok = convert_string_talloc(cred,
425 CH_UTF16MUNGED, CH_UTF8,
426 password_utf16->data,
427 password_utf16->length,
428 (void *)&password_talloc,
431 TALLOC_FREE(nt_hash);
435 ok = cli_credentials_set_old_password(cred, password_talloc, CRED_SPECIFIED);
436 TALLOC_FREE(password_talloc);
438 TALLOC_FREE(nt_hash);
442 mdfour(nt_hash->hash, password_utf16->data, password_utf16->length);
443 cred->old_nt_hash = nt_hash;
447 _PUBLIC_ void cli_credentials_set_password_will_be_nt_hash(struct cli_credentials *cred,
451 * We set this here and the next cli_credentials_set_password()
452 * that resets the password or password callback
455 * cli_credentials_set_nt_hash() and
456 * cli_credentials_set_utf16_password() will reset this
459 cred->password_will_be_nt_hash = val;
462 _PUBLIC_ bool cli_credentials_set_nt_hash(struct cli_credentials *cred,
463 const struct samr_Password *nt_hash,
464 enum credentials_obtained obtained)
466 cred->password_will_be_nt_hash = false;
468 if (obtained >= cred->password_obtained) {
469 cli_credentials_set_password(cred, NULL, obtained);
471 cred->nt_hash = talloc(cred, struct samr_Password);
472 if (cred->nt_hash == NULL) {
475 *cred->nt_hash = *nt_hash;
477 cred->nt_hash = NULL;
485 _PUBLIC_ bool cli_credentials_set_old_nt_hash(struct cli_credentials *cred,
486 const struct samr_Password *nt_hash)
488 cli_credentials_set_old_password(cred, NULL, CRED_SPECIFIED);
490 cred->old_nt_hash = talloc(cred, struct samr_Password);
491 if (cred->old_nt_hash == NULL) {
494 *cred->old_nt_hash = *nt_hash;
496 cred->old_nt_hash = NULL;
502 _PUBLIC_ bool cli_credentials_set_ntlm_response(struct cli_credentials *cred,
503 const DATA_BLOB *lm_response,
504 const DATA_BLOB *lm_session_key,
505 const DATA_BLOB *nt_response,
506 const DATA_BLOB *nt_session_key,
507 enum credentials_obtained obtained)
509 if (obtained >= cred->password_obtained) {
510 cli_credentials_set_password(cred, NULL, obtained);
512 data_blob_clear_free(&cred->lm_response);
513 data_blob_clear_free(&cred->lm_session_key);
514 data_blob_clear_free(&cred->nt_response);
515 data_blob_clear_free(&cred->nt_session_key);
517 if (lm_response != NULL && lm_response->length != 0) {
518 cred->lm_response = data_blob_talloc(cred,
520 lm_response->length);
521 if (cred->lm_response.data == NULL) {
525 if (lm_session_key != NULL && lm_session_key->length != 0) {
526 cred->lm_session_key = data_blob_talloc(cred,
527 lm_session_key->data,
528 lm_session_key->length);
529 if (cred->lm_session_key.data == NULL) {
534 if (nt_response != NULL && nt_response->length != 0) {
535 cred->nt_response = data_blob_talloc(cred,
537 nt_response->length);
538 if (cred->nt_response.data == NULL) {
542 if (nt_session_key != NULL && nt_session_key->length != 0) {
543 cred->nt_session_key = data_blob_talloc(cred,
544 nt_session_key->data,
545 nt_session_key->length);
546 if (cred->nt_session_key.data == NULL) {