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 11438 : _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 11438 : TALLOC_CTX *frame = talloc_stackframe();
47 11438 : const char *user = NULL;
48 11438 : const char *domain = NULL;
49 11438 : DATA_BLOB lm_response = data_blob_null;
50 11438 : DATA_BLOB nt_response = data_blob_null;
51 11438 : DATA_BLOB lm_session_key = data_blob_null;
52 11438 : DATA_BLOB session_key = data_blob_null;
53 11438 : const struct samr_Password *nt_hash = NULL;
54 : int rc;
55 :
56 11438 : 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 11438 : if (cred->nt_response.data || cred->lm_response.data) {
64 2 : if (cred->nt_response.length != 0) {
65 2 : nt_response = data_blob_dup_talloc(frame,
66 : cred->nt_response);
67 2 : if (nt_response.data == NULL) {
68 0 : TALLOC_FREE(frame);
69 0 : return NT_STATUS_NO_MEMORY;
70 : }
71 : }
72 2 : if (cred->nt_session_key.length != 0) {
73 2 : session_key = data_blob_dup_talloc(frame,
74 : cred->nt_session_key);
75 2 : if (session_key.data == NULL) {
76 0 : TALLOC_FREE(frame);
77 0 : return NT_STATUS_NO_MEMORY;
78 : }
79 : }
80 2 : if (cred->lm_response.length != 0) {
81 2 : lm_response = data_blob_dup_talloc(frame,
82 : cred->lm_response);
83 2 : if (lm_response.data == NULL) {
84 0 : TALLOC_FREE(frame);
85 0 : return NT_STATUS_NO_MEMORY;
86 : }
87 : }
88 2 : if (cred->lm_session_key.length != 0) {
89 2 : lm_session_key = data_blob_dup_talloc(frame,
90 : cred->lm_session_key);
91 2 : if (lm_session_key.data == NULL) {
92 0 : TALLOC_FREE(frame);
93 0 : return NT_STATUS_NO_MEMORY;
94 : }
95 : }
96 :
97 2 : if (cred->lm_response.data == NULL) {
98 0 : *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
99 : }
100 2 : goto done;
101 : }
102 :
103 11436 : nt_hash = cli_credentials_get_nt_hash(cred, frame);
104 :
105 11436 : cli_credentials_get_ntlm_username_domain(cred, frame, &user, &domain);
106 11436 : if (user == NULL) {
107 0 : TALLOC_FREE(frame);
108 0 : return NT_STATUS_NO_MEMORY;
109 : }
110 11436 : 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 11436 : 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 11436 : if (cred->machine_account) {
124 94 : *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
125 : }
126 :
127 11436 : if (!nt_hash) {
128 : /* do nothing - blobs are zero length */
129 :
130 : /* session key is all zeros */
131 500 : session_key = data_blob_talloc_zero(frame, 16);
132 500 : if (session_key.data == NULL) {
133 0 : TALLOC_FREE(frame);
134 0 : return NT_STATUS_NO_MEMORY;
135 : }
136 500 : lm_session_key = data_blob_talloc_zero(frame, 16);
137 500 : 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 500 : *flags &= ~CLI_CRED_NTLM2;
144 10936 : } else if (*flags & CLI_CRED_NTLMv2_AUTH) {
145 :
146 10686 : 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 10686 : if (!SMBNTLMv2encrypt_hash(frame,
157 : user,
158 : domain,
159 10686 : 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 10686 : *flags &= ~CLI_CRED_LANMAN_AUTH;
169 10686 : if (lm_response.length != 0) {
170 : /*
171 : * We should not expose the lm key.
172 : */
173 10686 : memset(lm_response.data, 0, lm_response.length);
174 : }
175 250 : } 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];
179 :
180 39 : lm_response = data_blob_talloc_zero(frame, 24);
181 39 : if (lm_response.data == NULL) {
182 0 : TALLOC_FREE(frame);
183 0 : return NT_STATUS_NO_MEMORY;
184 : }
185 39 : generate_random_buffer(lm_response.data, 8);
186 :
187 39 : memcpy(session_nonce, challenge.data, 8);
188 39 : memcpy(&session_nonce[8], lm_response.data, 8);
189 :
190 39 : rc = gnutls_hash_fast(GNUTLS_DIG_MD5,
191 : session_nonce,
192 : sizeof(session_nonce),
193 : session_nonce_hash);
194 39 : if (rc < 0) {
195 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED);
196 : }
197 :
198 39 : DEBUG(5, ("NTLMSSP challenge set by NTLM2\n"));
199 39 : DEBUG(5, ("challenge is: \n"));
200 39 : dump_data(5, session_nonce_hash, 8);
201 :
202 39 : nt_response = data_blob_talloc_zero(frame, 24);
203 39 : if (nt_response.data == NULL) {
204 0 : TALLOC_FREE(frame);
205 0 : return NT_STATUS_NO_MEMORY;
206 : }
207 39 : rc = SMBOWFencrypt(nt_hash->hash,
208 : session_nonce_hash,
209 : nt_response.data);
210 39 : 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 39 : ZERO_ARRAY(session_nonce_hash);
216 :
217 39 : session_key = data_blob_talloc_zero(frame, 16);
218 39 : if (session_key.data == NULL) {
219 0 : TALLOC_FREE(frame);
220 0 : return NT_STATUS_NO_MEMORY;
221 : }
222 :
223 39 : SMBsesskeygen_ntv1(nt_hash->hash, user_session_key);
224 :
225 39 : rc = gnutls_hmac_fast(GNUTLS_MAC_MD5,
226 : user_session_key,
227 : sizeof(user_session_key),
228 : session_nonce,
229 : sizeof(session_nonce),
230 39 : session_key.data);
231 39 : if (rc < 0) {
232 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED);
233 : }
234 :
235 39 : ZERO_ARRAY(user_session_key);
236 :
237 39 : dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);
238 :
239 : /* LM Key is incompatible... */
240 39 : *flags &= ~CLI_CRED_LANMAN_AUTH;
241 : } else {
242 211 : const char *password = cli_credentials_get_password(cred);
243 : uint8_t lm_hash[16];
244 211 : bool do_lm = false;
245 :
246 211 : nt_response = data_blob_talloc_zero(frame, 24);
247 211 : if (nt_response.data == NULL) {
248 0 : TALLOC_FREE(frame);
249 0 : return NT_STATUS_NO_MEMORY;
250 : }
251 211 : rc = SMBOWFencrypt(nt_hash->hash, challenge.data,
252 : nt_response.data);
253 211 : 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 211 : session_key = data_blob_talloc_zero(frame, 16);
259 211 : if (session_key.data == NULL) {
260 0 : TALLOC_FREE(frame);
261 0 : return NT_STATUS_NO_MEMORY;
262 : }
263 211 : SMBsesskeygen_ntv1(nt_hash->hash, session_key.data);
264 211 : 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 211 : if (password != NULL) {
270 211 : do_lm = E_deshash(password, lm_hash);
271 : }
272 :
273 211 : if (*flags & CLI_CRED_LANMAN_AUTH && do_lm) {
274 202 : lm_response = data_blob_talloc_zero(frame, 24);
275 202 : 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 401 : rc = SMBencrypt_hash(lm_hash,
282 202 : challenge.data,
283 : lm_response.data);
284 401 : 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 9 : lm_response = data_blob_dup_talloc(frame, nt_response);
292 9 : 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 211 : if (do_lm) {
300 205 : lm_session_key = data_blob_talloc_zero(frame, 16);
301 205 : 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 205 : memcpy(lm_session_key.data, lm_hash, 8);
307 :
308 205 : if (!(*flags & CLI_CRED_NTLM_AUTH)) {
309 4 : memcpy(session_key.data, lm_session_key.data, 16);
310 : }
311 205 : ZERO_STRUCT(lm_hash);
312 : }
313 : }
314 :
315 11438 : done:
316 11438 : if (_lm_response != NULL) {
317 11438 : talloc_steal(mem_ctx, lm_response.data);
318 11438 : *_lm_response = lm_response;
319 : } else {
320 0 : data_blob_clear(&lm_response);
321 : }
322 11438 : if (_nt_response != NULL) {
323 11434 : talloc_steal(mem_ctx, nt_response.data);
324 11434 : *_nt_response = nt_response;
325 : } else {
326 4 : data_blob_clear(&nt_response);
327 : }
328 11438 : if (_lm_session_key != NULL) {
329 10204 : talloc_steal(mem_ctx, lm_session_key.data);
330 10204 : *_lm_session_key = lm_session_key;
331 : } else {
332 1234 : data_blob_clear(&lm_session_key);
333 : }
334 11438 : if (_session_key != NULL) {
335 10213 : talloc_steal(mem_ctx, session_key.data);
336 10213 : *_session_key = session_key;
337 : } else {
338 1225 : data_blob_clear(&session_key);
339 : }
340 11438 : TALLOC_FREE(frame);
341 11438 : 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 loose information.
351 : */
352 0 : _PUBLIC_ bool cli_credentials_set_utf16_password(struct cli_credentials *cred,
353 : const DATA_BLOB *password_utf16,
354 : enum credentials_obtained obtained)
355 : {
356 0 : cred->password_will_be_nt_hash = false;
357 :
358 0 : if (password_utf16 == NULL) {
359 0 : return cli_credentials_set_password(cred, NULL, obtained);
360 : }
361 :
362 0 : if (obtained >= cred->password_obtained) {
363 0 : struct samr_Password *nt_hash = NULL;
364 0 : char *password_talloc = NULL;
365 0 : size_t password_len = 0;
366 : bool ok;
367 :
368 0 : nt_hash = talloc(cred, struct samr_Password);
369 0 : if (nt_hash == NULL) {
370 0 : return false;
371 : }
372 :
373 0 : ok = convert_string_talloc(cred,
374 : CH_UTF16MUNGED, CH_UTF8,
375 0 : password_utf16->data,
376 0 : password_utf16->length,
377 : (void *)&password_talloc,
378 : &password_len);
379 0 : if (!ok) {
380 0 : TALLOC_FREE(nt_hash);
381 0 : return false;
382 : }
383 :
384 0 : ok = cli_credentials_set_password(cred, password_talloc, obtained);
385 0 : TALLOC_FREE(password_talloc);
386 0 : if (!ok) {
387 0 : TALLOC_FREE(nt_hash);
388 0 : return false;
389 : }
390 :
391 0 : mdfour(nt_hash->hash, password_utf16->data, password_utf16->length);
392 0 : cred->nt_hash = nt_hash;
393 0 : 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 loose information.
405 : */
406 0 : _PUBLIC_ bool cli_credentials_set_old_utf16_password(struct cli_credentials *cred,
407 : const DATA_BLOB *password_utf16)
408 : {
409 0 : struct samr_Password *nt_hash = NULL;
410 0 : char *password_talloc = NULL;
411 0 : size_t password_len = 0;
412 : bool ok;
413 :
414 0 : if (password_utf16 == NULL) {
415 0 : return cli_credentials_set_old_password(cred, NULL, CRED_SPECIFIED);
416 : }
417 :
418 0 : nt_hash = talloc(cred, struct samr_Password);
419 0 : if (nt_hash == NULL) {
420 0 : return false;
421 : }
422 :
423 0 : ok = convert_string_talloc(cred,
424 : CH_UTF16MUNGED, CH_UTF8,
425 0 : password_utf16->data,
426 0 : password_utf16->length,
427 : (void *)&password_talloc,
428 : &password_len);
429 0 : if (!ok) {
430 0 : TALLOC_FREE(nt_hash);
431 0 : return false;
432 : }
433 :
434 0 : ok = cli_credentials_set_old_password(cred, password_talloc, CRED_SPECIFIED);
435 0 : TALLOC_FREE(password_talloc);
436 0 : if (!ok) {
437 0 : TALLOC_FREE(nt_hash);
438 0 : return false;
439 : }
440 :
441 0 : mdfour(nt_hash->hash, password_utf16->data, password_utf16->length);
442 0 : cred->old_nt_hash = nt_hash;
443 0 : return true;
444 : }
445 :
446 0 : _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 0 : cred->password_will_be_nt_hash = val;
459 0 : }
460 :
461 24 : _PUBLIC_ bool cli_credentials_set_nt_hash(struct cli_credentials *cred,
462 : const struct samr_Password *nt_hash,
463 : enum credentials_obtained obtained)
464 : {
465 24 : cred->password_will_be_nt_hash = false;
466 :
467 24 : if (obtained >= cred->password_obtained) {
468 24 : cli_credentials_set_password(cred, NULL, obtained);
469 24 : if (nt_hash) {
470 24 : cred->nt_hash = talloc(cred, struct samr_Password);
471 24 : if (cred->nt_hash == NULL) {
472 0 : return false;
473 : }
474 24 : *cred->nt_hash = *nt_hash;
475 : } else {
476 0 : cred->nt_hash = NULL;
477 : }
478 24 : return true;
479 : }
480 :
481 0 : return false;
482 : }
483 :
484 0 : _PUBLIC_ bool cli_credentials_set_old_nt_hash(struct cli_credentials *cred,
485 : const struct samr_Password *nt_hash)
486 : {
487 0 : cli_credentials_set_old_password(cred, NULL, CRED_SPECIFIED);
488 0 : if (nt_hash) {
489 0 : cred->old_nt_hash = talloc(cred, struct samr_Password);
490 0 : if (cred->old_nt_hash == NULL) {
491 0 : return false;
492 : }
493 0 : *cred->old_nt_hash = *nt_hash;
494 : } else {
495 0 : cred->old_nt_hash = NULL;
496 : }
497 :
498 0 : return true;
499 : }
500 :
501 2 : _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)
507 : {
508 2 : if (obtained >= cred->password_obtained) {
509 2 : cli_credentials_set_password(cred, NULL, obtained);
510 :
511 2 : data_blob_clear_free(&cred->lm_response);
512 2 : data_blob_clear_free(&cred->lm_session_key);
513 2 : data_blob_clear_free(&cred->nt_response);
514 2 : data_blob_clear_free(&cred->nt_session_key);
515 :
516 2 : if (lm_response != NULL && lm_response->length != 0) {
517 2 : cred->lm_response = data_blob_talloc(cred,
518 : lm_response->data,
519 : lm_response->length);
520 2 : if (cred->lm_response.data == NULL) {
521 0 : return false;
522 : }
523 : }
524 2 : if (lm_session_key != NULL && lm_session_key->length != 0) {
525 2 : cred->lm_session_key = data_blob_talloc(cred,
526 : lm_session_key->data,
527 : lm_session_key->length);
528 2 : if (cred->lm_session_key.data == NULL) {
529 0 : return false;
530 : }
531 : }
532 :
533 2 : if (nt_response != NULL && nt_response->length != 0) {
534 2 : cred->nt_response = data_blob_talloc(cred,
535 : nt_response->data,
536 : nt_response->length);
537 2 : if (cred->nt_response.data == NULL) {
538 0 : return false;
539 : }
540 : }
541 2 : if (nt_session_key != NULL && nt_session_key->length != 0) {
542 2 : cred->nt_session_key = data_blob_talloc(cred,
543 : nt_session_key->data,
544 : nt_session_key->length);
545 2 : if (cred->nt_session_key.data == NULL) {
546 0 : return false;
547 : }
548 : }
549 :
550 2 : return true;
551 : }
552 :
553 0 : return false;
554 : }
555 :
|