winbindd: add routing_domain as parameter to add_trusted_domain
[Samba.git] / auth / credentials / credentials_ntlm.c
blobeed8924567a214c338076f055080cf571a835c66
1 /*
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/>.
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"
31 #undef DBGC_CLASS
32 #define DBGC_CLASS DBGC_AUTH
34 _PUBLIC_ NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred, TALLOC_CTX *mem_ctx,
35 int *flags,
36 DATA_BLOB challenge,
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) {
52 TALLOC_FREE(frame);
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,
61 cred->nt_response);
62 if (nt_response.data == NULL) {
63 TALLOC_FREE(frame);
64 return NT_STATUS_NO_MEMORY;
67 if (cred->lm_response.length != 0) {
68 lm_response = data_blob_dup_talloc(frame,
69 cred->lm_response);
70 if (lm_response.data == NULL) {
71 TALLOC_FREE(frame);
72 return NT_STATUS_NO_MEMORY;
76 if (cred->lm_response.data == NULL) {
77 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
79 goto done;
82 nt_hash = cli_credentials_get_nt_hash(cred, frame);
84 cli_credentials_get_ntlm_username_domain(cred, frame, &user, &domain);
85 if (user == NULL) {
86 TALLOC_FREE(frame);
87 return NT_STATUS_NO_MEMORY;
89 if (domain == NULL) {
90 TALLOC_FREE(frame);
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
96 * accepted */
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;
106 if (!nt_hash) {
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) {
112 TALLOC_FREE(frame);
113 return NT_STATUS_NO_MEMORY;
115 lm_session_key = data_blob_talloc_zero(frame, 16);
116 if (lm_session_key.data == NULL) {
117 TALLOC_FREE(frame);
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"));
128 TALLOC_FREE(frame);
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,
136 user,
137 domain,
138 nt_hash->hash, &challenge,
139 server_timestamp, &target_info,
140 &lm_response, &nt_response,
141 NULL, &session_key)) {
142 TALLOC_FREE(frame);
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) {
162 TALLOC_FREE(frame);
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) {
181 TALLOC_FREE(frame);
182 return NT_STATUS_NO_MEMORY;
184 SMBOWFencrypt(nt_hash->hash,
185 session_nonce_hash,
186 nt_response.data);
188 session_key = data_blob_talloc_zero(frame, 16);
189 if (session_key.data == NULL) {
190 TALLOC_FREE(frame);
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;
201 } else {
202 const char *password = cli_credentials_get_password(cred);
203 uint8_t lm_hash[16];
204 bool do_lm = false;
206 nt_response = data_blob_talloc_zero(frame, 24);
207 if (nt_response.data == NULL) {
208 TALLOC_FREE(frame);
209 return NT_STATUS_NO_MEMORY;
211 SMBOWFencrypt(nt_hash->hash, challenge.data,
212 nt_response.data);
214 session_key = data_blob_talloc_zero(frame, 16);
215 if (session_key.data == NULL) {
216 TALLOC_FREE(frame);
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);
233 TALLOC_FREE(frame);
234 return NT_STATUS_NO_MEMORY;
237 SMBencrypt_hash(lm_hash,
238 challenge.data,
239 lm_response.data);
240 } else {
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);
245 TALLOC_FREE(frame);
246 return NT_STATUS_NO_MEMORY;
250 if (do_lm) {
251 lm_session_key = data_blob_talloc_zero(frame, 16);
252 if (lm_session_key.data == NULL) {
253 ZERO_STRUCT(lm_hash);
254 TALLOC_FREE(frame);
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);
266 done:
267 if (_lm_response != NULL) {
268 talloc_steal(mem_ctx, lm_response.data);
269 *_lm_response = lm_response;
270 } else {
271 data_blob_clear(&lm_response);
273 if (_nt_response != NULL) {
274 talloc_steal(mem_ctx, nt_response.data);
275 *_nt_response = nt_response;
276 } else {
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;
282 } else {
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;
288 } else {
289 data_blob_clear(&session_key);
291 TALLOC_FREE(frame);
292 return NT_STATUS_OK;
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;
317 bool ok;
319 nt_hash = talloc(cred, struct samr_Password);
320 if (nt_hash == NULL) {
321 return false;
324 ok = convert_string_talloc(cred,
325 CH_UTF16MUNGED, CH_UTF8,
326 password_utf16->data,
327 password_utf16->length,
328 (void *)&password_talloc,
329 &password_len);
330 if (!ok) {
331 TALLOC_FREE(nt_hash);
332 return false;
335 ok = cli_credentials_set_password(cred, password_talloc, obtained);
336 TALLOC_FREE(password_talloc);
337 if (!ok) {
338 TALLOC_FREE(nt_hash);
339 return false;
342 mdfour(nt_hash->hash, password_utf16->data, password_utf16->length);
343 cred->nt_hash = nt_hash;
344 return true;
347 return false;
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;
363 bool ok;
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) {
371 return false;
374 ok = convert_string_talloc(cred,
375 CH_UTF16MUNGED, CH_UTF8,
376 password_utf16->data,
377 password_utf16->length,
378 (void *)&password_talloc,
379 &password_len);
380 if (!ok) {
381 TALLOC_FREE(nt_hash);
382 return false;
385 ok = cli_credentials_set_old_password(cred, password_talloc, CRED_SPECIFIED);
386 TALLOC_FREE(password_talloc);
387 if (!ok) {
388 TALLOC_FREE(nt_hash);
389 return false;
392 mdfour(nt_hash->hash, password_utf16->data, password_utf16->length);
393 cred->old_nt_hash = nt_hash;
394 return true;
397 _PUBLIC_ void cli_credentials_set_password_will_be_nt_hash(struct cli_credentials *cred,
398 bool val)
401 * We set this here and the next cli_credentials_set_password()
402 * that resets the password or password callback
403 * will pick this up.
405 * cli_credentials_set_nt_hash() and
406 * cli_credentials_set_utf16_password() will reset this
407 * to false.
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);
420 if (nt_hash) {
421 cred->nt_hash = talloc(cred, struct samr_Password);
422 if (cred->nt_hash == NULL) {
423 return false;
425 *cred->nt_hash = *nt_hash;
426 } else {
427 cred->nt_hash = NULL;
429 return true;
432 return false;
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);
439 if (nt_hash) {
440 cred->old_nt_hash = talloc(cred, struct samr_Password);
441 if (cred->old_nt_hash == NULL) {
442 return false;
444 *cred->old_nt_hash = *nt_hash;
445 } else {
446 cred->old_nt_hash = NULL;
449 return true;
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);
459 if (nt_response) {
460 cred->nt_response = data_blob_talloc(cred, nt_response->data, nt_response->length);
461 talloc_steal(cred, cred->nt_response.data);
463 if (nt_response) {
464 cred->lm_response = data_blob_talloc(cred, lm_response->data, lm_response->length);
466 return true;
469 return false;