s4:minschema/fullschema - add correct header comments
[Samba/aatanasov.git] / libcli / auth / credentials.c
blob87d1866ca49fbd11c0628723a643f4cf86235d87
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"
28 static void netlogon_creds_step_crypt(struct netlogon_creds_CredentialState *creds,
29 const struct netr_Credential *in,
30 struct netr_Credential *out)
32 des_crypt112(out->data, in->data, creds->session_key, 1);
36 initialise the credentials state for old-style 64 bit session keys
38 this call is made after the netr_ServerReqChallenge call
40 static void netlogon_creds_init_64bit(struct netlogon_creds_CredentialState *creds,
41 const struct netr_Credential *client_challenge,
42 const struct netr_Credential *server_challenge,
43 const struct samr_Password *machine_password)
45 uint32_t sum[2];
46 uint8_t sum2[8];
48 sum[0] = IVAL(client_challenge->data, 0) + IVAL(server_challenge->data, 0);
49 sum[1] = IVAL(client_challenge->data, 4) + IVAL(server_challenge->data, 4);
51 SIVAL(sum2,0,sum[0]);
52 SIVAL(sum2,4,sum[1]);
54 ZERO_STRUCT(creds->session_key);
56 des_crypt128(creds->session_key, sum2, machine_password->hash);
60 initialise the credentials state for ADS-style 128 bit session keys
62 this call is made after the netr_ServerReqChallenge call
64 static void netlogon_creds_init_128bit(struct netlogon_creds_CredentialState *creds,
65 const struct netr_Credential *client_challenge,
66 const struct netr_Credential *server_challenge,
67 const struct samr_Password *machine_password)
69 unsigned char zero[4], tmp[16];
70 HMACMD5Context ctx;
71 struct MD5Context md5;
73 ZERO_STRUCT(creds->session_key);
75 memset(zero, 0, sizeof(zero));
77 hmac_md5_init_rfc2104(machine_password->hash, sizeof(machine_password->hash), &ctx);
78 MD5Init(&md5);
79 MD5Update(&md5, zero, sizeof(zero));
80 MD5Update(&md5, client_challenge->data, 8);
81 MD5Update(&md5, server_challenge->data, 8);
82 MD5Final(tmp, &md5);
83 hmac_md5_update(tmp, sizeof(tmp), &ctx);
84 hmac_md5_final(creds->session_key, &ctx);
87 static void netlogon_creds_first_step(struct netlogon_creds_CredentialState *creds,
88 const struct netr_Credential *client_challenge,
89 const struct netr_Credential *server_challenge)
91 netlogon_creds_step_crypt(creds, client_challenge, &creds->client);
93 netlogon_creds_step_crypt(creds, server_challenge, &creds->server);
95 creds->seed = creds->client;
99 step the credentials to the next element in the chain, updating the
100 current client and server credentials and the seed
102 static void netlogon_creds_step(struct netlogon_creds_CredentialState *creds)
104 struct netr_Credential time_cred;
106 DEBUG(5,("\tseed %08x:%08x\n",
107 IVAL(creds->seed.data, 0), IVAL(creds->seed.data, 4)));
109 SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence);
110 SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
112 DEBUG(5,("\tseed+time %08x:%08x\n", IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
114 netlogon_creds_step_crypt(creds, &time_cred, &creds->client);
116 DEBUG(5,("\tCLIENT %08x:%08x\n",
117 IVAL(creds->client.data, 0), IVAL(creds->client.data, 4)));
119 SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence + 1);
120 SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
122 DEBUG(5,("\tseed+time+1 %08x:%08x\n",
123 IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
125 netlogon_creds_step_crypt(creds, &time_cred, &creds->server);
127 DEBUG(5,("\tSERVER %08x:%08x\n",
128 IVAL(creds->server.data, 0), IVAL(creds->server.data, 4)));
130 creds->seed = time_cred;
135 DES encrypt a 8 byte LMSessionKey buffer using the Netlogon session key
137 void netlogon_creds_des_encrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key)
139 struct netr_LMSessionKey tmp;
140 des_crypt56(tmp.key, key->key, creds->session_key, 1);
141 *key = tmp;
145 DES decrypt a 8 byte LMSessionKey buffer using the Netlogon session key
147 void netlogon_creds_des_decrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key)
149 struct netr_LMSessionKey tmp;
150 des_crypt56(tmp.key, key->key, creds->session_key, 0);
151 *key = tmp;
155 DES encrypt a 16 byte password buffer using the session key
157 void netlogon_creds_des_encrypt(struct netlogon_creds_CredentialState *creds, struct samr_Password *pass)
159 struct samr_Password tmp;
160 des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 1);
161 *pass = tmp;
165 DES decrypt a 16 byte password buffer using the session key
167 void netlogon_creds_des_decrypt(struct netlogon_creds_CredentialState *creds, struct samr_Password *pass)
169 struct samr_Password tmp;
170 des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 0);
171 *pass = tmp;
175 ARCFOUR encrypt/decrypt a password buffer using the session key
177 void netlogon_creds_arcfour_crypt(struct netlogon_creds_CredentialState *creds, uint8_t *data, size_t len)
179 DATA_BLOB session_key = data_blob(creds->session_key, 16);
181 arcfour_crypt_blob(data, len, &session_key);
183 data_blob_free(&session_key);
186 /*****************************************************************
187 The above functions are common to the client and server interface
188 next comes the client specific functions
189 ******************************************************************/
192 initialise the credentials chain and return the first client
193 credentials
196 struct netlogon_creds_CredentialState *netlogon_creds_client_init(TALLOC_CTX *mem_ctx,
197 const char *client_account,
198 const char *client_computer_name,
199 const struct netr_Credential *client_challenge,
200 const struct netr_Credential *server_challenge,
201 const struct samr_Password *machine_password,
202 struct netr_Credential *initial_credential,
203 uint32_t negotiate_flags)
205 struct netlogon_creds_CredentialState *creds = talloc(mem_ctx, struct netlogon_creds_CredentialState);
207 if (!creds) {
208 return NULL;
211 creds->sequence = time(NULL);
212 creds->negotiate_flags = negotiate_flags;
214 creds->computer_name = talloc_strdup(creds, client_computer_name);
215 if (!creds->computer_name) {
216 talloc_free(creds);
217 return NULL;
219 creds->account_name = talloc_strdup(creds, client_account);
220 if (!creds->account_name) {
221 talloc_free(creds);
222 return NULL;
225 dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
226 dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
227 dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
229 if (negotiate_flags & NETLOGON_NEG_128BIT) {
230 netlogon_creds_init_128bit(creds, client_challenge, server_challenge, machine_password);
231 } else {
232 netlogon_creds_init_64bit(creds, client_challenge, server_challenge, machine_password);
235 netlogon_creds_first_step(creds, client_challenge, server_challenge);
237 dump_data_pw("Session key", creds->session_key, 16);
238 dump_data_pw("Credential ", creds->client.data, 8);
240 *initial_credential = creds->client;
241 return creds;
245 initialise the credentials structure with only a session key. The caller better know what they are doing!
248 struct netlogon_creds_CredentialState *netlogon_creds_client_init_session_key(TALLOC_CTX *mem_ctx,
249 const uint8_t session_key[16])
251 struct netlogon_creds_CredentialState *creds = talloc(mem_ctx, struct netlogon_creds_CredentialState);
253 if (!creds) {
254 return NULL;
257 memcpy(creds->session_key, session_key, 16);
259 return creds;
263 step the credentials to the next element in the chain, updating the
264 current client and server credentials and the seed
266 produce the next authenticator in the sequence ready to send to
267 the server
269 void netlogon_creds_client_authenticator(struct netlogon_creds_CredentialState *creds,
270 struct netr_Authenticator *next)
272 creds->sequence += 2;
273 netlogon_creds_step(creds);
275 next->cred = creds->client;
276 next->timestamp = creds->sequence;
280 check that a credentials reply from a server is correct
282 bool netlogon_creds_client_check(struct netlogon_creds_CredentialState *creds,
283 const struct netr_Credential *received_credentials)
285 if (!received_credentials ||
286 memcmp(received_credentials->data, creds->server.data, 8) != 0) {
287 DEBUG(2,("credentials check failed\n"));
288 return false;
290 return true;
294 /*****************************************************************
295 The above functions are common to the client and server interface
296 next comes the server specific functions
297 ******************************************************************/
300 check that a credentials reply from a server is correct
302 static bool netlogon_creds_server_check_internal(const struct netlogon_creds_CredentialState *creds,
303 const struct netr_Credential *received_credentials)
305 if (memcmp(received_credentials->data, creds->client.data, 8) != 0) {
306 DEBUG(2,("credentials check failed\n"));
307 dump_data_pw("client creds", creds->client.data, 8);
308 dump_data_pw("calc creds", received_credentials->data, 8);
309 return false;
311 return true;
315 initialise the credentials chain and return the first server
316 credentials
318 struct netlogon_creds_CredentialState *netlogon_creds_server_init(TALLOC_CTX *mem_ctx,
319 const char *client_account,
320 const char *client_computer_name,
321 uint16_t secure_channel_type,
322 const struct netr_Credential *client_challenge,
323 const struct netr_Credential *server_challenge,
324 const struct samr_Password *machine_password,
325 struct netr_Credential *credentials_in,
326 struct netr_Credential *credentials_out,
327 uint32_t negotiate_flags)
330 struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
332 if (!creds) {
333 return NULL;
336 creds->negotiate_flags = negotiate_flags;
337 creds->secure_channel_type = secure_channel_type;
339 creds->computer_name = talloc_strdup(creds, client_computer_name);
340 if (!creds->computer_name) {
341 talloc_free(creds);
342 return NULL;
344 creds->account_name = talloc_strdup(creds, client_account);
345 if (!creds->account_name) {
346 talloc_free(creds);
347 return NULL;
350 if (negotiate_flags & NETLOGON_NEG_128BIT) {
351 netlogon_creds_init_128bit(creds, client_challenge, server_challenge,
352 machine_password);
353 } else {
354 netlogon_creds_init_64bit(creds, client_challenge, server_challenge,
355 machine_password);
358 netlogon_creds_first_step(creds, client_challenge, server_challenge);
360 /* And before we leak information about the machine account
361 * password, check that they got the first go right */
362 if (!netlogon_creds_server_check_internal(creds, credentials_in)) {
363 talloc_free(creds);
364 return NULL;
367 *credentials_out = creds->server;
369 return creds;
372 NTSTATUS netlogon_creds_server_step_check(struct netlogon_creds_CredentialState *creds,
373 struct netr_Authenticator *received_authenticator,
374 struct netr_Authenticator *return_authenticator)
376 if (!received_authenticator || !return_authenticator) {
377 return NT_STATUS_INVALID_PARAMETER;
380 if (!creds) {
381 return NT_STATUS_ACCESS_DENIED;
384 /* TODO: this may allow the a replay attack on a non-signed
385 connection. Should we check that this is increasing? */
386 creds->sequence = received_authenticator->timestamp;
387 netlogon_creds_step(creds);
388 if (netlogon_creds_server_check_internal(creds, &received_authenticator->cred)) {
389 return_authenticator->cred = creds->server;
390 return_authenticator->timestamp = creds->sequence;
391 return NT_STATUS_OK;
392 } else {
393 ZERO_STRUCTP(return_authenticator);
394 return NT_STATUS_ACCESS_DENIED;
398 void netlogon_creds_decrypt_samlogon(struct netlogon_creds_CredentialState *creds,
399 uint16_t validation_level,
400 union netr_Validation *validation)
402 static const char zeros[16];
404 struct netr_SamBaseInfo *base = NULL;
405 switch (validation_level) {
406 case 2:
407 if (validation->sam2) {
408 base = &validation->sam2->base;
410 break;
411 case 3:
412 if (validation->sam3) {
413 base = &validation->sam3->base;
415 break;
416 case 6:
417 if (validation->sam6) {
418 base = &validation->sam6->base;
420 break;
421 default:
422 /* If we can't find it, we can't very well decrypt it */
423 return;
426 if (!base) {
427 return;
430 /* find and decyrpt the session keys, return in parameters above */
431 if (validation_level == 6) {
432 /* they aren't encrypted! */
433 } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
434 if (memcmp(base->key.key, zeros,
435 sizeof(base->key.key)) != 0) {
436 netlogon_creds_arcfour_crypt(creds,
437 base->key.key,
438 sizeof(base->key.key));
441 if (memcmp(base->LMSessKey.key, zeros,
442 sizeof(base->LMSessKey.key)) != 0) {
443 netlogon_creds_arcfour_crypt(creds,
444 base->LMSessKey.key,
445 sizeof(base->LMSessKey.key));
447 } else {
448 if (memcmp(base->LMSessKey.key, zeros,
449 sizeof(base->LMSessKey.key)) != 0) {
450 netlogon_creds_des_decrypt_LMKey(creds,
451 &base->LMSessKey);