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 32135 : _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 32135 : TALLOC_CTX *frame = talloc_stackframe();
47 32135 : const char *user = NULL;
48 32135 : const char *domain = NULL;
49 32135 : DATA_BLOB lm_response = data_blob_null;
50 32135 : DATA_BLOB nt_response = data_blob_null;
51 32135 : DATA_BLOB lm_session_key = data_blob_null;
52 32135 : DATA_BLOB session_key = data_blob_null;
53 32135 : const struct samr_Password *nt_hash = NULL;
54 : int rc;
55 :
56 32135 : 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 32135 : if (cred->nt_response.data || cred->lm_response.data) {
64 0 : if (cred->nt_response.length != 0) {
65 0 : nt_response = data_blob_dup_talloc(frame,
66 : cred->nt_response);
67 0 : if (nt_response.data == NULL) {
68 0 : TALLOC_FREE(frame);
69 0 : return NT_STATUS_NO_MEMORY;
70 : }
71 : }
72 0 : if (cred->lm_response.length != 0) {
73 0 : lm_response = data_blob_dup_talloc(frame,
74 : cred->lm_response);
75 0 : if (lm_response.data == NULL) {
76 0 : TALLOC_FREE(frame);
77 0 : return NT_STATUS_NO_MEMORY;
78 : }
79 : }
80 :
81 0 : if (cred->lm_response.data == NULL) {
82 0 : *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
83 : }
84 0 : goto done;
85 : }
86 :
87 32135 : nt_hash = cli_credentials_get_nt_hash(cred, frame);
88 :
89 32135 : cli_credentials_get_ntlm_username_domain(cred, frame, &user, &domain);
90 32135 : if (user == NULL) {
91 0 : TALLOC_FREE(frame);
92 0 : return NT_STATUS_NO_MEMORY;
93 : }
94 32135 : if (domain == NULL) {
95 0 : TALLOC_FREE(frame);
96 0 : return NT_STATUS_NO_MEMORY;
97 : }
98 :
99 : /* If we are sending a username@realm login (see function
100 : * above), then we will not send LM, it will not be
101 : * accepted */
102 32135 : if (cred->principal_obtained > cred->username_obtained) {
103 0 : *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
104 : }
105 :
106 : /* Likewise if we are a machine account (avoid protocol downgrade attacks) */
107 32135 : if (cred->machine_account) {
108 126 : *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
109 : }
110 :
111 32135 : if (!nt_hash) {
112 : /* do nothing - blobs are zero length */
113 :
114 : /* session key is all zeros */
115 942 : session_key = data_blob_talloc_zero(frame, 16);
116 942 : if (session_key.data == NULL) {
117 0 : TALLOC_FREE(frame);
118 0 : return NT_STATUS_NO_MEMORY;
119 : }
120 942 : lm_session_key = data_blob_talloc_zero(frame, 16);
121 942 : if (lm_session_key.data == NULL) {
122 0 : TALLOC_FREE(frame);
123 0 : return NT_STATUS_NO_MEMORY;
124 : }
125 :
126 : /* not doing NTLM2 without a password */
127 942 : *flags &= ~CLI_CRED_NTLM2;
128 31193 : } else if (*flags & CLI_CRED_NTLMv2_AUTH) {
129 :
130 30328 : if (!target_info.length) {
131 : /* be lazy, match win2k - we can't do NTLMv2 without it */
132 0 : DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n"));
133 0 : TALLOC_FREE(frame);
134 0 : return NT_STATUS_INVALID_PARAMETER;
135 : }
136 :
137 : /* TODO: if the remote server is standalone, then we should replace 'domain'
138 : with the server name as supplied above */
139 :
140 30328 : if (!SMBNTLMv2encrypt_hash(frame,
141 : user,
142 : domain,
143 30328 : nt_hash->hash, &challenge,
144 : server_timestamp, &target_info,
145 : &lm_response, &nt_response,
146 : NULL, &session_key)) {
147 0 : TALLOC_FREE(frame);
148 0 : return NT_STATUS_NO_MEMORY;
149 : }
150 :
151 : /* LM Key is incompatible... */
152 30328 : *flags &= ~CLI_CRED_LANMAN_AUTH;
153 30328 : if (lm_response.length != 0) {
154 : /*
155 : * We should not expose the lm key.
156 : */
157 30328 : memset(lm_response.data, 0, lm_response.length);
158 : }
159 865 : } else if (*flags & CLI_CRED_NTLM2) {
160 : uint8_t session_nonce[16];
161 : uint8_t session_nonce_hash[16];
162 : uint8_t user_session_key[16];
163 :
164 170 : lm_response = data_blob_talloc_zero(frame, 24);
165 170 : if (lm_response.data == NULL) {
166 0 : TALLOC_FREE(frame);
167 0 : return NT_STATUS_NO_MEMORY;
168 : }
169 170 : generate_random_buffer(lm_response.data, 8);
170 :
171 170 : memcpy(session_nonce, challenge.data, 8);
172 170 : memcpy(&session_nonce[8], lm_response.data, 8);
173 :
174 170 : rc = gnutls_hash_fast(GNUTLS_DIG_MD5,
175 : session_nonce,
176 : sizeof(session_nonce),
177 : session_nonce_hash);
178 170 : if (rc < 0) {
179 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED);
180 : }
181 :
182 170 : DEBUG(5, ("NTLMSSP challenge set by NTLM2\n"));
183 170 : DEBUG(5, ("challenge is: \n"));
184 170 : dump_data(5, session_nonce_hash, 8);
185 :
186 170 : nt_response = data_blob_talloc_zero(frame, 24);
187 170 : if (nt_response.data == NULL) {
188 0 : TALLOC_FREE(frame);
189 0 : return NT_STATUS_NO_MEMORY;
190 : }
191 170 : rc = SMBOWFencrypt(nt_hash->hash,
192 : session_nonce_hash,
193 : nt_response.data);
194 170 : if (rc != 0) {
195 0 : TALLOC_FREE(frame);
196 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
197 : }
198 :
199 170 : ZERO_ARRAY(session_nonce_hash);
200 :
201 170 : session_key = data_blob_talloc_zero(frame, 16);
202 170 : if (session_key.data == NULL) {
203 0 : TALLOC_FREE(frame);
204 0 : return NT_STATUS_NO_MEMORY;
205 : }
206 :
207 170 : SMBsesskeygen_ntv1(nt_hash->hash, user_session_key);
208 :
209 170 : rc = gnutls_hmac_fast(GNUTLS_MAC_MD5,
210 : user_session_key,
211 : sizeof(user_session_key),
212 : session_nonce,
213 : sizeof(session_nonce),
214 170 : session_key.data);
215 170 : if (rc < 0) {
216 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED);
217 : }
218 :
219 170 : ZERO_ARRAY(user_session_key);
220 :
221 170 : dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);
222 :
223 : /* LM Key is incompatible... */
224 170 : *flags &= ~CLI_CRED_LANMAN_AUTH;
225 : } else {
226 695 : const char *password = cli_credentials_get_password(cred);
227 : uint8_t lm_hash[16];
228 695 : bool do_lm = false;
229 :
230 695 : nt_response = data_blob_talloc_zero(frame, 24);
231 695 : if (nt_response.data == NULL) {
232 0 : TALLOC_FREE(frame);
233 0 : return NT_STATUS_NO_MEMORY;
234 : }
235 695 : rc = SMBOWFencrypt(nt_hash->hash, challenge.data,
236 : nt_response.data);
237 695 : if (rc != 0) {
238 0 : TALLOC_FREE(frame);
239 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
240 : }
241 :
242 695 : session_key = data_blob_talloc_zero(frame, 16);
243 695 : if (session_key.data == NULL) {
244 0 : TALLOC_FREE(frame);
245 0 : return NT_STATUS_NO_MEMORY;
246 : }
247 695 : SMBsesskeygen_ntv1(nt_hash->hash, session_key.data);
248 695 : dump_data_pw("NT session key:\n", session_key.data, session_key.length);
249 :
250 : /* lanman auth is insecure, it may be disabled.
251 : We may also not have a password */
252 :
253 695 : if (password != NULL) {
254 695 : do_lm = E_deshash(password, lm_hash);
255 : }
256 :
257 695 : if (*flags & CLI_CRED_LANMAN_AUTH && do_lm) {
258 676 : lm_response = data_blob_talloc_zero(frame, 24);
259 676 : if (lm_response.data == NULL) {
260 0 : ZERO_STRUCT(lm_hash);
261 0 : TALLOC_FREE(frame);
262 0 : return NT_STATUS_NO_MEMORY;
263 : }
264 :
265 1343 : rc = SMBencrypt_hash(lm_hash,
266 676 : challenge.data,
267 : lm_response.data);
268 1343 : if (rc != 0) {
269 0 : ZERO_STRUCT(lm_hash);
270 0 : TALLOC_FREE(frame);
271 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
272 : }
273 : } else {
274 : /* just copy the nt_response */
275 19 : lm_response = data_blob_dup_talloc(frame, nt_response);
276 19 : if (lm_response.data == NULL) {
277 0 : ZERO_STRUCT(lm_hash);
278 0 : TALLOC_FREE(frame);
279 0 : return NT_STATUS_NO_MEMORY;
280 : }
281 : }
282 :
283 695 : if (do_lm) {
284 689 : lm_session_key = data_blob_talloc_zero(frame, 16);
285 689 : if (lm_session_key.data == NULL) {
286 0 : ZERO_STRUCT(lm_hash);
287 0 : TALLOC_FREE(frame);
288 0 : return NT_STATUS_NO_MEMORY;
289 : }
290 698 : memcpy(lm_session_key.data, lm_hash, 8);
291 :
292 689 : if (!(*flags & CLI_CRED_NTLM_AUTH)) {
293 26 : memcpy(session_key.data, lm_session_key.data, 16);
294 : }
295 689 : ZERO_STRUCT(lm_hash);
296 : }
297 : }
298 :
299 32135 : done:
300 32135 : if (_lm_response != NULL) {
301 32135 : talloc_steal(mem_ctx, lm_response.data);
302 32135 : *_lm_response = lm_response;
303 : } else {
304 0 : data_blob_clear(&lm_response);
305 : }
306 32135 : if (_nt_response != NULL) {
307 32131 : talloc_steal(mem_ctx, nt_response.data);
308 32131 : *_nt_response = nt_response;
309 : } else {
310 4 : data_blob_clear(&nt_response);
311 : }
312 32135 : if (_lm_session_key != NULL) {
313 29414 : talloc_steal(mem_ctx, lm_session_key.data);
314 29414 : *_lm_session_key = lm_session_key;
315 : } else {
316 2721 : data_blob_clear(&lm_session_key);
317 : }
318 32135 : if (_session_key != NULL) {
319 29437 : talloc_steal(mem_ctx, session_key.data);
320 29437 : *_session_key = session_key;
321 : } else {
322 2698 : data_blob_clear(&session_key);
323 : }
324 32135 : TALLOC_FREE(frame);
325 32135 : return NT_STATUS_OK;
326 : }
327 :
328 : /*
329 : * Set a utf16 password on the credentials context, including an indication
330 : * of 'how' the password was obtained
331 : *
332 : * This is required because the nt_hash is calculated over the raw utf16 blob,
333 : * which might not be completely valid utf16, which means the conversion
334 : * from CH_UTF16MUNGED to CH_UTF8 might loose information.
335 : */
336 127 : _PUBLIC_ bool cli_credentials_set_utf16_password(struct cli_credentials *cred,
337 : const DATA_BLOB *password_utf16,
338 : enum credentials_obtained obtained)
339 : {
340 127 : cred->password_will_be_nt_hash = false;
341 :
342 127 : if (password_utf16 == NULL) {
343 0 : return cli_credentials_set_password(cred, NULL, obtained);
344 : }
345 :
346 127 : if (obtained >= cred->password_obtained) {
347 127 : struct samr_Password *nt_hash = NULL;
348 127 : char *password_talloc = NULL;
349 127 : size_t password_len = 0;
350 : bool ok;
351 :
352 127 : nt_hash = talloc(cred, struct samr_Password);
353 127 : if (nt_hash == NULL) {
354 0 : return false;
355 : }
356 :
357 194 : ok = convert_string_talloc(cred,
358 : CH_UTF16MUNGED, CH_UTF8,
359 127 : password_utf16->data,
360 60 : password_utf16->length,
361 : (void *)&password_talloc,
362 : &password_len);
363 127 : if (!ok) {
364 0 : TALLOC_FREE(nt_hash);
365 0 : return false;
366 : }
367 :
368 127 : ok = cli_credentials_set_password(cred, password_talloc, obtained);
369 127 : TALLOC_FREE(password_talloc);
370 127 : if (!ok) {
371 0 : TALLOC_FREE(nt_hash);
372 0 : return false;
373 : }
374 :
375 127 : mdfour(nt_hash->hash, password_utf16->data, password_utf16->length);
376 127 : cred->nt_hash = nt_hash;
377 127 : return true;
378 : }
379 :
380 0 : return false;
381 : }
382 :
383 : /*
384 : * Set a old utf16 password on the credentials context.
385 : *
386 : * This is required because the nt_hash is calculated over the raw utf16 blob,
387 : * which might not be completely valid utf16, which means the conversion
388 : * from CH_UTF16MUNGED to CH_UTF8 might loose information.
389 : */
390 1 : _PUBLIC_ bool cli_credentials_set_old_utf16_password(struct cli_credentials *cred,
391 : const DATA_BLOB *password_utf16)
392 : {
393 1 : struct samr_Password *nt_hash = NULL;
394 1 : char *password_talloc = NULL;
395 1 : size_t password_len = 0;
396 : bool ok;
397 :
398 1 : if (password_utf16 == NULL) {
399 0 : return cli_credentials_set_old_password(cred, NULL, CRED_SPECIFIED);
400 : }
401 :
402 1 : nt_hash = talloc(cred, struct samr_Password);
403 1 : if (nt_hash == NULL) {
404 0 : return false;
405 : }
406 :
407 2 : ok = convert_string_talloc(cred,
408 : CH_UTF16MUNGED, CH_UTF8,
409 1 : password_utf16->data,
410 0 : password_utf16->length,
411 : (void *)&password_talloc,
412 : &password_len);
413 1 : if (!ok) {
414 0 : TALLOC_FREE(nt_hash);
415 0 : return false;
416 : }
417 :
418 1 : ok = cli_credentials_set_old_password(cred, password_talloc, CRED_SPECIFIED);
419 1 : TALLOC_FREE(password_talloc);
420 1 : if (!ok) {
421 0 : TALLOC_FREE(nt_hash);
422 0 : return false;
423 : }
424 :
425 1 : mdfour(nt_hash->hash, password_utf16->data, password_utf16->length);
426 1 : cred->old_nt_hash = nt_hash;
427 1 : return true;
428 : }
429 :
430 3 : _PUBLIC_ void cli_credentials_set_password_will_be_nt_hash(struct cli_credentials *cred,
431 : bool val)
432 : {
433 : /*
434 : * We set this here and the next cli_credentials_set_password()
435 : * that resets the password or password callback
436 : * will pick this up.
437 : *
438 : * cli_credentials_set_nt_hash() and
439 : * cli_credentials_set_utf16_password() will reset this
440 : * to false.
441 : */
442 3 : cred->password_will_be_nt_hash = val;
443 3 : }
444 :
445 42 : _PUBLIC_ bool cli_credentials_set_nt_hash(struct cli_credentials *cred,
446 : const struct samr_Password *nt_hash,
447 : enum credentials_obtained obtained)
448 : {
449 42 : cred->password_will_be_nt_hash = false;
450 :
451 42 : if (obtained >= cred->password_obtained) {
452 42 : cli_credentials_set_password(cred, NULL, obtained);
453 42 : if (nt_hash) {
454 42 : cred->nt_hash = talloc(cred, struct samr_Password);
455 42 : if (cred->nt_hash == NULL) {
456 0 : return false;
457 : }
458 42 : *cred->nt_hash = *nt_hash;
459 : } else {
460 0 : cred->nt_hash = NULL;
461 : }
462 36 : return true;
463 : }
464 :
465 0 : return false;
466 : }
467 :
468 0 : _PUBLIC_ bool cli_credentials_set_old_nt_hash(struct cli_credentials *cred,
469 : const struct samr_Password *nt_hash)
470 : {
471 0 : cli_credentials_set_old_password(cred, NULL, CRED_SPECIFIED);
472 0 : if (nt_hash) {
473 0 : cred->old_nt_hash = talloc(cred, struct samr_Password);
474 0 : if (cred->old_nt_hash == NULL) {
475 0 : return false;
476 : }
477 0 : *cred->old_nt_hash = *nt_hash;
478 : } else {
479 0 : cred->old_nt_hash = NULL;
480 : }
481 :
482 0 : return true;
483 : }
484 :
485 0 : _PUBLIC_ bool cli_credentials_set_ntlm_response(struct cli_credentials *cred,
486 : const DATA_BLOB *lm_response,
487 : const DATA_BLOB *nt_response,
488 : enum credentials_obtained obtained)
489 : {
490 0 : if (obtained >= cred->password_obtained) {
491 0 : cli_credentials_set_password(cred, NULL, obtained);
492 0 : if (nt_response) {
493 0 : cred->nt_response = data_blob_talloc(cred, nt_response->data, nt_response->length);
494 0 : talloc_steal(cred, cred->nt_response.data);
495 : }
496 0 : if (nt_response) {
497 0 : cred->lm_response = data_blob_talloc(cred, lm_response->data, lm_response->length);
498 : }
499 0 : return true;
500 : }
501 :
502 0 : return false;
503 : }
504 :
|