s3/docs: Remove reference to nonexistent file.
[Samba/gbeck.git] / source4 / auth / credentials / credentials_ntlm.c
blobef41971462b0db0d8c0162789dd01091e2b03731
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_ void cli_credentials_get_ntlm_username_domain(struct cli_credentials *cred, TALLOC_CTX *mem_ctx,
31 const char **username,
32 const char **domain)
34 if (cred->principal_obtained > cred->username_obtained) {
35 *domain = talloc_strdup(mem_ctx, "");
36 *username = cli_credentials_get_principal(cred, mem_ctx);
37 } else {
38 *domain = cli_credentials_get_domain(cred);
39 *username = cli_credentials_get_username(cred);
43 _PUBLIC_ NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred, TALLOC_CTX *mem_ctx,
44 int *flags,
45 DATA_BLOB challenge, DATA_BLOB target_info,
46 DATA_BLOB *_lm_response, DATA_BLOB *_nt_response,
47 DATA_BLOB *_lm_session_key, DATA_BLOB *_session_key)
49 const char *user, *domain;
50 DATA_BLOB lm_response, nt_response;
51 DATA_BLOB lm_session_key, session_key;
52 const struct samr_Password *nt_hash;
53 lm_session_key = data_blob(NULL, 0);
55 /* We may already have an NTLM response we prepared earlier.
56 * This is used for NTLM pass-though authentication */
57 if (cred->nt_response.data || cred->lm_response.data) {
58 *_nt_response = cred->nt_response;
59 *_lm_response = cred->lm_response;
61 if (!cred->lm_response.data) {
62 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
64 *_lm_session_key = data_blob(NULL, 0);
65 *_session_key = data_blob(NULL, 0);
66 return NT_STATUS_OK;
69 nt_hash = cli_credentials_get_nt_hash(cred, mem_ctx);
71 cli_credentials_get_ntlm_username_domain(cred, mem_ctx, &user, &domain);
73 /* If we are sending a username@realm login (see function
74 * above), then we will not send LM, it will not be
75 * accepted */
76 if (cred->principal_obtained > cred->username_obtained) {
77 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
80 /* Likewise if we are a machine account (avoid protocol downgrade attacks) */
81 if (cred->machine_account) {
82 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
85 if (cred->use_kerberos == CRED_MUST_USE_KERBEROS) {
86 return NT_STATUS_ACCESS_DENIED;
89 if (!nt_hash) {
90 static const uint8_t zeros[16];
91 /* do nothing - blobs are zero length */
93 /* session key is all zeros */
94 session_key = data_blob_talloc(mem_ctx, zeros, 16);
95 lm_session_key = data_blob_talloc(mem_ctx, zeros, 16);
97 lm_response = data_blob(NULL, 0);
98 nt_response = data_blob(NULL, 0);
100 /* not doing NTLM2 without a password */
101 *flags &= ~CLI_CRED_NTLM2;
102 } else if (*flags & CLI_CRED_NTLMv2_AUTH) {
104 if (!target_info.length) {
105 /* be lazy, match win2k - we can't do NTLMv2 without it */
106 DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n"));
107 return NT_STATUS_INVALID_PARAMETER;
110 /* TODO: if the remote server is standalone, then we should replace 'domain'
111 with the server name as supplied above */
113 if (!SMBNTLMv2encrypt_hash(mem_ctx,
114 user,
115 domain,
116 nt_hash->hash, &challenge,
117 &target_info,
118 &lm_response, &nt_response,
119 NULL, &session_key)) {
120 return NT_STATUS_NO_MEMORY;
123 /* LM Key is incompatible... */
124 *flags &= ~CLI_CRED_LANMAN_AUTH;
125 } else if (*flags & CLI_CRED_NTLM2) {
126 struct MD5Context md5_session_nonce_ctx;
127 uint8_t session_nonce[16];
128 uint8_t session_nonce_hash[16];
129 uint8_t user_session_key[16];
131 lm_response = data_blob_talloc(mem_ctx, NULL, 24);
132 generate_random_buffer(lm_response.data, 8);
133 memset(lm_response.data+8, 0, 16);
135 memcpy(session_nonce, challenge.data, 8);
136 memcpy(&session_nonce[8], lm_response.data, 8);
138 MD5Init(&md5_session_nonce_ctx);
139 MD5Update(&md5_session_nonce_ctx, challenge.data, 8);
140 MD5Update(&md5_session_nonce_ctx, lm_response.data, 8);
141 MD5Final(session_nonce_hash, &md5_session_nonce_ctx);
143 DEBUG(5, ("NTLMSSP challenge set by NTLM2\n"));
144 DEBUG(5, ("challenge is: \n"));
145 dump_data(5, session_nonce_hash, 8);
147 nt_response = data_blob_talloc(mem_ctx, NULL, 24);
148 SMBOWFencrypt(nt_hash->hash,
149 session_nonce_hash,
150 nt_response.data);
152 session_key = data_blob_talloc(mem_ctx, NULL, 16);
154 SMBsesskeygen_ntv1(nt_hash->hash, user_session_key);
155 hmac_md5(user_session_key, session_nonce, sizeof(session_nonce), session_key.data);
156 dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);
158 /* LM Key is incompatible... */
159 *flags &= ~CLI_CRED_LANMAN_AUTH;
160 } else {
161 uint8_t lm_hash[16];
162 nt_response = data_blob_talloc(mem_ctx, NULL, 24);
163 SMBOWFencrypt(nt_hash->hash, challenge.data,
164 nt_response.data);
166 session_key = data_blob_talloc(mem_ctx, NULL, 16);
167 SMBsesskeygen_ntv1(nt_hash->hash, session_key.data);
168 dump_data_pw("NT session key:\n", session_key.data, session_key.length);
170 /* lanman auth is insecure, it may be disabled.
171 We may also not have a password */
172 if (*flags & CLI_CRED_LANMAN_AUTH) {
173 const char *password;
174 password = cli_credentials_get_password(cred);
175 if (!password) {
176 lm_response = nt_response;
177 } else {
178 lm_response = data_blob_talloc(mem_ctx, NULL, 24);
179 if (!SMBencrypt(password,challenge.data,
180 lm_response.data)) {
181 /* If the LM password was too long (and therefore the LM hash being
182 of the first 14 chars only), don't send it.
184 We don't have any better options but to send the NT response
186 data_blob_free(&lm_response);
187 lm_response = nt_response;
188 /* LM Key is incompatible with 'long' passwords */
189 *flags &= ~CLI_CRED_LANMAN_AUTH;
190 } else {
191 E_deshash(password, lm_hash);
192 lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
193 memcpy(lm_session_key.data, lm_hash, 8);
194 memset(&lm_session_key.data[8], '\0', 8);
196 if (!(*flags & CLI_CRED_NTLM_AUTH)) {
197 session_key = lm_session_key;
201 } else {
202 const char *password;
204 /* LM Key is incompatible... */
205 lm_response = nt_response;
206 *flags &= ~CLI_CRED_LANMAN_AUTH;
208 password = cli_credentials_get_password(cred);
209 if (password) {
210 E_deshash(password, lm_hash);
211 lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
212 memcpy(lm_session_key.data, lm_hash, 8);
213 memset(&lm_session_key.data[8], '\0', 8);
217 if (_lm_response) {
218 *_lm_response = lm_response;
220 if (_nt_response) {
221 *_nt_response = nt_response;
223 if (_lm_session_key) {
224 *_lm_session_key = lm_session_key;
226 if (_session_key) {
227 *_session_key = session_key;
229 return NT_STATUS_OK;
232 _PUBLIC_ bool cli_credentials_set_nt_hash(struct cli_credentials *cred,
233 const struct samr_Password *nt_hash,
234 enum credentials_obtained obtained)
236 if (obtained >= cred->password_obtained) {
237 cli_credentials_set_password(cred, NULL, obtained);
238 if (nt_hash) {
239 cred->nt_hash = talloc(cred, struct samr_Password);
240 *cred->nt_hash = *nt_hash;
241 } else {
242 cred->nt_hash = NULL;
244 return true;
247 return false;
250 _PUBLIC_ bool cli_credentials_set_ntlm_response(struct cli_credentials *cred,
251 const DATA_BLOB *lm_response,
252 const DATA_BLOB *nt_response,
253 enum credentials_obtained obtained)
255 if (obtained >= cred->password_obtained) {
256 cli_credentials_set_password(cred, NULL, obtained);
257 if (nt_response) {
258 cred->nt_response = data_blob_talloc(cred, nt_response->data, nt_response->length);
259 talloc_steal(cred, cred->nt_response.data);
261 if (nt_response) {
262 cred->lm_response = data_blob_talloc(cred, lm_response->data, lm_response->length);
264 return true;
267 return false;