ctdb: Accept the key in hex format for the pstore command
[Samba.git] / auth / credentials / credentials_ntlm.c
blob4e122772dea8c750897e788b004e1c8ad9d09ea9
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, DATA_BLOB target_info,
34 DATA_BLOB *_lm_response, DATA_BLOB *_nt_response,
35 DATA_BLOB *_lm_session_key, DATA_BLOB *_session_key)
37 const char *user, *domain;
38 DATA_BLOB lm_response, nt_response;
39 DATA_BLOB lm_session_key, session_key;
40 const struct samr_Password *nt_hash;
41 lm_session_key = data_blob(NULL, 0);
43 /* We may already have an NTLM response we prepared earlier.
44 * This is used for NTLM pass-though authentication */
45 if (cred->nt_response.data || cred->lm_response.data) {
46 *_nt_response = cred->nt_response;
47 *_lm_response = cred->lm_response;
49 if (!cred->lm_response.data) {
50 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
52 *_lm_session_key = data_blob(NULL, 0);
53 *_session_key = data_blob(NULL, 0);
54 return NT_STATUS_OK;
57 nt_hash = cli_credentials_get_nt_hash(cred, mem_ctx);
59 cli_credentials_get_ntlm_username_domain(cred, mem_ctx, &user, &domain);
61 /* If we are sending a username@realm login (see function
62 * above), then we will not send LM, it will not be
63 * accepted */
64 if (cred->principal_obtained > cred->username_obtained) {
65 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
68 /* Likewise if we are a machine account (avoid protocol downgrade attacks) */
69 if (cred->machine_account) {
70 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
73 if (cred->use_kerberos == CRED_MUST_USE_KERBEROS) {
74 return NT_STATUS_ACCESS_DENIED;
77 if (!nt_hash) {
78 static const uint8_t zeros[16];
79 /* do nothing - blobs are zero length */
81 /* session key is all zeros */
82 session_key = data_blob_talloc(mem_ctx, zeros, 16);
83 lm_session_key = data_blob_talloc(mem_ctx, zeros, 16);
85 lm_response = data_blob(NULL, 0);
86 nt_response = data_blob(NULL, 0);
88 /* not doing NTLM2 without a password */
89 *flags &= ~CLI_CRED_NTLM2;
90 } else if (*flags & CLI_CRED_NTLMv2_AUTH) {
92 if (!target_info.length) {
93 /* be lazy, match win2k - we can't do NTLMv2 without it */
94 DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n"));
95 return NT_STATUS_INVALID_PARAMETER;
98 /* TODO: if the remote server is standalone, then we should replace 'domain'
99 with the server name as supplied above */
101 if (!SMBNTLMv2encrypt_hash(mem_ctx,
102 user,
103 domain,
104 nt_hash->hash, &challenge,
105 &target_info,
106 &lm_response, &nt_response,
107 NULL, &session_key)) {
108 return NT_STATUS_NO_MEMORY;
111 /* LM Key is incompatible... */
112 *flags &= ~CLI_CRED_LANMAN_AUTH;
113 } else if (*flags & CLI_CRED_NTLM2) {
114 MD5_CTX md5_session_nonce_ctx;
115 uint8_t session_nonce[16];
116 uint8_t session_nonce_hash[16];
117 uint8_t user_session_key[16];
119 lm_response = data_blob_talloc(mem_ctx, NULL, 24);
120 generate_random_buffer(lm_response.data, 8);
121 memset(lm_response.data+8, 0, 16);
123 memcpy(session_nonce, challenge.data, 8);
124 memcpy(&session_nonce[8], lm_response.data, 8);
126 MD5Init(&md5_session_nonce_ctx);
127 MD5Update(&md5_session_nonce_ctx, challenge.data, 8);
128 MD5Update(&md5_session_nonce_ctx, lm_response.data, 8);
129 MD5Final(session_nonce_hash, &md5_session_nonce_ctx);
131 DEBUG(5, ("NTLMSSP challenge set by NTLM2\n"));
132 DEBUG(5, ("challenge is: \n"));
133 dump_data(5, session_nonce_hash, 8);
135 nt_response = data_blob_talloc(mem_ctx, NULL, 24);
136 SMBOWFencrypt(nt_hash->hash,
137 session_nonce_hash,
138 nt_response.data);
140 session_key = data_blob_talloc(mem_ctx, NULL, 16);
142 SMBsesskeygen_ntv1(nt_hash->hash, user_session_key);
143 hmac_md5(user_session_key, session_nonce, sizeof(session_nonce), session_key.data);
144 dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);
146 /* LM Key is incompatible... */
147 *flags &= ~CLI_CRED_LANMAN_AUTH;
148 } else {
149 uint8_t lm_hash[16];
150 nt_response = data_blob_talloc(mem_ctx, NULL, 24);
151 SMBOWFencrypt(nt_hash->hash, challenge.data,
152 nt_response.data);
154 session_key = data_blob_talloc(mem_ctx, NULL, 16);
155 SMBsesskeygen_ntv1(nt_hash->hash, session_key.data);
156 dump_data_pw("NT session key:\n", session_key.data, session_key.length);
158 /* lanman auth is insecure, it may be disabled.
159 We may also not have a password */
160 if (*flags & CLI_CRED_LANMAN_AUTH) {
161 const char *password;
162 password = cli_credentials_get_password(cred);
163 if (!password) {
164 lm_response = nt_response;
165 } else {
166 lm_response = data_blob_talloc(mem_ctx, NULL, 24);
167 if (!SMBencrypt(password,challenge.data,
168 lm_response.data)) {
169 /* If the LM password was too long (and therefore the LM hash being
170 of the first 14 chars only), don't send it.
172 We don't have any better options but to send the NT response
174 data_blob_free(&lm_response);
175 lm_response = nt_response;
176 /* LM Key is incompatible with 'long' passwords */
177 *flags &= ~CLI_CRED_LANMAN_AUTH;
178 } else if (E_deshash(password, lm_hash)) {
179 lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
180 memcpy(lm_session_key.data, lm_hash, 8);
181 memset(&lm_session_key.data[8], '\0', 8);
183 if (!(*flags & CLI_CRED_NTLM_AUTH)) {
184 session_key = lm_session_key;
188 } else {
189 const char *password;
191 /* LM Key is incompatible... */
192 lm_response = nt_response;
193 *flags &= ~CLI_CRED_LANMAN_AUTH;
195 password = cli_credentials_get_password(cred);
196 if (password && E_deshash(password, lm_hash)) {
197 lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
198 memcpy(lm_session_key.data, lm_hash, 8);
199 memset(&lm_session_key.data[8], '\0', 8);
203 if (_lm_response) {
204 *_lm_response = lm_response;
206 if (_nt_response) {
207 *_nt_response = nt_response;
209 if (_lm_session_key) {
210 *_lm_session_key = lm_session_key;
212 if (_session_key) {
213 *_session_key = session_key;
215 return NT_STATUS_OK;
219 * Set a utf16 password on the credentials context, including an indication
220 * of 'how' the password was obtained
222 * This is required because the nt_hash is calculated over the raw utf16 blob,
223 * which might not be completely valid utf16, which means the conversion
224 * from CH_UTF16MUNGED to CH_UTF8 might loose information.
226 _PUBLIC_ bool cli_credentials_set_utf16_password(struct cli_credentials *cred,
227 const DATA_BLOB *password_utf16,
228 enum credentials_obtained obtained)
230 if (password_utf16 == NULL) {
231 return cli_credentials_set_password(cred, NULL, obtained);
234 if (obtained >= cred->password_obtained) {
235 struct samr_Password *nt_hash = NULL;
236 char *password_talloc = NULL;
237 size_t password_len = 0;
238 bool ok;
240 nt_hash = talloc(cred, struct samr_Password);
241 if (nt_hash == NULL) {
242 return false;
245 ok = convert_string_talloc(cred,
246 CH_UTF16MUNGED, CH_UTF8,
247 password_utf16->data,
248 password_utf16->length,
249 (void *)&password_talloc,
250 &password_len);
251 if (!ok) {
252 TALLOC_FREE(nt_hash);
253 return false;
256 ok = cli_credentials_set_password(cred, password_talloc, obtained);
257 TALLOC_FREE(password_talloc);
258 if (!ok) {
259 TALLOC_FREE(nt_hash);
260 return false;
263 mdfour(nt_hash->hash, password_utf16->data, password_utf16->length);
264 cred->nt_hash = nt_hash;
265 return true;
268 return false;
272 * Set a old utf16 password on the credentials context.
274 * This is required because the nt_hash is calculated over the raw utf16 blob,
275 * which might not be completely valid utf16, which means the conversion
276 * from CH_UTF16MUNGED to CH_UTF8 might loose information.
278 _PUBLIC_ bool cli_credentials_set_old_utf16_password(struct cli_credentials *cred,
279 const DATA_BLOB *password_utf16)
281 struct samr_Password *nt_hash = NULL;
282 char *password_talloc = NULL;
283 size_t password_len = 0;
284 bool ok;
286 if (password_utf16 == NULL) {
287 return cli_credentials_set_old_password(cred, NULL, CRED_SPECIFIED);
290 nt_hash = talloc(cred, struct samr_Password);
291 if (nt_hash == NULL) {
292 return false;
295 ok = convert_string_talloc(cred,
296 CH_UTF16MUNGED, CH_UTF8,
297 password_utf16->data,
298 password_utf16->length,
299 (void *)&password_talloc,
300 &password_len);
301 if (!ok) {
302 TALLOC_FREE(nt_hash);
303 return false;
306 ok = cli_credentials_set_old_password(cred, password_talloc, CRED_SPECIFIED);
307 TALLOC_FREE(password_talloc);
308 if (!ok) {
309 TALLOC_FREE(nt_hash);
310 return false;
313 mdfour(nt_hash->hash, password_utf16->data, password_utf16->length);
314 cred->old_nt_hash = nt_hash;
315 return true;
318 _PUBLIC_ bool cli_credentials_set_nt_hash(struct cli_credentials *cred,
319 const struct samr_Password *nt_hash,
320 enum credentials_obtained obtained)
322 if (obtained >= cred->password_obtained) {
323 cli_credentials_set_password(cred, NULL, obtained);
324 if (nt_hash) {
325 cred->nt_hash = talloc(cred, struct samr_Password);
326 if (cred->nt_hash == NULL) {
327 return false;
329 *cred->nt_hash = *nt_hash;
330 } else {
331 cred->nt_hash = NULL;
333 return true;
336 return false;
339 _PUBLIC_ bool cli_credentials_set_old_nt_hash(struct cli_credentials *cred,
340 const struct samr_Password *nt_hash)
342 cli_credentials_set_old_password(cred, NULL, CRED_SPECIFIED);
343 if (nt_hash) {
344 cred->old_nt_hash = talloc(cred, struct samr_Password);
345 if (cred->old_nt_hash == NULL) {
346 return false;
348 *cred->old_nt_hash = *nt_hash;
349 } else {
350 cred->old_nt_hash = NULL;
353 return true;
356 _PUBLIC_ bool cli_credentials_set_ntlm_response(struct cli_credentials *cred,
357 const DATA_BLOB *lm_response,
358 const DATA_BLOB *nt_response,
359 enum credentials_obtained obtained)
361 if (obtained >= cred->password_obtained) {
362 cli_credentials_set_password(cred, NULL, obtained);
363 if (nt_response) {
364 cred->nt_response = data_blob_talloc(cred, nt_response->data, nt_response->length);
365 talloc_steal(cred, cred->nt_response.data);
367 if (nt_response) {
368 cred->lm_response = data_blob_talloc(cred, lm_response->data, lm_response->length);
370 return true;
373 return false;