s4 dns: Move record lookup to dns_utils.c
[Samba/gebeck_regimport.git] / auth / credentials / credentials_ntlm.c
blob7f4af4f08cd8183b829e5bf6b9f6aefe47e30cf4
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"
30 _PUBLIC_ NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred, TALLOC_CTX *mem_ctx,
31 int *flags,
32 DATA_BLOB challenge, DATA_BLOB target_info,
33 DATA_BLOB *_lm_response, DATA_BLOB *_nt_response,
34 DATA_BLOB *_lm_session_key, DATA_BLOB *_session_key)
36 const char *user, *domain;
37 DATA_BLOB lm_response, nt_response;
38 DATA_BLOB lm_session_key, session_key;
39 const struct samr_Password *nt_hash;
40 lm_session_key = data_blob(NULL, 0);
42 /* We may already have an NTLM response we prepared earlier.
43 * This is used for NTLM pass-though authentication */
44 if (cred->nt_response.data || cred->lm_response.data) {
45 *_nt_response = cred->nt_response;
46 *_lm_response = cred->lm_response;
48 if (!cred->lm_response.data) {
49 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
51 *_lm_session_key = data_blob(NULL, 0);
52 *_session_key = data_blob(NULL, 0);
53 return NT_STATUS_OK;
56 nt_hash = cli_credentials_get_nt_hash(cred, mem_ctx);
58 cli_credentials_get_ntlm_username_domain(cred, mem_ctx, &user, &domain);
60 /* If we are sending a username@realm login (see function
61 * above), then we will not send LM, it will not be
62 * accepted */
63 if (cred->principal_obtained > cred->username_obtained) {
64 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
67 /* Likewise if we are a machine account (avoid protocol downgrade attacks) */
68 if (cred->machine_account) {
69 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
72 if (cred->use_kerberos == CRED_MUST_USE_KERBEROS) {
73 return NT_STATUS_ACCESS_DENIED;
76 if (!nt_hash) {
77 static const uint8_t zeros[16];
78 /* do nothing - blobs are zero length */
80 /* session key is all zeros */
81 session_key = data_blob_talloc(mem_ctx, zeros, 16);
82 lm_session_key = data_blob_talloc(mem_ctx, zeros, 16);
84 lm_response = data_blob(NULL, 0);
85 nt_response = data_blob(NULL, 0);
87 /* not doing NTLM2 without a password */
88 *flags &= ~CLI_CRED_NTLM2;
89 } else if (*flags & CLI_CRED_NTLMv2_AUTH) {
91 if (!target_info.length) {
92 /* be lazy, match win2k - we can't do NTLMv2 without it */
93 DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n"));
94 return NT_STATUS_INVALID_PARAMETER;
97 /* TODO: if the remote server is standalone, then we should replace 'domain'
98 with the server name as supplied above */
100 if (!SMBNTLMv2encrypt_hash(mem_ctx,
101 user,
102 domain,
103 nt_hash->hash, &challenge,
104 &target_info,
105 &lm_response, &nt_response,
106 NULL, &session_key)) {
107 return NT_STATUS_NO_MEMORY;
110 /* LM Key is incompatible... */
111 *flags &= ~CLI_CRED_LANMAN_AUTH;
112 } else if (*flags & CLI_CRED_NTLM2) {
113 struct MD5Context md5_session_nonce_ctx;
114 uint8_t session_nonce[16];
115 uint8_t session_nonce_hash[16];
116 uint8_t user_session_key[16];
118 lm_response = data_blob_talloc(mem_ctx, NULL, 24);
119 generate_random_buffer(lm_response.data, 8);
120 memset(lm_response.data+8, 0, 16);
122 memcpy(session_nonce, challenge.data, 8);
123 memcpy(&session_nonce[8], lm_response.data, 8);
125 MD5Init(&md5_session_nonce_ctx);
126 MD5Update(&md5_session_nonce_ctx, challenge.data, 8);
127 MD5Update(&md5_session_nonce_ctx, lm_response.data, 8);
128 MD5Final(session_nonce_hash, &md5_session_nonce_ctx);
130 DEBUG(5, ("NTLMSSP challenge set by NTLM2\n"));
131 DEBUG(5, ("challenge is: \n"));
132 dump_data(5, session_nonce_hash, 8);
134 nt_response = data_blob_talloc(mem_ctx, NULL, 24);
135 SMBOWFencrypt(nt_hash->hash,
136 session_nonce_hash,
137 nt_response.data);
139 session_key = data_blob_talloc(mem_ctx, NULL, 16);
141 SMBsesskeygen_ntv1(nt_hash->hash, user_session_key);
142 hmac_md5(user_session_key, session_nonce, sizeof(session_nonce), session_key.data);
143 dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);
145 /* LM Key is incompatible... */
146 *flags &= ~CLI_CRED_LANMAN_AUTH;
147 } else {
148 uint8_t lm_hash[16];
149 nt_response = data_blob_talloc(mem_ctx, NULL, 24);
150 SMBOWFencrypt(nt_hash->hash, challenge.data,
151 nt_response.data);
153 session_key = data_blob_talloc(mem_ctx, NULL, 16);
154 SMBsesskeygen_ntv1(nt_hash->hash, session_key.data);
155 dump_data_pw("NT session key:\n", session_key.data, session_key.length);
157 /* lanman auth is insecure, it may be disabled.
158 We may also not have a password */
159 if (*flags & CLI_CRED_LANMAN_AUTH) {
160 const char *password;
161 password = cli_credentials_get_password(cred);
162 if (!password) {
163 lm_response = nt_response;
164 } else {
165 lm_response = data_blob_talloc(mem_ctx, NULL, 24);
166 if (!SMBencrypt(password,challenge.data,
167 lm_response.data)) {
168 /* If the LM password was too long (and therefore the LM hash being
169 of the first 14 chars only), don't send it.
171 We don't have any better options but to send the NT response
173 data_blob_free(&lm_response);
174 lm_response = nt_response;
175 /* LM Key is incompatible with 'long' passwords */
176 *flags &= ~CLI_CRED_LANMAN_AUTH;
177 } else {
178 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) {
197 E_deshash(password, lm_hash);
198 lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
199 memcpy(lm_session_key.data, lm_hash, 8);
200 memset(&lm_session_key.data[8], '\0', 8);
204 if (_lm_response) {
205 *_lm_response = lm_response;
207 if (_nt_response) {
208 *_nt_response = nt_response;
210 if (_lm_session_key) {
211 *_lm_session_key = lm_session_key;
213 if (_session_key) {
214 *_session_key = session_key;
216 return NT_STATUS_OK;
219 _PUBLIC_ bool cli_credentials_set_nt_hash(struct cli_credentials *cred,
220 const struct samr_Password *nt_hash,
221 enum credentials_obtained obtained)
223 if (obtained >= cred->password_obtained) {
224 cli_credentials_set_password(cred, NULL, obtained);
225 if (nt_hash) {
226 cred->nt_hash = talloc(cred, struct samr_Password);
227 *cred->nt_hash = *nt_hash;
228 } else {
229 cred->nt_hash = NULL;
231 return true;
234 return false;
237 _PUBLIC_ bool cli_credentials_set_ntlm_response(struct cli_credentials *cred,
238 const DATA_BLOB *lm_response,
239 const DATA_BLOB *nt_response,
240 enum credentials_obtained obtained)
242 if (obtained >= cred->password_obtained) {
243 cli_credentials_set_password(cred, NULL, obtained);
244 if (nt_response) {
245 cred->nt_response = data_blob_talloc(cred, nt_response->data, nt_response->length);
246 talloc_steal(cred, cred->nt_response.data);
248 if (nt_response) {
249 cred->lm_response = data_blob_talloc(cred, lm_response->data, lm_response->length);
251 return true;
254 return false;