Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : User credentials handling
5 :
6 : Copyright (C) Andrew Tridgell 2001
7 : Copyright (C) Andrew Bartlett <abartlet@samba.org> 2001-2005
8 : Copyright (C) Stefan Metzmacher 2005
9 :
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.
14 :
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.
19 :
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/>.
22 : */
23 :
24 : #include "includes.h"
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"
30 :
31 : #include "lib/crypto/gnutls_helpers.h"
32 : #include <gnutls/gnutls.h>
33 : #include <gnutls/crypto.h>
34 :
35 : #undef DBGC_CLASS
36 : #define DBGC_CLASS DBGC_AUTH
37 :
38 40550 : _PUBLIC_ NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred, TALLOC_CTX *mem_ctx,
39 : int *flags,
40 : DATA_BLOB challenge,
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)
45 : {
46 40550 : TALLOC_CTX *frame = talloc_stackframe();
47 40550 : const char *user = NULL;
48 40550 : const char *domain = NULL;
49 40550 : DATA_BLOB lm_response = data_blob_null;
50 40550 : DATA_BLOB nt_response = data_blob_null;
51 40550 : DATA_BLOB lm_session_key = data_blob_null;
52 40550 : DATA_BLOB session_key = data_blob_null;
53 40550 : const struct samr_Password *nt_hash = NULL;
54 514 : int rc;
55 :
56 40550 : if (cred->kerberos_state == CRED_USE_KERBEROS_REQUIRED) {
57 0 : TALLOC_FREE(frame);
58 0 : return NT_STATUS_INVALID_PARAMETER_MIX;
59 : }
60 :
61 : /* We may already have an NTLM response we prepared earlier.
62 : * This is used for NTLM pass-though authentication */
63 40550 : if (cred->nt_response.data || cred->lm_response.data) {
64 12 : if (cred->nt_response.length != 0) {
65 12 : nt_response = data_blob_dup_talloc(frame,
66 : cred->nt_response);
67 12 : if (nt_response.data == NULL) {
68 0 : TALLOC_FREE(frame);
69 0 : return NT_STATUS_NO_MEMORY;
70 : }
71 : }
72 12 : if (cred->nt_session_key.length != 0) {
73 12 : session_key = data_blob_dup_talloc(frame,
74 : cred->nt_session_key);
75 12 : if (session_key.data == NULL) {
76 0 : TALLOC_FREE(frame);
77 0 : return NT_STATUS_NO_MEMORY;
78 : }
79 : }
80 12 : if (cred->lm_response.length != 0) {
81 12 : lm_response = data_blob_dup_talloc(frame,
82 : cred->lm_response);
83 12 : if (lm_response.data == NULL) {
84 0 : TALLOC_FREE(frame);
85 0 : return NT_STATUS_NO_MEMORY;
86 : }
87 : }
88 12 : if (cred->lm_session_key.length != 0) {
89 12 : lm_session_key = data_blob_dup_talloc(frame,
90 : cred->lm_session_key);
91 12 : if (lm_session_key.data == NULL) {
92 0 : TALLOC_FREE(frame);
93 0 : return NT_STATUS_NO_MEMORY;
94 : }
95 : }
96 :
97 12 : if (cred->lm_response.data == NULL) {
98 0 : *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
99 : }
100 12 : goto done;
101 : }
102 :
103 40538 : nt_hash = cli_credentials_get_nt_hash(cred, frame);
104 :
105 40538 : cli_credentials_get_ntlm_username_domain(cred, frame, &user, &domain);
106 40538 : if (user == NULL) {
107 0 : TALLOC_FREE(frame);
108 0 : return NT_STATUS_NO_MEMORY;
109 : }
110 40538 : if (domain == NULL) {
111 0 : TALLOC_FREE(frame);
112 0 : return NT_STATUS_NO_MEMORY;
113 : }
114 :
115 : /* If we are sending a username@realm login (see function
116 : * above), then we will not send LM, it will not be
117 : * accepted */
118 40538 : if (cred->principal_obtained > cred->username_obtained) {
119 0 : *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
120 : }
121 :
122 : /* Likewise if we are a machine account (avoid protocol downgrade attacks) */
123 40538 : if (cred->machine_account) {
124 156 : *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
125 : }
126 :
127 40538 : if (!nt_hash) {
128 : /* do nothing - blobs are zero length */
129 :
130 : /* session key is all zeros */
131 1079 : session_key = data_blob_talloc_zero(frame, 16);
132 1079 : if (session_key.data == NULL) {
133 0 : TALLOC_FREE(frame);
134 0 : return NT_STATUS_NO_MEMORY;
135 : }
136 1079 : lm_session_key = data_blob_talloc_zero(frame, 16);
137 1079 : if (lm_session_key.data == NULL) {
138 0 : TALLOC_FREE(frame);
139 0 : return NT_STATUS_NO_MEMORY;
140 : }
141 :
142 : /* not doing NTLM2 without a password */
143 1079 : *flags &= ~CLI_CRED_NTLM2;
144 39459 : } else if (*flags & CLI_CRED_NTLMv2_AUTH) {
145 :
146 38490 : if (!target_info.length) {
147 : /* be lazy, match win2k - we can't do NTLMv2 without it */
148 0 : DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n"));
149 0 : TALLOC_FREE(frame);
150 0 : return NT_STATUS_INVALID_PARAMETER;
151 : }
152 :
153 : /* TODO: if the remote server is standalone, then we should replace 'domain'
154 : with the server name as supplied above */
155 :
156 38490 : if (!SMBNTLMv2encrypt_hash(frame,
157 : user,
158 : domain,
159 38490 : nt_hash->hash, &challenge,
160 : server_timestamp, &target_info,
161 : &lm_response, &nt_response,
162 : NULL, &session_key)) {
163 0 : TALLOC_FREE(frame);
164 0 : return NT_STATUS_NO_MEMORY;
165 : }
166 :
167 : /* LM Key is incompatible... */
168 38490 : *flags &= ~CLI_CRED_LANMAN_AUTH;
169 38490 : if (lm_response.length != 0) {
170 : /*
171 : * We should not expose the lm key.
172 : */
173 38490 : memset(lm_response.data, 0, lm_response.length);
174 : }
175 969 : } else if (*flags & CLI_CRED_NTLM2) {
176 1 : uint8_t session_nonce[16];
177 1 : uint8_t session_nonce_hash[16];
178 1 : uint8_t user_session_key[16];
179 :
180 170 : lm_response = data_blob_talloc_zero(frame, 24);
181 170 : if (lm_response.data == NULL) {
182 0 : TALLOC_FREE(frame);
183 0 : return NT_STATUS_NO_MEMORY;
184 : }
185 170 : generate_random_buffer(lm_response.data, 8);
186 :
187 170 : memcpy(session_nonce, challenge.data, 8);
188 170 : memcpy(&session_nonce[8], lm_response.data, 8);
189 :
190 170 : rc = gnutls_hash_fast(GNUTLS_DIG_MD5,
191 : session_nonce,
192 : sizeof(session_nonce),
193 : session_nonce_hash);
194 170 : if (rc < 0) {
195 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED);
196 : }
197 :
198 170 : DEBUG(5, ("NTLMSSP challenge set by NTLM2\n"));
199 170 : DEBUG(5, ("challenge is: \n"));
200 170 : dump_data(5, session_nonce_hash, 8);
201 :
202 170 : nt_response = data_blob_talloc_zero(frame, 24);
203 170 : if (nt_response.data == NULL) {
204 0 : TALLOC_FREE(frame);
205 0 : return NT_STATUS_NO_MEMORY;
206 : }
207 170 : rc = SMBOWFencrypt(nt_hash->hash,
208 : session_nonce_hash,
209 : nt_response.data);
210 170 : if (rc != 0) {
211 0 : TALLOC_FREE(frame);
212 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
213 : }
214 :
215 170 : ZERO_ARRAY(session_nonce_hash);
216 :
217 170 : session_key = data_blob_talloc_zero(frame, 16);
218 170 : if (session_key.data == NULL) {
219 0 : TALLOC_FREE(frame);
220 0 : return NT_STATUS_NO_MEMORY;
221 : }
222 :
223 170 : SMBsesskeygen_ntv1(nt_hash->hash, user_session_key);
224 :
225 171 : rc = gnutls_hmac_fast(GNUTLS_MAC_MD5,
226 : user_session_key,
227 : sizeof(user_session_key),
228 : session_nonce,
229 : sizeof(session_nonce),
230 170 : session_key.data);
231 170 : if (rc < 0) {
232 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED);
233 : }
234 :
235 170 : ZERO_ARRAY(user_session_key);
236 :
237 170 : dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);
238 :
239 : /* LM Key is incompatible... */
240 170 : *flags &= ~CLI_CRED_LANMAN_AUTH;
241 : } else {
242 799 : const char *password = cli_credentials_get_password(cred);
243 9 : uint8_t lm_hash[16];
244 799 : bool do_lm = false;
245 :
246 799 : nt_response = data_blob_talloc_zero(frame, 24);
247 799 : if (nt_response.data == NULL) {
248 0 : TALLOC_FREE(frame);
249 0 : return NT_STATUS_NO_MEMORY;
250 : }
251 799 : rc = SMBOWFencrypt(nt_hash->hash, challenge.data,
252 : nt_response.data);
253 799 : if (rc != 0) {
254 0 : TALLOC_FREE(frame);
255 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
256 : }
257 :
258 799 : session_key = data_blob_talloc_zero(frame, 16);
259 799 : if (session_key.data == NULL) {
260 0 : TALLOC_FREE(frame);
261 0 : return NT_STATUS_NO_MEMORY;
262 : }
263 799 : SMBsesskeygen_ntv1(nt_hash->hash, session_key.data);
264 799 : dump_data_pw("NT session key:\n", session_key.data, session_key.length);
265 :
266 : /* lanman auth is insecure, it may be disabled.
267 : We may also not have a password */
268 :
269 799 : if (password != NULL) {
270 798 : do_lm = E_deshash(password, lm_hash);
271 : }
272 :
273 799 : if (*flags & CLI_CRED_LANMAN_AUTH && do_lm) {
274 677 : lm_response = data_blob_talloc_zero(frame, 24);
275 677 : if (lm_response.data == NULL) {
276 0 : ZERO_STRUCT(lm_hash);
277 0 : TALLOC_FREE(frame);
278 0 : return NT_STATUS_NO_MEMORY;
279 : }
280 :
281 679 : rc = SMBencrypt_hash(lm_hash,
282 677 : challenge.data,
283 : lm_response.data);
284 677 : if (rc != 0) {
285 0 : ZERO_STRUCT(lm_hash);
286 0 : TALLOC_FREE(frame);
287 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
288 : }
289 : } else {
290 : /* just copy the nt_response */
291 122 : lm_response = data_blob_dup_talloc(frame, nt_response);
292 122 : if (lm_response.data == NULL) {
293 0 : ZERO_STRUCT(lm_hash);
294 0 : TALLOC_FREE(frame);
295 0 : return NT_STATUS_NO_MEMORY;
296 : }
297 : }
298 :
299 799 : if (do_lm) {
300 696 : lm_session_key = data_blob_talloc_zero(frame, 16);
301 696 : if (lm_session_key.data == NULL) {
302 0 : ZERO_STRUCT(lm_hash);
303 0 : TALLOC_FREE(frame);
304 0 : return NT_STATUS_NO_MEMORY;
305 : }
306 696 : memcpy(lm_session_key.data, lm_hash, 8);
307 :
308 696 : if (!(*flags & CLI_CRED_NTLM_AUTH)) {
309 32 : memcpy(session_key.data, lm_session_key.data, 16);
310 : }
311 696 : ZERO_STRUCT(lm_hash);
312 : }
313 : }
314 :
315 40550 : done:
316 40550 : if (_lm_response != NULL) {
317 40550 : talloc_steal(mem_ctx, lm_response.data);
318 40550 : *_lm_response = lm_response;
319 : } else {
320 0 : data_blob_clear(&lm_response);
321 : }
322 40550 : if (_nt_response != NULL) {
323 40546 : talloc_steal(mem_ctx, nt_response.data);
324 40546 : *_nt_response = nt_response;
325 : } else {
326 4 : data_blob_clear(&nt_response);
327 : }
328 40550 : if (_lm_session_key != NULL) {
329 37791 : talloc_steal(mem_ctx, lm_session_key.data);
330 37791 : *_lm_session_key = lm_session_key;
331 : } else {
332 2759 : data_blob_clear(&lm_session_key);
333 : }
334 40550 : if (_session_key != NULL) {
335 37812 : talloc_steal(mem_ctx, session_key.data);
336 37812 : *_session_key = session_key;
337 : } else {
338 2738 : data_blob_clear(&session_key);
339 : }
340 40550 : TALLOC_FREE(frame);
341 40550 : return NT_STATUS_OK;
342 : }
343 :
344 : /*
345 : * Set a utf16 password on the credentials context, including an indication
346 : * of 'how' the password was obtained
347 : *
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 lose information.
351 : */
352 809 : _PUBLIC_ bool cli_credentials_set_utf16_password(struct cli_credentials *cred,
353 : const DATA_BLOB *password_utf16,
354 : enum credentials_obtained obtained)
355 : {
356 809 : cred->password_will_be_nt_hash = false;
357 :
358 809 : if (password_utf16 == NULL) {
359 0 : return cli_credentials_set_password(cred, NULL, obtained);
360 : }
361 :
362 809 : if (obtained >= cred->password_obtained) {
363 809 : struct samr_Password *nt_hash = NULL;
364 809 : char *password_talloc = NULL;
365 809 : size_t password_len = 0;
366 1 : bool ok;
367 :
368 809 : nt_hash = talloc(cred, struct samr_Password);
369 809 : if (nt_hash == NULL) {
370 0 : return false;
371 : }
372 :
373 810 : ok = convert_string_talloc(cred,
374 : CH_UTF16MUNGED, CH_UTF8,
375 809 : password_utf16->data,
376 809 : password_utf16->length,
377 : &password_talloc,
378 : &password_len);
379 809 : if (!ok) {
380 0 : TALLOC_FREE(nt_hash);
381 0 : return false;
382 : }
383 :
384 809 : ok = cli_credentials_set_password(cred, password_talloc, obtained);
385 809 : TALLOC_FREE(password_talloc);
386 809 : if (!ok) {
387 0 : TALLOC_FREE(nt_hash);
388 0 : return false;
389 : }
390 :
391 809 : mdfour(nt_hash->hash, password_utf16->data, password_utf16->length);
392 809 : cred->nt_hash = nt_hash;
393 809 : return true;
394 : }
395 :
396 0 : return false;
397 : }
398 :
399 : /*
400 : * Set a old utf16 password on the credentials context.
401 : *
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 lose information.
405 : */
406 1 : _PUBLIC_ bool cli_credentials_set_old_utf16_password(struct cli_credentials *cred,
407 : const DATA_BLOB *password_utf16)
408 : {
409 1 : struct samr_Password *nt_hash = NULL;
410 1 : char *password_talloc = NULL;
411 1 : size_t password_len = 0;
412 1 : bool ok;
413 :
414 1 : if (password_utf16 == NULL) {
415 0 : return cli_credentials_set_old_password(cred, NULL, CRED_SPECIFIED);
416 : }
417 :
418 1 : nt_hash = talloc(cred, struct samr_Password);
419 1 : if (nt_hash == NULL) {
420 0 : return false;
421 : }
422 :
423 2 : ok = convert_string_talloc(cred,
424 : CH_UTF16MUNGED, CH_UTF8,
425 1 : password_utf16->data,
426 1 : password_utf16->length,
427 : &password_talloc,
428 : &password_len);
429 1 : if (!ok) {
430 0 : TALLOC_FREE(nt_hash);
431 0 : return false;
432 : }
433 :
434 1 : ok = cli_credentials_set_old_password(cred, password_talloc, CRED_SPECIFIED);
435 1 : TALLOC_FREE(password_talloc);
436 1 : if (!ok) {
437 0 : TALLOC_FREE(nt_hash);
438 0 : return false;
439 : }
440 :
441 1 : mdfour(nt_hash->hash, password_utf16->data, password_utf16->length);
442 1 : cred->old_nt_hash = nt_hash;
443 1 : return true;
444 : }
445 :
446 3 : _PUBLIC_ void cli_credentials_set_password_will_be_nt_hash(struct cli_credentials *cred,
447 : bool val)
448 : {
449 : /*
450 : * We set this here and the next cli_credentials_set_password()
451 : * that resets the password or password callback
452 : * will pick this up.
453 : *
454 : * cli_credentials_set_nt_hash() and
455 : * cli_credentials_set_utf16_password() will reset this
456 : * to false.
457 : */
458 3 : cred->password_will_be_nt_hash = val;
459 3 : }
460 :
461 48 : _PUBLIC_ bool cli_credentials_is_password_nt_hash(struct cli_credentials *cred)
462 : {
463 48 : return cred->password_will_be_nt_hash;
464 : }
465 :
466 170 : _PUBLIC_ bool cli_credentials_set_nt_hash(struct cli_credentials *cred,
467 : const struct samr_Password *nt_hash,
468 : enum credentials_obtained obtained)
469 : {
470 170 : cred->password_will_be_nt_hash = false;
471 :
472 170 : if (obtained >= cred->password_obtained) {
473 170 : cli_credentials_set_password(cred, NULL, obtained);
474 170 : if (nt_hash) {
475 170 : cred->nt_hash = talloc(cred, struct samr_Password);
476 170 : if (cred->nt_hash == NULL) {
477 0 : return false;
478 : }
479 170 : *cred->nt_hash = *nt_hash;
480 : } else {
481 0 : cred->nt_hash = NULL;
482 : }
483 170 : return true;
484 : }
485 :
486 0 : return false;
487 : }
488 :
489 0 : _PUBLIC_ bool cli_credentials_set_old_nt_hash(struct cli_credentials *cred,
490 : const struct samr_Password *nt_hash)
491 : {
492 0 : cli_credentials_set_old_password(cred, NULL, CRED_SPECIFIED);
493 0 : if (nt_hash) {
494 0 : cred->old_nt_hash = talloc(cred, struct samr_Password);
495 0 : if (cred->old_nt_hash == NULL) {
496 0 : return false;
497 : }
498 0 : *cred->old_nt_hash = *nt_hash;
499 : } else {
500 0 : cred->old_nt_hash = NULL;
501 : }
502 :
503 0 : return true;
504 : }
505 :
506 12 : _PUBLIC_ bool cli_credentials_set_ntlm_response(struct cli_credentials *cred,
507 : const DATA_BLOB *lm_response,
508 : const DATA_BLOB *lm_session_key,
509 : const DATA_BLOB *nt_response,
510 : const DATA_BLOB *nt_session_key,
511 : enum credentials_obtained obtained)
512 : {
513 12 : if (obtained >= cred->password_obtained) {
514 12 : cli_credentials_set_password(cred, NULL, obtained);
515 :
516 12 : data_blob_clear_free(&cred->lm_response);
517 12 : data_blob_clear_free(&cred->lm_session_key);
518 12 : data_blob_clear_free(&cred->nt_response);
519 12 : data_blob_clear_free(&cred->nt_session_key);
520 :
521 12 : if (lm_response != NULL && lm_response->length != 0) {
522 12 : cred->lm_response = data_blob_talloc(cred,
523 : lm_response->data,
524 : lm_response->length);
525 12 : if (cred->lm_response.data == NULL) {
526 0 : return false;
527 : }
528 : }
529 12 : if (lm_session_key != NULL && lm_session_key->length != 0) {
530 12 : cred->lm_session_key = data_blob_talloc(cred,
531 : lm_session_key->data,
532 : lm_session_key->length);
533 12 : if (cred->lm_session_key.data == NULL) {
534 0 : return false;
535 : }
536 : }
537 :
538 12 : if (nt_response != NULL && nt_response->length != 0) {
539 12 : cred->nt_response = data_blob_talloc(cred,
540 : nt_response->data,
541 : nt_response->length);
542 12 : if (cred->nt_response.data == NULL) {
543 0 : return false;
544 : }
545 : }
546 12 : if (nt_session_key != NULL && nt_session_key->length != 0) {
547 12 : cred->nt_session_key = data_blob_talloc(cred,
548 : nt_session_key->data,
549 : nt_session_key->length);
550 12 : if (cred->nt_session_key.data == NULL) {
551 0 : return false;
552 : }
553 : }
554 :
555 12 : return true;
556 : }
557 :
558 0 : return false;
559 : }
560 :
|