s3/packaging: source -> source3
[Samba/gebeck_regimport.git] / libcli / auth / credentials.c
blobdc84ffb474594c3ca67949d4db103dd4d04d90e4
1 /*
2 Unix SMB/CIFS implementation.
4 code to manipulate domain credentials
6 Copyright (C) Andrew Tridgell 1997-2003
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "system/time.h"
25 #include "../lib/crypto/crypto.h"
26 #include "libcli/auth/libcli_auth.h"
29 initialise the credentials state for old-style 64 bit session keys
31 this call is made after the netr_ServerReqChallenge call
33 static void netlogon_creds_init_64bit(struct netlogon_creds_CredentialState *creds,
34 const struct netr_Credential *client_challenge,
35 const struct netr_Credential *server_challenge,
36 const struct samr_Password *machine_password)
38 uint32_t sum[2];
39 uint8_t sum2[8];
41 sum[0] = IVAL(client_challenge->data, 0) + IVAL(server_challenge->data, 0);
42 sum[1] = IVAL(client_challenge->data, 4) + IVAL(server_challenge->data, 4);
44 SIVAL(sum2,0,sum[0]);
45 SIVAL(sum2,4,sum[1]);
47 ZERO_STRUCT(creds->session_key);
49 des_crypt128(creds->session_key, sum2, machine_password->hash);
51 des_crypt112(creds->client.data, client_challenge->data, creds->session_key, 1);
52 des_crypt112(creds->server.data, server_challenge->data, creds->session_key, 1);
54 creds->seed = creds->client;
58 initialise the credentials state for ADS-style 128 bit session keys
60 this call is made after the netr_ServerReqChallenge call
62 static void netlogon_creds_init_128bit(struct netlogon_creds_CredentialState *creds,
63 const struct netr_Credential *client_challenge,
64 const struct netr_Credential *server_challenge,
65 const struct samr_Password *machine_password)
67 unsigned char zero[4], tmp[16];
68 HMACMD5Context ctx;
69 struct MD5Context md5;
71 ZERO_STRUCT(creds->session_key);
73 memset(zero, 0, sizeof(zero));
75 hmac_md5_init_rfc2104(machine_password->hash, sizeof(machine_password->hash), &ctx);
76 MD5Init(&md5);
77 MD5Update(&md5, zero, sizeof(zero));
78 MD5Update(&md5, client_challenge->data, 8);
79 MD5Update(&md5, server_challenge->data, 8);
80 MD5Final(tmp, &md5);
81 hmac_md5_update(tmp, sizeof(tmp), &ctx);
82 hmac_md5_final(creds->session_key, &ctx);
84 creds->client = *client_challenge;
85 creds->server = *server_challenge;
87 des_crypt112(creds->client.data, client_challenge->data, creds->session_key, 1);
88 des_crypt112(creds->server.data, server_challenge->data, creds->session_key, 1);
90 creds->seed = creds->client;
95 step the credentials to the next element in the chain, updating the
96 current client and server credentials and the seed
98 static void netlogon_creds_step(struct netlogon_creds_CredentialState *creds)
100 struct netr_Credential time_cred;
102 DEBUG(5,("\tseed %08x:%08x\n",
103 IVAL(creds->seed.data, 0), IVAL(creds->seed.data, 4)));
105 SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence);
106 SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
108 DEBUG(5,("\tseed+time %08x:%08x\n", IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
110 des_crypt112(creds->client.data, time_cred.data, creds->session_key, 1);
112 DEBUG(5,("\tCLIENT %08x:%08x\n",
113 IVAL(creds->client.data, 0), IVAL(creds->client.data, 4)));
115 SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence + 1);
116 SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
118 DEBUG(5,("\tseed+time+1 %08x:%08x\n",
119 IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
121 des_crypt112(creds->server.data, time_cred.data, creds->session_key, 1);
123 DEBUG(5,("\tSERVER %08x:%08x\n",
124 IVAL(creds->server.data, 0), IVAL(creds->server.data, 4)));
126 creds->seed = time_cred;
131 DES encrypt a 8 byte LMSessionKey buffer using the Netlogon session key
133 void netlogon_creds_des_encrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key)
135 struct netr_LMSessionKey tmp;
136 des_crypt56(tmp.key, key->key, creds->session_key, 1);
137 *key = tmp;
141 DES decrypt a 8 byte LMSessionKey buffer using the Netlogon session key
143 void netlogon_creds_des_decrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key)
145 struct netr_LMSessionKey tmp;
146 des_crypt56(tmp.key, key->key, creds->session_key, 0);
147 *key = tmp;
151 DES encrypt a 16 byte password buffer using the session key
153 void netlogon_creds_des_encrypt(struct netlogon_creds_CredentialState *creds, struct samr_Password *pass)
155 struct samr_Password tmp;
156 des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 1);
157 *pass = tmp;
161 DES decrypt a 16 byte password buffer using the session key
163 void netlogon_creds_des_decrypt(struct netlogon_creds_CredentialState *creds, struct samr_Password *pass)
165 struct samr_Password tmp;
166 des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 0);
167 *pass = tmp;
171 ARCFOUR encrypt/decrypt a password buffer using the session key
173 void netlogon_creds_arcfour_crypt(struct netlogon_creds_CredentialState *creds, uint8_t *data, size_t len)
175 DATA_BLOB session_key = data_blob(creds->session_key, 16);
177 arcfour_crypt_blob(data, len, &session_key);
179 data_blob_free(&session_key);
182 /*****************************************************************
183 The above functions are common to the client and server interface
184 next comes the client specific functions
185 ******************************************************************/
188 initialise the credentials chain and return the first client
189 credentials
192 struct netlogon_creds_CredentialState *netlogon_creds_client_init(TALLOC_CTX *mem_ctx,
193 const char *client_account,
194 const char *client_computer_name,
195 const struct netr_Credential *client_challenge,
196 const struct netr_Credential *server_challenge,
197 const struct samr_Password *machine_password,
198 struct netr_Credential *initial_credential,
199 uint32_t negotiate_flags)
201 struct netlogon_creds_CredentialState *creds = talloc(mem_ctx, struct netlogon_creds_CredentialState);
203 if (!creds) {
204 return NULL;
207 creds->sequence = time(NULL);
208 creds->negotiate_flags = negotiate_flags;
210 creds->computer_name = talloc_strdup(creds, client_computer_name);
211 if (!creds->computer_name) {
212 talloc_free(creds);
213 return NULL;
215 creds->account_name = talloc_strdup(creds, client_account);
216 if (!creds->account_name) {
217 talloc_free(creds);
218 return NULL;
221 dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
222 dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
223 dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
225 if (negotiate_flags & NETLOGON_NEG_128BIT) {
226 netlogon_creds_init_128bit(creds, client_challenge, server_challenge, machine_password);
227 } else {
228 netlogon_creds_init_64bit(creds, client_challenge, server_challenge, machine_password);
231 dump_data_pw("Session key", creds->session_key, 16);
232 dump_data_pw("Credential ", creds->client.data, 8);
234 *initial_credential = creds->client;
235 return creds;
239 initialise the credentials structure with only a session key. The caller better know what they are doing!
242 struct netlogon_creds_CredentialState *netlogon_creds_client_init_session_key(TALLOC_CTX *mem_ctx,
243 const uint8_t session_key[16])
245 struct netlogon_creds_CredentialState *creds = talloc(mem_ctx, struct netlogon_creds_CredentialState);
247 if (!creds) {
248 return NULL;
251 memcpy(creds->session_key, session_key, 16);
253 return creds;
257 step the credentials to the next element in the chain, updating the
258 current client and server credentials and the seed
260 produce the next authenticator in the sequence ready to send to
261 the server
263 void netlogon_creds_client_authenticator(struct netlogon_creds_CredentialState *creds,
264 struct netr_Authenticator *next)
266 creds->sequence += 2;
267 netlogon_creds_step(creds);
269 next->cred = creds->client;
270 next->timestamp = creds->sequence;
274 check that a credentials reply from a server is correct
276 bool netlogon_creds_client_check(struct netlogon_creds_CredentialState *creds,
277 const struct netr_Credential *received_credentials)
279 if (!received_credentials ||
280 memcmp(received_credentials->data, creds->server.data, 8) != 0) {
281 DEBUG(2,("credentials check failed\n"));
282 return false;
284 return true;
288 /*****************************************************************
289 The above functions are common to the client and server interface
290 next comes the server specific functions
291 ******************************************************************/
294 check that a credentials reply from a server is correct
296 static bool netlogon_creds_server_check_internal(const struct netlogon_creds_CredentialState *creds,
297 const struct netr_Credential *received_credentials)
299 if (memcmp(received_credentials->data, creds->client.data, 8) != 0) {
300 DEBUG(2,("credentials check failed\n"));
301 dump_data_pw("client creds", creds->client.data, 8);
302 dump_data_pw("calc creds", received_credentials->data, 8);
303 return false;
305 return true;
309 initialise the credentials chain and return the first server
310 credentials
312 struct netlogon_creds_CredentialState *netlogon_creds_server_init(TALLOC_CTX *mem_ctx,
313 const char *client_account,
314 const char *client_computer_name,
315 uint16_t secure_channel_type,
316 const struct netr_Credential *client_challenge,
317 const struct netr_Credential *server_challenge,
318 const struct samr_Password *machine_password,
319 struct netr_Credential *credentials_in,
320 struct netr_Credential *credentials_out,
321 uint32_t negotiate_flags)
324 struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
326 if (!creds) {
327 return NULL;
330 creds->negotiate_flags = negotiate_flags;
332 creds->computer_name = talloc_strdup(creds, client_computer_name);
333 if (!creds->computer_name) {
334 talloc_free(creds);
335 return NULL;
337 creds->account_name = talloc_strdup(creds, client_account);
338 if (!creds->account_name) {
339 talloc_free(creds);
340 return NULL;
343 if (negotiate_flags & NETLOGON_NEG_128BIT) {
344 netlogon_creds_init_128bit(creds, client_challenge, server_challenge,
345 machine_password);
346 } else {
347 netlogon_creds_init_64bit(creds, client_challenge, server_challenge,
348 machine_password);
351 /* And before we leak information about the machine account
352 * password, check that they got the first go right */
353 if (!netlogon_creds_server_check_internal(creds, credentials_in)) {
354 talloc_free(creds);
355 return NULL;
358 *credentials_out = creds->server;
360 return creds;
363 NTSTATUS netlogon_creds_server_step_check(struct netlogon_creds_CredentialState *creds,
364 struct netr_Authenticator *received_authenticator,
365 struct netr_Authenticator *return_authenticator)
367 if (!received_authenticator || !return_authenticator) {
368 return NT_STATUS_INVALID_PARAMETER;
371 if (!creds) {
372 return NT_STATUS_ACCESS_DENIED;
375 /* TODO: this may allow the a replay attack on a non-signed
376 connection. Should we check that this is increasing? */
377 creds->sequence = received_authenticator->timestamp;
378 netlogon_creds_step(creds);
379 if (netlogon_creds_server_check_internal(creds, &received_authenticator->cred)) {
380 return_authenticator->cred = creds->server;
381 return_authenticator->timestamp = creds->sequence;
382 return NT_STATUS_OK;
383 } else {
384 ZERO_STRUCTP(return_authenticator);
385 return NT_STATUS_ACCESS_DENIED;
389 void netlogon_creds_decrypt_samlogon(struct netlogon_creds_CredentialState *creds,
390 uint16_t validation_level,
391 union netr_Validation *validation)
393 static const char zeros[16];
395 struct netr_SamBaseInfo *base = NULL;
396 switch (validation_level) {
397 case 2:
398 if (validation->sam2) {
399 base = &validation->sam2->base;
401 break;
402 case 3:
403 if (validation->sam3) {
404 base = &validation->sam3->base;
406 break;
407 case 6:
408 if (validation->sam6) {
409 base = &validation->sam6->base;
411 break;
412 default:
413 /* If we can't find it, we can't very well decrypt it */
414 return;
417 if (!base) {
418 return;
421 /* find and decyrpt the session keys, return in parameters above */
422 if (validation_level == 6) {
423 /* they aren't encrypted! */
424 } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
425 if (memcmp(base->key.key, zeros,
426 sizeof(base->key.key)) != 0) {
427 netlogon_creds_arcfour_crypt(creds,
428 base->key.key,
429 sizeof(base->key.key));
432 if (memcmp(base->LMSessKey.key, zeros,
433 sizeof(base->LMSessKey.key)) != 0) {
434 netlogon_creds_arcfour_crypt(creds,
435 base->LMSessKey.key,
436 sizeof(base->LMSessKey.key));
438 } else {
439 if (memcmp(base->LMSessKey.key, zeros,
440 sizeof(base->LMSessKey.key)) != 0) {
441 netlogon_creds_des_decrypt_LMKey(creds,
442 &base->LMSessKey);