rpcclient3: Factor out cli_rpc_pipe_open_bind_schannel()
[Samba.git] / auth / credentials / credentials_ntlm.c
blobe6859bf9c450add0640c5d1f452ad82d2429e379
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 _PUBLIC_ NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred, TALLOC_CTX *mem_ctx,
32 int *flags,
33 DATA_BLOB challenge,
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) {
49 TALLOC_FREE(frame);
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,
58 cred->nt_response);
59 if (nt_response.data == NULL) {
60 TALLOC_FREE(frame);
61 return NT_STATUS_NO_MEMORY;
64 if (cred->lm_response.length != 0) {
65 lm_response = data_blob_dup_talloc(frame,
66 cred->lm_response);
67 if (lm_response.data == NULL) {
68 TALLOC_FREE(frame);
69 return NT_STATUS_NO_MEMORY;
73 if (cred->lm_response.data == NULL) {
74 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
76 goto done;
79 nt_hash = cli_credentials_get_nt_hash(cred, frame);
81 cli_credentials_get_ntlm_username_domain(cred, frame, &user, &domain);
82 if (user == NULL) {
83 TALLOC_FREE(frame);
84 return NT_STATUS_NO_MEMORY;
86 if (domain == NULL) {
87 TALLOC_FREE(frame);
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
93 * accepted */
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;
103 if (!nt_hash) {
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) {
109 TALLOC_FREE(frame);
110 return NT_STATUS_NO_MEMORY;
112 lm_session_key = data_blob_talloc_zero(frame, 16);
113 if (lm_session_key.data == NULL) {
114 TALLOC_FREE(frame);
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"));
125 TALLOC_FREE(frame);
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,
133 user,
134 domain,
135 nt_hash->hash, &challenge,
136 server_timestamp, &target_info,
137 &lm_response, &nt_response,
138 NULL, &session_key)) {
139 TALLOC_FREE(frame);
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) {
159 TALLOC_FREE(frame);
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) {
178 TALLOC_FREE(frame);
179 return NT_STATUS_NO_MEMORY;
181 SMBOWFencrypt(nt_hash->hash,
182 session_nonce_hash,
183 nt_response.data);
185 session_key = data_blob_talloc_zero(frame, 16);
186 if (session_key.data == NULL) {
187 TALLOC_FREE(frame);
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;
198 } else {
199 const char *password = cli_credentials_get_password(cred);
200 uint8_t lm_hash[16];
201 bool do_lm = false;
203 nt_response = data_blob_talloc_zero(frame, 24);
204 if (nt_response.data == NULL) {
205 TALLOC_FREE(frame);
206 return NT_STATUS_NO_MEMORY;
208 SMBOWFencrypt(nt_hash->hash, challenge.data,
209 nt_response.data);
211 session_key = data_blob_talloc_zero(frame, 16);
212 if (session_key.data == NULL) {
213 TALLOC_FREE(frame);
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);
230 TALLOC_FREE(frame);
231 return NT_STATUS_NO_MEMORY;
234 SMBencrypt_hash(lm_hash,
235 challenge.data,
236 lm_response.data);
237 } else {
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);
242 TALLOC_FREE(frame);
243 return NT_STATUS_NO_MEMORY;
247 if (do_lm) {
248 lm_session_key = data_blob_talloc_zero(frame, 16);
249 if (lm_session_key.data == NULL) {
250 ZERO_STRUCT(lm_hash);
251 TALLOC_FREE(frame);
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);
263 done:
264 if (_lm_response != NULL) {
265 talloc_steal(mem_ctx, lm_response.data);
266 *_lm_response = lm_response;
267 } else {
268 data_blob_clear(&lm_response);
270 if (_nt_response != NULL) {
271 talloc_steal(mem_ctx, nt_response.data);
272 *_nt_response = nt_response;
273 } else {
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;
279 } else {
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;
285 } else {
286 data_blob_clear(&session_key);
288 TALLOC_FREE(frame);
289 return NT_STATUS_OK;
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;
314 bool ok;
316 nt_hash = talloc(cred, struct samr_Password);
317 if (nt_hash == NULL) {
318 return false;
321 ok = convert_string_talloc(cred,
322 CH_UTF16MUNGED, CH_UTF8,
323 password_utf16->data,
324 password_utf16->length,
325 (void *)&password_talloc,
326 &password_len);
327 if (!ok) {
328 TALLOC_FREE(nt_hash);
329 return false;
332 ok = cli_credentials_set_password(cred, password_talloc, obtained);
333 TALLOC_FREE(password_talloc);
334 if (!ok) {
335 TALLOC_FREE(nt_hash);
336 return false;
339 mdfour(nt_hash->hash, password_utf16->data, password_utf16->length);
340 cred->nt_hash = nt_hash;
341 return true;
344 return false;
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;
360 bool ok;
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) {
368 return false;
371 ok = convert_string_talloc(cred,
372 CH_UTF16MUNGED, CH_UTF8,
373 password_utf16->data,
374 password_utf16->length,
375 (void *)&password_talloc,
376 &password_len);
377 if (!ok) {
378 TALLOC_FREE(nt_hash);
379 return false;
382 ok = cli_credentials_set_old_password(cred, password_talloc, CRED_SPECIFIED);
383 TALLOC_FREE(password_talloc);
384 if (!ok) {
385 TALLOC_FREE(nt_hash);
386 return false;
389 mdfour(nt_hash->hash, password_utf16->data, password_utf16->length);
390 cred->old_nt_hash = nt_hash;
391 return true;
394 _PUBLIC_ void cli_credentials_set_password_will_be_nt_hash(struct cli_credentials *cred,
395 bool val)
398 * We set this here and the next cli_credentials_set_password()
399 * that resets the password or password callback
400 * will pick this up.
402 * cli_credentials_set_nt_hash() and
403 * cli_credentials_set_utf16_password() will reset this
404 * to false.
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);
417 if (nt_hash) {
418 cred->nt_hash = talloc(cred, struct samr_Password);
419 if (cred->nt_hash == NULL) {
420 return false;
422 *cred->nt_hash = *nt_hash;
423 } else {
424 cred->nt_hash = NULL;
426 return true;
429 return false;
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);
436 if (nt_hash) {
437 cred->old_nt_hash = talloc(cred, struct samr_Password);
438 if (cred->old_nt_hash == NULL) {
439 return false;
441 *cred->old_nt_hash = *nt_hash;
442 } else {
443 cred->old_nt_hash = NULL;
446 return true;
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);
456 if (nt_response) {
457 cred->nt_response = data_blob_talloc(cred, nt_response->data, nt_response->length);
458 talloc_steal(cred, cred->nt_response.data);
460 if (nt_response) {
461 cred->lm_response = data_blob_talloc(cred, lm_response->data, lm_response->length);
463 return true;
466 return false;