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 _PUBLIC_ NTSTATUS
cli_credentials_get_ntlm_response(struct cli_credentials
*cred
, TALLOC_CTX
*mem_ctx
,
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 TALLOC_CTX
*frame
= talloc_stackframe();
40 const char *user
= NULL
;
41 const char *domain
= NULL
;
42 DATA_BLOB lm_response
= data_blob_null
;
43 DATA_BLOB nt_response
= data_blob_null
;
44 DATA_BLOB lm_session_key
= data_blob_null
;
45 DATA_BLOB session_key
= data_blob_null
;
46 const struct samr_Password
*nt_hash
= NULL
;
48 if (cred
->use_kerberos
== CRED_MUST_USE_KERBEROS
) {
50 return NT_STATUS_INVALID_PARAMETER_MIX
;
53 /* We may already have an NTLM response we prepared earlier.
54 * This is used for NTLM pass-though authentication */
55 if (cred
->nt_response
.data
|| cred
->lm_response
.data
) {
56 if (cred
->nt_response
.length
!= 0) {
57 nt_response
= data_blob_dup_talloc(frame
,
59 if (nt_response
.data
== NULL
) {
61 return NT_STATUS_NO_MEMORY
;
64 if (cred
->lm_response
.length
!= 0) {
65 lm_response
= data_blob_dup_talloc(frame
,
67 if (lm_response
.data
== NULL
) {
69 return NT_STATUS_NO_MEMORY
;
73 if (cred
->lm_response
.data
== NULL
) {
74 *flags
= *flags
& ~CLI_CRED_LANMAN_AUTH
;
79 nt_hash
= cli_credentials_get_nt_hash(cred
, frame
);
81 cli_credentials_get_ntlm_username_domain(cred
, frame
, &user
, &domain
);
84 return NT_STATUS_NO_MEMORY
;
88 return NT_STATUS_NO_MEMORY
;
91 /* If we are sending a username@realm login (see function
92 * above), then we will not send LM, it will not be
94 if (cred
->principal_obtained
> cred
->username_obtained
) {
95 *flags
= *flags
& ~CLI_CRED_LANMAN_AUTH
;
98 /* Likewise if we are a machine account (avoid protocol downgrade attacks) */
99 if (cred
->machine_account
) {
100 *flags
= *flags
& ~CLI_CRED_LANMAN_AUTH
;
104 /* do nothing - blobs are zero length */
106 /* session key is all zeros */
107 session_key
= data_blob_talloc_zero(frame
, 16);
108 if (session_key
.data
== NULL
) {
110 return NT_STATUS_NO_MEMORY
;
112 lm_session_key
= data_blob_talloc_zero(frame
, 16);
113 if (lm_session_key
.data
== NULL
) {
115 return NT_STATUS_NO_MEMORY
;
118 /* not doing NTLM2 without a password */
119 *flags
&= ~CLI_CRED_NTLM2
;
120 } else if (*flags
& CLI_CRED_NTLMv2_AUTH
) {
122 if (!target_info
.length
) {
123 /* be lazy, match win2k - we can't do NTLMv2 without it */
124 DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n"));
126 return NT_STATUS_INVALID_PARAMETER
;
129 /* TODO: if the remote server is standalone, then we should replace 'domain'
130 with the server name as supplied above */
132 if (!SMBNTLMv2encrypt_hash(frame
,
135 nt_hash
->hash
, &challenge
,
136 server_timestamp
, &target_info
,
137 &lm_response
, &nt_response
,
138 NULL
, &session_key
)) {
140 return NT_STATUS_NO_MEMORY
;
143 /* LM Key is incompatible... */
144 *flags
&= ~CLI_CRED_LANMAN_AUTH
;
145 if (lm_response
.length
!= 0) {
147 * We should not expose the lm key.
149 memset(lm_response
.data
, 0, lm_response
.length
);
151 } else if (*flags
& CLI_CRED_NTLM2
) {
152 MD5_CTX md5_session_nonce_ctx
;
153 uint8_t session_nonce
[16];
154 uint8_t session_nonce_hash
[16];
155 uint8_t user_session_key
[16];
157 lm_response
= data_blob_talloc_zero(frame
, 24);
158 if (lm_response
.data
== NULL
) {
160 return NT_STATUS_NO_MEMORY
;
162 generate_random_buffer(lm_response
.data
, 8);
164 memcpy(session_nonce
, challenge
.data
, 8);
165 memcpy(&session_nonce
[8], lm_response
.data
, 8);
167 MD5Init(&md5_session_nonce_ctx
);
168 MD5Update(&md5_session_nonce_ctx
, session_nonce
,
169 sizeof(session_nonce
));
170 MD5Final(session_nonce_hash
, &md5_session_nonce_ctx
);
172 DEBUG(5, ("NTLMSSP challenge set by NTLM2\n"));
173 DEBUG(5, ("challenge is: \n"));
174 dump_data(5, session_nonce_hash
, 8);
176 nt_response
= data_blob_talloc_zero(frame
, 24);
177 if (nt_response
.data
== NULL
) {
179 return NT_STATUS_NO_MEMORY
;
181 SMBOWFencrypt(nt_hash
->hash
,
185 session_key
= data_blob_talloc_zero(frame
, 16);
186 if (session_key
.data
== NULL
) {
188 return NT_STATUS_NO_MEMORY
;
191 SMBsesskeygen_ntv1(nt_hash
->hash
, user_session_key
);
192 hmac_md5(user_session_key
, session_nonce
, sizeof(session_nonce
), session_key
.data
);
193 ZERO_STRUCT(user_session_key
);
194 dump_data_pw("NTLM2 session key:\n", session_key
.data
, session_key
.length
);
196 /* LM Key is incompatible... */
197 *flags
&= ~CLI_CRED_LANMAN_AUTH
;
199 const char *password
= cli_credentials_get_password(cred
);
203 nt_response
= data_blob_talloc_zero(frame
, 24);
204 if (nt_response
.data
== NULL
) {
206 return NT_STATUS_NO_MEMORY
;
208 SMBOWFencrypt(nt_hash
->hash
, challenge
.data
,
211 session_key
= data_blob_talloc_zero(frame
, 16);
212 if (session_key
.data
== NULL
) {
214 return NT_STATUS_NO_MEMORY
;
216 SMBsesskeygen_ntv1(nt_hash
->hash
, session_key
.data
);
217 dump_data_pw("NT session key:\n", session_key
.data
, session_key
.length
);
219 /* lanman auth is insecure, it may be disabled.
220 We may also not have a password */
222 if (password
!= NULL
) {
223 do_lm
= E_deshash(password
, lm_hash
);
226 if (*flags
& CLI_CRED_LANMAN_AUTH
&& do_lm
) {
227 lm_response
= data_blob_talloc_zero(frame
, 24);
228 if (lm_response
.data
== NULL
) {
229 ZERO_STRUCT(lm_hash
);
231 return NT_STATUS_NO_MEMORY
;
234 SMBencrypt_hash(lm_hash
,
238 /* just copy the nt_response */
239 lm_response
= data_blob_dup_talloc(frame
, nt_response
);
240 if (lm_response
.data
== NULL
) {
241 ZERO_STRUCT(lm_hash
);
243 return NT_STATUS_NO_MEMORY
;
248 lm_session_key
= data_blob_talloc_zero(frame
, 16);
249 if (lm_session_key
.data
== NULL
) {
250 ZERO_STRUCT(lm_hash
);
252 return NT_STATUS_NO_MEMORY
;
254 memcpy(lm_session_key
.data
, lm_hash
, 8);
256 if (!(*flags
& CLI_CRED_NTLM_AUTH
)) {
257 memcpy(session_key
.data
, lm_session_key
.data
, 16);
259 ZERO_STRUCT(lm_hash
);
264 if (_lm_response
!= NULL
) {
265 talloc_steal(mem_ctx
, lm_response
.data
);
266 *_lm_response
= lm_response
;
268 data_blob_clear(&lm_response
);
270 if (_nt_response
!= NULL
) {
271 talloc_steal(mem_ctx
, nt_response
.data
);
272 *_nt_response
= nt_response
;
274 data_blob_clear(&nt_response
);
276 if (_lm_session_key
!= NULL
) {
277 talloc_steal(mem_ctx
, lm_session_key
.data
);
278 *_lm_session_key
= lm_session_key
;
280 data_blob_clear(&lm_session_key
);
282 if (_session_key
!= NULL
) {
283 talloc_steal(mem_ctx
, session_key
.data
);
284 *_session_key
= session_key
;
286 data_blob_clear(&session_key
);
293 * Set a utf16 password on the credentials context, including an indication
294 * of 'how' the password was obtained
296 * This is required because the nt_hash is calculated over the raw utf16 blob,
297 * which might not be completely valid utf16, which means the conversion
298 * from CH_UTF16MUNGED to CH_UTF8 might loose information.
300 _PUBLIC_
bool cli_credentials_set_utf16_password(struct cli_credentials
*cred
,
301 const DATA_BLOB
*password_utf16
,
302 enum credentials_obtained obtained
)
304 cred
->password_will_be_nt_hash
= false;
306 if (password_utf16
== NULL
) {
307 return cli_credentials_set_password(cred
, NULL
, obtained
);
310 if (obtained
>= cred
->password_obtained
) {
311 struct samr_Password
*nt_hash
= NULL
;
312 char *password_talloc
= NULL
;
313 size_t password_len
= 0;
316 nt_hash
= talloc(cred
, struct samr_Password
);
317 if (nt_hash
== NULL
) {
321 ok
= convert_string_talloc(cred
,
322 CH_UTF16MUNGED
, CH_UTF8
,
323 password_utf16
->data
,
324 password_utf16
->length
,
325 (void *)&password_talloc
,
328 TALLOC_FREE(nt_hash
);
332 ok
= cli_credentials_set_password(cred
, password_talloc
, obtained
);
333 TALLOC_FREE(password_talloc
);
335 TALLOC_FREE(nt_hash
);
339 mdfour(nt_hash
->hash
, password_utf16
->data
, password_utf16
->length
);
340 cred
->nt_hash
= nt_hash
;
348 * Set a old utf16 password on the credentials context.
350 * This is required because the nt_hash is calculated over the raw utf16 blob,
351 * which might not be completely valid utf16, which means the conversion
352 * from CH_UTF16MUNGED to CH_UTF8 might loose information.
354 _PUBLIC_
bool cli_credentials_set_old_utf16_password(struct cli_credentials
*cred
,
355 const DATA_BLOB
*password_utf16
)
357 struct samr_Password
*nt_hash
= NULL
;
358 char *password_talloc
= NULL
;
359 size_t password_len
= 0;
362 if (password_utf16
== NULL
) {
363 return cli_credentials_set_old_password(cred
, NULL
, CRED_SPECIFIED
);
366 nt_hash
= talloc(cred
, struct samr_Password
);
367 if (nt_hash
== NULL
) {
371 ok
= convert_string_talloc(cred
,
372 CH_UTF16MUNGED
, CH_UTF8
,
373 password_utf16
->data
,
374 password_utf16
->length
,
375 (void *)&password_talloc
,
378 TALLOC_FREE(nt_hash
);
382 ok
= cli_credentials_set_old_password(cred
, password_talloc
, CRED_SPECIFIED
);
383 TALLOC_FREE(password_talloc
);
385 TALLOC_FREE(nt_hash
);
389 mdfour(nt_hash
->hash
, password_utf16
->data
, password_utf16
->length
);
390 cred
->old_nt_hash
= nt_hash
;
394 _PUBLIC_
void cli_credentials_set_password_will_be_nt_hash(struct cli_credentials
*cred
,
398 * We set this here and the next cli_credentials_set_password()
399 * that resets the password or password callback
402 * cli_credentials_set_nt_hash() and
403 * cli_credentials_set_utf16_password() will reset this
406 cred
->password_will_be_nt_hash
= val
;
409 _PUBLIC_
bool cli_credentials_set_nt_hash(struct cli_credentials
*cred
,
410 const struct samr_Password
*nt_hash
,
411 enum credentials_obtained obtained
)
413 cred
->password_will_be_nt_hash
= false;
415 if (obtained
>= cred
->password_obtained
) {
416 cli_credentials_set_password(cred
, NULL
, obtained
);
418 cred
->nt_hash
= talloc(cred
, struct samr_Password
);
419 if (cred
->nt_hash
== NULL
) {
422 *cred
->nt_hash
= *nt_hash
;
424 cred
->nt_hash
= NULL
;
432 _PUBLIC_
bool cli_credentials_set_old_nt_hash(struct cli_credentials
*cred
,
433 const struct samr_Password
*nt_hash
)
435 cli_credentials_set_old_password(cred
, NULL
, CRED_SPECIFIED
);
437 cred
->old_nt_hash
= talloc(cred
, struct samr_Password
);
438 if (cred
->old_nt_hash
== NULL
) {
441 *cred
->old_nt_hash
= *nt_hash
;
443 cred
->old_nt_hash
= NULL
;
449 _PUBLIC_
bool cli_credentials_set_ntlm_response(struct cli_credentials
*cred
,
450 const DATA_BLOB
*lm_response
,
451 const DATA_BLOB
*nt_response
,
452 enum credentials_obtained obtained
)
454 if (obtained
>= cred
->password_obtained
) {
455 cli_credentials_set_password(cred
, NULL
, obtained
);
457 cred
->nt_response
= data_blob_talloc(cred
, nt_response
->data
, nt_response
->length
);
458 talloc_steal(cred
, cred
->nt_response
.data
);
461 cred
->lm_response
= data_blob_talloc(cred
, lm_response
->data
, lm_response
->length
);