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"
32 #define DBGC_CLASS DBGC_AUTH
34 _PUBLIC_ NTSTATUS
cli_credentials_get_ntlm_response(struct cli_credentials
*cred
, TALLOC_CTX
*mem_ctx
,
37 const NTTIME
*server_timestamp
,
38 DATA_BLOB target_info
,
39 DATA_BLOB
*_lm_response
, DATA_BLOB
*_nt_response
,
40 DATA_BLOB
*_lm_session_key
, DATA_BLOB
*_session_key
)
42 TALLOC_CTX
*frame
= talloc_stackframe();
43 const char *user
= NULL
;
44 const char *domain
= NULL
;
45 DATA_BLOB lm_response
= data_blob_null
;
46 DATA_BLOB nt_response
= data_blob_null
;
47 DATA_BLOB lm_session_key
= data_blob_null
;
48 DATA_BLOB session_key
= data_blob_null
;
49 const struct samr_Password
*nt_hash
= NULL
;
51 if (cred
->use_kerberos
== CRED_MUST_USE_KERBEROS
) {
53 return NT_STATUS_INVALID_PARAMETER_MIX
;
56 /* We may already have an NTLM response we prepared earlier.
57 * This is used for NTLM pass-though authentication */
58 if (cred
->nt_response
.data
|| cred
->lm_response
.data
) {
59 if (cred
->nt_response
.length
!= 0) {
60 nt_response
= data_blob_dup_talloc(frame
,
62 if (nt_response
.data
== NULL
) {
64 return NT_STATUS_NO_MEMORY
;
67 if (cred
->lm_response
.length
!= 0) {
68 lm_response
= data_blob_dup_talloc(frame
,
70 if (lm_response
.data
== NULL
) {
72 return NT_STATUS_NO_MEMORY
;
76 if (cred
->lm_response
.data
== NULL
) {
77 *flags
= *flags
& ~CLI_CRED_LANMAN_AUTH
;
82 nt_hash
= cli_credentials_get_nt_hash(cred
, frame
);
84 cli_credentials_get_ntlm_username_domain(cred
, frame
, &user
, &domain
);
87 return NT_STATUS_NO_MEMORY
;
91 return NT_STATUS_NO_MEMORY
;
94 /* If we are sending a username@realm login (see function
95 * above), then we will not send LM, it will not be
97 if (cred
->principal_obtained
> cred
->username_obtained
) {
98 *flags
= *flags
& ~CLI_CRED_LANMAN_AUTH
;
101 /* Likewise if we are a machine account (avoid protocol downgrade attacks) */
102 if (cred
->machine_account
) {
103 *flags
= *flags
& ~CLI_CRED_LANMAN_AUTH
;
107 /* do nothing - blobs are zero length */
109 /* session key is all zeros */
110 session_key
= data_blob_talloc_zero(frame
, 16);
111 if (session_key
.data
== NULL
) {
113 return NT_STATUS_NO_MEMORY
;
115 lm_session_key
= data_blob_talloc_zero(frame
, 16);
116 if (lm_session_key
.data
== NULL
) {
118 return NT_STATUS_NO_MEMORY
;
121 /* not doing NTLM2 without a password */
122 *flags
&= ~CLI_CRED_NTLM2
;
123 } else if (*flags
& CLI_CRED_NTLMv2_AUTH
) {
125 if (!target_info
.length
) {
126 /* be lazy, match win2k - we can't do NTLMv2 without it */
127 DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n"));
129 return NT_STATUS_INVALID_PARAMETER
;
132 /* TODO: if the remote server is standalone, then we should replace 'domain'
133 with the server name as supplied above */
135 if (!SMBNTLMv2encrypt_hash(frame
,
138 nt_hash
->hash
, &challenge
,
139 server_timestamp
, &target_info
,
140 &lm_response
, &nt_response
,
141 NULL
, &session_key
)) {
143 return NT_STATUS_NO_MEMORY
;
146 /* LM Key is incompatible... */
147 *flags
&= ~CLI_CRED_LANMAN_AUTH
;
148 if (lm_response
.length
!= 0) {
150 * We should not expose the lm key.
152 memset(lm_response
.data
, 0, lm_response
.length
);
154 } else if (*flags
& CLI_CRED_NTLM2
) {
155 MD5_CTX md5_session_nonce_ctx
;
156 uint8_t session_nonce
[16];
157 uint8_t session_nonce_hash
[16];
158 uint8_t user_session_key
[16];
160 lm_response
= data_blob_talloc_zero(frame
, 24);
161 if (lm_response
.data
== NULL
) {
163 return NT_STATUS_NO_MEMORY
;
165 generate_random_buffer(lm_response
.data
, 8);
167 memcpy(session_nonce
, challenge
.data
, 8);
168 memcpy(&session_nonce
[8], lm_response
.data
, 8);
170 MD5Init(&md5_session_nonce_ctx
);
171 MD5Update(&md5_session_nonce_ctx
, session_nonce
,
172 sizeof(session_nonce
));
173 MD5Final(session_nonce_hash
, &md5_session_nonce_ctx
);
175 DEBUG(5, ("NTLMSSP challenge set by NTLM2\n"));
176 DEBUG(5, ("challenge is: \n"));
177 dump_data(5, session_nonce_hash
, 8);
179 nt_response
= data_blob_talloc_zero(frame
, 24);
180 if (nt_response
.data
== NULL
) {
182 return NT_STATUS_NO_MEMORY
;
184 SMBOWFencrypt(nt_hash
->hash
,
188 session_key
= data_blob_talloc_zero(frame
, 16);
189 if (session_key
.data
== NULL
) {
191 return NT_STATUS_NO_MEMORY
;
194 SMBsesskeygen_ntv1(nt_hash
->hash
, user_session_key
);
195 hmac_md5(user_session_key
, session_nonce
, sizeof(session_nonce
), session_key
.data
);
196 ZERO_STRUCT(user_session_key
);
197 dump_data_pw("NTLM2 session key:\n", session_key
.data
, session_key
.length
);
199 /* LM Key is incompatible... */
200 *flags
&= ~CLI_CRED_LANMAN_AUTH
;
202 const char *password
= cli_credentials_get_password(cred
);
206 nt_response
= data_blob_talloc_zero(frame
, 24);
207 if (nt_response
.data
== NULL
) {
209 return NT_STATUS_NO_MEMORY
;
211 SMBOWFencrypt(nt_hash
->hash
, challenge
.data
,
214 session_key
= data_blob_talloc_zero(frame
, 16);
215 if (session_key
.data
== NULL
) {
217 return NT_STATUS_NO_MEMORY
;
219 SMBsesskeygen_ntv1(nt_hash
->hash
, session_key
.data
);
220 dump_data_pw("NT session key:\n", session_key
.data
, session_key
.length
);
222 /* lanman auth is insecure, it may be disabled.
223 We may also not have a password */
225 if (password
!= NULL
) {
226 do_lm
= E_deshash(password
, lm_hash
);
229 if (*flags
& CLI_CRED_LANMAN_AUTH
&& do_lm
) {
230 lm_response
= data_blob_talloc_zero(frame
, 24);
231 if (lm_response
.data
== NULL
) {
232 ZERO_STRUCT(lm_hash
);
234 return NT_STATUS_NO_MEMORY
;
237 SMBencrypt_hash(lm_hash
,
241 /* just copy the nt_response */
242 lm_response
= data_blob_dup_talloc(frame
, nt_response
);
243 if (lm_response
.data
== NULL
) {
244 ZERO_STRUCT(lm_hash
);
246 return NT_STATUS_NO_MEMORY
;
251 lm_session_key
= data_blob_talloc_zero(frame
, 16);
252 if (lm_session_key
.data
== NULL
) {
253 ZERO_STRUCT(lm_hash
);
255 return NT_STATUS_NO_MEMORY
;
257 memcpy(lm_session_key
.data
, lm_hash
, 8);
259 if (!(*flags
& CLI_CRED_NTLM_AUTH
)) {
260 memcpy(session_key
.data
, lm_session_key
.data
, 16);
262 ZERO_STRUCT(lm_hash
);
267 if (_lm_response
!= NULL
) {
268 talloc_steal(mem_ctx
, lm_response
.data
);
269 *_lm_response
= lm_response
;
271 data_blob_clear(&lm_response
);
273 if (_nt_response
!= NULL
) {
274 talloc_steal(mem_ctx
, nt_response
.data
);
275 *_nt_response
= nt_response
;
277 data_blob_clear(&nt_response
);
279 if (_lm_session_key
!= NULL
) {
280 talloc_steal(mem_ctx
, lm_session_key
.data
);
281 *_lm_session_key
= lm_session_key
;
283 data_blob_clear(&lm_session_key
);
285 if (_session_key
!= NULL
) {
286 talloc_steal(mem_ctx
, session_key
.data
);
287 *_session_key
= session_key
;
289 data_blob_clear(&session_key
);
296 * Set a utf16 password on the credentials context, including an indication
297 * of 'how' the password was obtained
299 * This is required because the nt_hash is calculated over the raw utf16 blob,
300 * which might not be completely valid utf16, which means the conversion
301 * from CH_UTF16MUNGED to CH_UTF8 might loose information.
303 _PUBLIC_
bool cli_credentials_set_utf16_password(struct cli_credentials
*cred
,
304 const DATA_BLOB
*password_utf16
,
305 enum credentials_obtained obtained
)
307 cred
->password_will_be_nt_hash
= false;
309 if (password_utf16
== NULL
) {
310 return cli_credentials_set_password(cred
, NULL
, obtained
);
313 if (obtained
>= cred
->password_obtained
) {
314 struct samr_Password
*nt_hash
= NULL
;
315 char *password_talloc
= NULL
;
316 size_t password_len
= 0;
319 nt_hash
= talloc(cred
, struct samr_Password
);
320 if (nt_hash
== NULL
) {
324 ok
= convert_string_talloc(cred
,
325 CH_UTF16MUNGED
, CH_UTF8
,
326 password_utf16
->data
,
327 password_utf16
->length
,
328 (void *)&password_talloc
,
331 TALLOC_FREE(nt_hash
);
335 ok
= cli_credentials_set_password(cred
, password_talloc
, obtained
);
336 TALLOC_FREE(password_talloc
);
338 TALLOC_FREE(nt_hash
);
342 mdfour(nt_hash
->hash
, password_utf16
->data
, password_utf16
->length
);
343 cred
->nt_hash
= nt_hash
;
351 * Set a old utf16 password on the credentials context.
353 * This is required because the nt_hash is calculated over the raw utf16 blob,
354 * which might not be completely valid utf16, which means the conversion
355 * from CH_UTF16MUNGED to CH_UTF8 might loose information.
357 _PUBLIC_
bool cli_credentials_set_old_utf16_password(struct cli_credentials
*cred
,
358 const DATA_BLOB
*password_utf16
)
360 struct samr_Password
*nt_hash
= NULL
;
361 char *password_talloc
= NULL
;
362 size_t password_len
= 0;
365 if (password_utf16
== NULL
) {
366 return cli_credentials_set_old_password(cred
, NULL
, CRED_SPECIFIED
);
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_old_password(cred
, password_talloc
, CRED_SPECIFIED
);
386 TALLOC_FREE(password_talloc
);
388 TALLOC_FREE(nt_hash
);
392 mdfour(nt_hash
->hash
, password_utf16
->data
, password_utf16
->length
);
393 cred
->old_nt_hash
= nt_hash
;
397 _PUBLIC_
void cli_credentials_set_password_will_be_nt_hash(struct cli_credentials
*cred
,
401 * We set this here and the next cli_credentials_set_password()
402 * that resets the password or password callback
405 * cli_credentials_set_nt_hash() and
406 * cli_credentials_set_utf16_password() will reset this
409 cred
->password_will_be_nt_hash
= val
;
412 _PUBLIC_
bool cli_credentials_set_nt_hash(struct cli_credentials
*cred
,
413 const struct samr_Password
*nt_hash
,
414 enum credentials_obtained obtained
)
416 cred
->password_will_be_nt_hash
= false;
418 if (obtained
>= cred
->password_obtained
) {
419 cli_credentials_set_password(cred
, NULL
, obtained
);
421 cred
->nt_hash
= talloc(cred
, struct samr_Password
);
422 if (cred
->nt_hash
== NULL
) {
425 *cred
->nt_hash
= *nt_hash
;
427 cred
->nt_hash
= NULL
;
435 _PUBLIC_
bool cli_credentials_set_old_nt_hash(struct cli_credentials
*cred
,
436 const struct samr_Password
*nt_hash
)
438 cli_credentials_set_old_password(cred
, NULL
, CRED_SPECIFIED
);
440 cred
->old_nt_hash
= talloc(cred
, struct samr_Password
);
441 if (cred
->old_nt_hash
== NULL
) {
444 *cred
->old_nt_hash
= *nt_hash
;
446 cred
->old_nt_hash
= NULL
;
452 _PUBLIC_
bool cli_credentials_set_ntlm_response(struct cli_credentials
*cred
,
453 const DATA_BLOB
*lm_response
,
454 const DATA_BLOB
*nt_response
,
455 enum credentials_obtained obtained
)
457 if (obtained
>= cred
->password_obtained
) {
458 cli_credentials_set_password(cred
, NULL
, obtained
);
460 cred
->nt_response
= data_blob_talloc(cred
, nt_response
->data
, nt_response
->length
);
461 talloc_steal(cred
, cred
->nt_response
.data
);
464 cred
->lm_response
= data_blob_talloc(cred
, lm_response
->data
, lm_response
->length
);