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 lm_session_key
= data_blob_talloc_zero(frame
, 16);
137 if (lm_session_key
.data
== NULL
) {
139 return NT_STATUS_NO_MEMORY
;
142 /* not doing NTLM2 without a password */
143 *flags
&= ~CLI_CRED_NTLM2
;
144 } else if (*flags
& CLI_CRED_NTLMv2_AUTH
) {
146 if (!target_info
.length
) {
147 /* be lazy, match win2k - we can't do NTLMv2 without it */
148 DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n"));
150 return NT_STATUS_INVALID_PARAMETER
;
153 /* TODO: if the remote server is standalone, then we should replace 'domain'
154 with the server name as supplied above */
156 if (!SMBNTLMv2encrypt_hash(frame
,
159 nt_hash
->hash
, &challenge
,
160 server_timestamp
, &target_info
,
161 &lm_response
, &nt_response
,
162 NULL
, &session_key
)) {
164 return NT_STATUS_NO_MEMORY
;
167 /* LM Key is incompatible... */
168 *flags
&= ~CLI_CRED_LANMAN_AUTH
;
169 if (lm_response
.length
!= 0) {
171 * We should not expose the lm key.
173 memset(lm_response
.data
, 0, lm_response
.length
);
175 } else if (*flags
& CLI_CRED_NTLM2
) {
176 uint8_t session_nonce
[16];
177 uint8_t session_nonce_hash
[16];
178 uint8_t user_session_key
[16];
180 lm_response
= data_blob_talloc_zero(frame
, 24);
181 if (lm_response
.data
== NULL
) {
183 return NT_STATUS_NO_MEMORY
;
185 generate_random_buffer(lm_response
.data
, 8);
187 memcpy(session_nonce
, challenge
.data
, 8);
188 memcpy(&session_nonce
[8], lm_response
.data
, 8);
190 rc
= gnutls_hash_fast(GNUTLS_DIG_MD5
,
192 sizeof(session_nonce
),
195 return gnutls_error_to_ntstatus(rc
, NT_STATUS_NTLM_BLOCKED
);
198 DEBUG(5, ("NTLMSSP challenge set by NTLM2\n"));
199 DEBUG(5, ("challenge is: \n"));
200 dump_data(5, session_nonce_hash
, 8);
202 nt_response
= data_blob_talloc_zero(frame
, 24);
203 if (nt_response
.data
== NULL
) {
205 return NT_STATUS_NO_MEMORY
;
207 rc
= SMBOWFencrypt(nt_hash
->hash
,
212 return gnutls_error_to_ntstatus(rc
, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
215 ZERO_ARRAY(session_nonce_hash
);
217 session_key
= data_blob_talloc_zero(frame
, 16);
218 if (session_key
.data
== NULL
) {
220 return NT_STATUS_NO_MEMORY
;
223 SMBsesskeygen_ntv1(nt_hash
->hash
, user_session_key
);
225 rc
= gnutls_hmac_fast(GNUTLS_MAC_MD5
,
227 sizeof(user_session_key
),
229 sizeof(session_nonce
),
232 return gnutls_error_to_ntstatus(rc
, NT_STATUS_NTLM_BLOCKED
);
235 ZERO_ARRAY(user_session_key
);
237 dump_data_pw("NTLM2 session key:\n", session_key
.data
, session_key
.length
);
239 /* LM Key is incompatible... */
240 *flags
&= ~CLI_CRED_LANMAN_AUTH
;
242 const char *password
= cli_credentials_get_password(cred
);
246 nt_response
= data_blob_talloc_zero(frame
, 24);
247 if (nt_response
.data
== NULL
) {
249 return NT_STATUS_NO_MEMORY
;
251 rc
= SMBOWFencrypt(nt_hash
->hash
, challenge
.data
,
255 return gnutls_error_to_ntstatus(rc
, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
258 session_key
= data_blob_talloc_zero(frame
, 16);
259 if (session_key
.data
== NULL
) {
261 return NT_STATUS_NO_MEMORY
;
263 SMBsesskeygen_ntv1(nt_hash
->hash
, session_key
.data
);
264 dump_data_pw("NT session key:\n", session_key
.data
, session_key
.length
);
266 /* lanman auth is insecure, it may be disabled.
267 We may also not have a password */
269 if (password
!= NULL
) {
270 do_lm
= E_deshash(password
, lm_hash
);
273 if (*flags
& CLI_CRED_LANMAN_AUTH
&& do_lm
) {
274 lm_response
= data_blob_talloc_zero(frame
, 24);
275 if (lm_response
.data
== NULL
) {
276 ZERO_STRUCT(lm_hash
);
278 return NT_STATUS_NO_MEMORY
;
281 rc
= SMBencrypt_hash(lm_hash
,
285 ZERO_STRUCT(lm_hash
);
287 return gnutls_error_to_ntstatus(rc
, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
290 /* just copy the nt_response */
291 lm_response
= data_blob_dup_talloc(frame
, nt_response
);
292 if (lm_response
.data
== NULL
) {
293 ZERO_STRUCT(lm_hash
);
295 return NT_STATUS_NO_MEMORY
;
300 lm_session_key
= data_blob_talloc_zero(frame
, 16);
301 if (lm_session_key
.data
== NULL
) {
302 ZERO_STRUCT(lm_hash
);
304 return NT_STATUS_NO_MEMORY
;
306 memcpy(lm_session_key
.data
, lm_hash
, 8);
308 if (!(*flags
& CLI_CRED_NTLM_AUTH
)) {
309 memcpy(session_key
.data
, lm_session_key
.data
, 16);
311 ZERO_STRUCT(lm_hash
);
316 if (_lm_response
!= NULL
) {
317 talloc_steal(mem_ctx
, lm_response
.data
);
318 *_lm_response
= lm_response
;
320 data_blob_clear(&lm_response
);
322 if (_nt_response
!= NULL
) {
323 talloc_steal(mem_ctx
, nt_response
.data
);
324 *_nt_response
= nt_response
;
326 data_blob_clear(&nt_response
);
328 if (_lm_session_key
!= NULL
) {
329 talloc_steal(mem_ctx
, lm_session_key
.data
);
330 *_lm_session_key
= lm_session_key
;
332 data_blob_clear(&lm_session_key
);
334 if (_session_key
!= NULL
) {
335 talloc_steal(mem_ctx
, session_key
.data
);
336 *_session_key
= session_key
;
338 data_blob_clear(&session_key
);
345 * Set a utf16 password on the credentials context, including an indication
346 * of 'how' the password was obtained
348 * This is required because the nt_hash is calculated over the raw utf16 blob,
349 * which might not be completely valid utf16, which means the conversion
350 * from CH_UTF16MUNGED to CH_UTF8 might loose information.
352 _PUBLIC_
bool cli_credentials_set_utf16_password(struct cli_credentials
*cred
,
353 const DATA_BLOB
*password_utf16
,
354 enum credentials_obtained obtained
)
356 cred
->password_will_be_nt_hash
= false;
358 if (password_utf16
== NULL
) {
359 return cli_credentials_set_password(cred
, NULL
, obtained
);
362 if (obtained
>= cred
->password_obtained
) {
363 struct samr_Password
*nt_hash
= NULL
;
364 char *password_talloc
= NULL
;
365 size_t password_len
= 0;
368 nt_hash
= talloc(cred
, struct samr_Password
);
369 if (nt_hash
== NULL
) {
373 ok
= convert_string_talloc(cred
,
374 CH_UTF16MUNGED
, CH_UTF8
,
375 password_utf16
->data
,
376 password_utf16
->length
,
377 (void *)&password_talloc
,
380 TALLOC_FREE(nt_hash
);
384 ok
= cli_credentials_set_password(cred
, password_talloc
, obtained
);
385 TALLOC_FREE(password_talloc
);
387 TALLOC_FREE(nt_hash
);
391 mdfour(nt_hash
->hash
, password_utf16
->data
, password_utf16
->length
);
392 cred
->nt_hash
= nt_hash
;
400 * Set a old utf16 password on the credentials context.
402 * This is required because the nt_hash is calculated over the raw utf16 blob,
403 * which might not be completely valid utf16, which means the conversion
404 * from CH_UTF16MUNGED to CH_UTF8 might loose information.
406 _PUBLIC_
bool cli_credentials_set_old_utf16_password(struct cli_credentials
*cred
,
407 const DATA_BLOB
*password_utf16
)
409 struct samr_Password
*nt_hash
= NULL
;
410 char *password_talloc
= NULL
;
411 size_t password_len
= 0;
414 if (password_utf16
== NULL
) {
415 return cli_credentials_set_old_password(cred
, NULL
, CRED_SPECIFIED
);
418 nt_hash
= talloc(cred
, struct samr_Password
);
419 if (nt_hash
== NULL
) {
423 ok
= convert_string_talloc(cred
,
424 CH_UTF16MUNGED
, CH_UTF8
,
425 password_utf16
->data
,
426 password_utf16
->length
,
427 (void *)&password_talloc
,
430 TALLOC_FREE(nt_hash
);
434 ok
= cli_credentials_set_old_password(cred
, password_talloc
, CRED_SPECIFIED
);
435 TALLOC_FREE(password_talloc
);
437 TALLOC_FREE(nt_hash
);
441 mdfour(nt_hash
->hash
, password_utf16
->data
, password_utf16
->length
);
442 cred
->old_nt_hash
= nt_hash
;
446 _PUBLIC_
void cli_credentials_set_password_will_be_nt_hash(struct cli_credentials
*cred
,
450 * We set this here and the next cli_credentials_set_password()
451 * that resets the password or password callback
454 * cli_credentials_set_nt_hash() and
455 * cli_credentials_set_utf16_password() will reset this
458 cred
->password_will_be_nt_hash
= val
;
461 _PUBLIC_
bool cli_credentials_set_nt_hash(struct cli_credentials
*cred
,
462 const struct samr_Password
*nt_hash
,
463 enum credentials_obtained obtained
)
465 cred
->password_will_be_nt_hash
= false;
467 if (obtained
>= cred
->password_obtained
) {
468 cli_credentials_set_password(cred
, NULL
, obtained
);
470 cred
->nt_hash
= talloc(cred
, struct samr_Password
);
471 if (cred
->nt_hash
== NULL
) {
474 *cred
->nt_hash
= *nt_hash
;
476 cred
->nt_hash
= NULL
;
484 _PUBLIC_
bool cli_credentials_set_old_nt_hash(struct cli_credentials
*cred
,
485 const struct samr_Password
*nt_hash
)
487 cli_credentials_set_old_password(cred
, NULL
, CRED_SPECIFIED
);
489 cred
->old_nt_hash
= talloc(cred
, struct samr_Password
);
490 if (cred
->old_nt_hash
== NULL
) {
493 *cred
->old_nt_hash
= *nt_hash
;
495 cred
->old_nt_hash
= NULL
;
501 _PUBLIC_
bool cli_credentials_set_ntlm_response(struct cli_credentials
*cred
,
502 const DATA_BLOB
*lm_response
,
503 const DATA_BLOB
*lm_session_key
,
504 const DATA_BLOB
*nt_response
,
505 const DATA_BLOB
*nt_session_key
,
506 enum credentials_obtained obtained
)
508 if (obtained
>= cred
->password_obtained
) {
509 cli_credentials_set_password(cred
, NULL
, obtained
);
511 data_blob_clear_free(&cred
->lm_response
);
512 data_blob_clear_free(&cred
->lm_session_key
);
513 data_blob_clear_free(&cred
->nt_response
);
514 data_blob_clear_free(&cred
->nt_session_key
);
516 if (lm_response
!= NULL
&& lm_response
->length
!= 0) {
517 cred
->lm_response
= data_blob_talloc(cred
,
519 lm_response
->length
);
520 if (cred
->lm_response
.data
== NULL
) {
524 if (lm_session_key
!= NULL
&& lm_session_key
->length
!= 0) {
525 cred
->lm_session_key
= data_blob_talloc(cred
,
526 lm_session_key
->data
,
527 lm_session_key
->length
);
528 if (cred
->lm_session_key
.data
== NULL
) {
533 if (nt_response
!= NULL
&& nt_response
->length
!= 0) {
534 cred
->nt_response
= data_blob_talloc(cred
,
536 nt_response
->length
);
537 if (cred
->nt_response
.data
== NULL
) {
541 if (nt_session_key
!= NULL
&& nt_session_key
->length
!= 0) {
542 cred
->nt_session_key
= data_blob_talloc(cred
,
543 nt_session_key
->data
,
544 nt_session_key
->length
);
545 if (cred
->nt_session_key
.data
== NULL
) {