source: vendor/3.6.0/libcli/auth/credentials.c

Last change on this file was 740, checked in by Silvan Scherrer, 13 years ago

Samba Server: update vendor to 3.6.0

File size: 15.2 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3
4 code to manipulate domain credentials
5
6 Copyright (C) Andrew Tridgell 1997-2003
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
8
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.
13
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.
18
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/>.
21*/
22
23#include "includes.h"
24#include "system/time.h"
25#include "../lib/crypto/crypto.h"
26#include "libcli/auth/libcli_auth.h"
27#include "../libcli/security/dom_sid.h"
28
29static void netlogon_creds_step_crypt(struct netlogon_creds_CredentialState *creds,
30 const struct netr_Credential *in,
31 struct netr_Credential *out)
32{
33 des_crypt112(out->data, in->data, creds->session_key, 1);
34}
35
36/*
37 initialise the credentials state for old-style 64 bit session keys
38
39 this call is made after the netr_ServerReqChallenge call
40*/
41static void netlogon_creds_init_64bit(struct netlogon_creds_CredentialState *creds,
42 const struct netr_Credential *client_challenge,
43 const struct netr_Credential *server_challenge,
44 const struct samr_Password *machine_password)
45{
46 uint32_t sum[2];
47 uint8_t sum2[8];
48
49 sum[0] = IVAL(client_challenge->data, 0) + IVAL(server_challenge->data, 0);
50 sum[1] = IVAL(client_challenge->data, 4) + IVAL(server_challenge->data, 4);
51
52 SIVAL(sum2,0,sum[0]);
53 SIVAL(sum2,4,sum[1]);
54
55 ZERO_STRUCT(creds->session_key);
56
57 des_crypt128(creds->session_key, sum2, machine_password->hash);
58}
59
60/*
61 initialise the credentials state for ADS-style 128 bit session keys
62
63 this call is made after the netr_ServerReqChallenge call
64*/
65static void netlogon_creds_init_128bit(struct netlogon_creds_CredentialState *creds,
66 const struct netr_Credential *client_challenge,
67 const struct netr_Credential *server_challenge,
68 const struct samr_Password *machine_password)
69{
70 unsigned char zero[4], tmp[16];
71 HMACMD5Context ctx;
72 struct MD5Context md5;
73
74 ZERO_STRUCT(creds->session_key);
75
76 memset(zero, 0, sizeof(zero));
77
78 hmac_md5_init_rfc2104(machine_password->hash, sizeof(machine_password->hash), &ctx);
79 MD5Init(&md5);
80 MD5Update(&md5, zero, sizeof(zero));
81 MD5Update(&md5, client_challenge->data, 8);
82 MD5Update(&md5, server_challenge->data, 8);
83 MD5Final(tmp, &md5);
84 hmac_md5_update(tmp, sizeof(tmp), &ctx);
85 hmac_md5_final(creds->session_key, &ctx);
86}
87
88static void netlogon_creds_first_step(struct netlogon_creds_CredentialState *creds,
89 const struct netr_Credential *client_challenge,
90 const struct netr_Credential *server_challenge)
91{
92 netlogon_creds_step_crypt(creds, client_challenge, &creds->client);
93
94 netlogon_creds_step_crypt(creds, server_challenge, &creds->server);
95
96 creds->seed = creds->client;
97}
98
99/*
100 step the credentials to the next element in the chain, updating the
101 current client and server credentials and the seed
102*/
103static void netlogon_creds_step(struct netlogon_creds_CredentialState *creds)
104{
105 struct netr_Credential time_cred;
106
107 DEBUG(5,("\tseed %08x:%08x\n",
108 IVAL(creds->seed.data, 0), IVAL(creds->seed.data, 4)));
109
110 SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence);
111 SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
112
113 DEBUG(5,("\tseed+time %08x:%08x\n", IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
114
115 netlogon_creds_step_crypt(creds, &time_cred, &creds->client);
116
117 DEBUG(5,("\tCLIENT %08x:%08x\n",
118 IVAL(creds->client.data, 0), IVAL(creds->client.data, 4)));
119
120 SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence + 1);
121 SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
122
123 DEBUG(5,("\tseed+time+1 %08x:%08x\n",
124 IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
125
126 netlogon_creds_step_crypt(creds, &time_cred, &creds->server);
127
128 DEBUG(5,("\tSERVER %08x:%08x\n",
129 IVAL(creds->server.data, 0), IVAL(creds->server.data, 4)));
130
131 creds->seed = time_cred;
132}
133
134
135/*
136 DES encrypt a 8 byte LMSessionKey buffer using the Netlogon session key
137*/
138void netlogon_creds_des_encrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key)
139{
140 struct netr_LMSessionKey tmp;
141 des_crypt56(tmp.key, key->key, creds->session_key, 1);
142 *key = tmp;
143}
144
145/*
146 DES decrypt a 8 byte LMSessionKey buffer using the Netlogon session key
147*/
148void netlogon_creds_des_decrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key)
149{
150 struct netr_LMSessionKey tmp;
151 des_crypt56(tmp.key, key->key, creds->session_key, 0);
152 *key = tmp;
153}
154
155/*
156 DES encrypt a 16 byte password buffer using the session key
157*/
158void netlogon_creds_des_encrypt(struct netlogon_creds_CredentialState *creds, struct samr_Password *pass)
159{
160 struct samr_Password tmp;
161 des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 1);
162 *pass = tmp;
163}
164
165/*
166 DES decrypt a 16 byte password buffer using the session key
167*/
168void netlogon_creds_des_decrypt(struct netlogon_creds_CredentialState *creds, struct samr_Password *pass)
169{
170 struct samr_Password tmp;
171 des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 0);
172 *pass = tmp;
173}
174
175/*
176 ARCFOUR encrypt/decrypt a password buffer using the session key
177*/
178void netlogon_creds_arcfour_crypt(struct netlogon_creds_CredentialState *creds, uint8_t *data, size_t len)
179{
180 DATA_BLOB session_key = data_blob(creds->session_key, 16);
181
182 arcfour_crypt_blob(data, len, &session_key);
183
184 data_blob_free(&session_key);
185}
186
187/*****************************************************************
188The above functions are common to the client and server interface
189next comes the client specific functions
190******************************************************************/
191
192/*
193 initialise the credentials chain and return the first client
194 credentials
195*/
196
197struct netlogon_creds_CredentialState *netlogon_creds_client_init(TALLOC_CTX *mem_ctx,
198 const char *client_account,
199 const char *client_computer_name,
200 const struct netr_Credential *client_challenge,
201 const struct netr_Credential *server_challenge,
202 const struct samr_Password *machine_password,
203 struct netr_Credential *initial_credential,
204 uint32_t negotiate_flags)
205{
206 struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
207
208 if (!creds) {
209 return NULL;
210 }
211
212 creds->sequence = time(NULL);
213 creds->negotiate_flags = negotiate_flags;
214
215 creds->computer_name = talloc_strdup(creds, client_computer_name);
216 if (!creds->computer_name) {
217 talloc_free(creds);
218 return NULL;
219 }
220 creds->account_name = talloc_strdup(creds, client_account);
221 if (!creds->account_name) {
222 talloc_free(creds);
223 return NULL;
224 }
225
226 dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
227 dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
228 dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
229
230 if (negotiate_flags & NETLOGON_NEG_128BIT) {
231 netlogon_creds_init_128bit(creds, client_challenge, server_challenge, machine_password);
232 } else {
233 netlogon_creds_init_64bit(creds, client_challenge, server_challenge, machine_password);
234 }
235
236 netlogon_creds_first_step(creds, client_challenge, server_challenge);
237
238 dump_data_pw("Session key", creds->session_key, 16);
239 dump_data_pw("Credential ", creds->client.data, 8);
240
241 *initial_credential = creds->client;
242 return creds;
243}
244
245/*
246 initialise the credentials structure with only a session key. The caller better know what they are doing!
247 */
248
249struct netlogon_creds_CredentialState *netlogon_creds_client_init_session_key(TALLOC_CTX *mem_ctx,
250 const uint8_t session_key[16])
251{
252 struct netlogon_creds_CredentialState *creds;
253
254 creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
255 if (!creds) {
256 return NULL;
257 }
258
259 memcpy(creds->session_key, session_key, 16);
260
261 return creds;
262}
263
264/*
265 step the credentials to the next element in the chain, updating the
266 current client and server credentials and the seed
267
268 produce the next authenticator in the sequence ready to send to
269 the server
270*/
271void netlogon_creds_client_authenticator(struct netlogon_creds_CredentialState *creds,
272 struct netr_Authenticator *next)
273{
274 creds->sequence += 2;
275 netlogon_creds_step(creds);
276
277 next->cred = creds->client;
278 next->timestamp = creds->sequence;
279}
280
281/*
282 check that a credentials reply from a server is correct
283*/
284bool netlogon_creds_client_check(struct netlogon_creds_CredentialState *creds,
285 const struct netr_Credential *received_credentials)
286{
287 if (!received_credentials ||
288 memcmp(received_credentials->data, creds->server.data, 8) != 0) {
289 DEBUG(2,("credentials check failed\n"));
290 return false;
291 }
292 return true;
293}
294
295
296/*****************************************************************
297The above functions are common to the client and server interface
298next comes the server specific functions
299******************************************************************/
300
301/*
302 check that a credentials reply from a server is correct
303*/
304static bool netlogon_creds_server_check_internal(const struct netlogon_creds_CredentialState *creds,
305 const struct netr_Credential *received_credentials)
306{
307 if (memcmp(received_credentials->data, creds->client.data, 8) != 0) {
308 DEBUG(2,("credentials check failed\n"));
309 dump_data_pw("client creds", creds->client.data, 8);
310 dump_data_pw("calc creds", received_credentials->data, 8);
311 return false;
312 }
313 return true;
314}
315
316/*
317 initialise the credentials chain and return the first server
318 credentials
319*/
320struct netlogon_creds_CredentialState *netlogon_creds_server_init(TALLOC_CTX *mem_ctx,
321 const char *client_account,
322 const char *client_computer_name,
323 uint16_t secure_channel_type,
324 const struct netr_Credential *client_challenge,
325 const struct netr_Credential *server_challenge,
326 const struct samr_Password *machine_password,
327 struct netr_Credential *credentials_in,
328 struct netr_Credential *credentials_out,
329 uint32_t negotiate_flags)
330{
331
332 struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
333
334 if (!creds) {
335 return NULL;
336 }
337
338 creds->negotiate_flags = negotiate_flags;
339 creds->secure_channel_type = secure_channel_type;
340
341 creds->computer_name = talloc_strdup(creds, client_computer_name);
342 if (!creds->computer_name) {
343 talloc_free(creds);
344 return NULL;
345 }
346 creds->account_name = talloc_strdup(creds, client_account);
347 if (!creds->account_name) {
348 talloc_free(creds);
349 return NULL;
350 }
351
352 if (negotiate_flags & NETLOGON_NEG_128BIT) {
353 netlogon_creds_init_128bit(creds, client_challenge, server_challenge,
354 machine_password);
355 } else {
356 netlogon_creds_init_64bit(creds, client_challenge, server_challenge,
357 machine_password);
358 }
359
360 netlogon_creds_first_step(creds, client_challenge, server_challenge);
361
362 /* And before we leak information about the machine account
363 * password, check that they got the first go right */
364 if (!netlogon_creds_server_check_internal(creds, credentials_in)) {
365 talloc_free(creds);
366 return NULL;
367 }
368
369 *credentials_out = creds->server;
370
371 return creds;
372}
373
374NTSTATUS netlogon_creds_server_step_check(struct netlogon_creds_CredentialState *creds,
375 struct netr_Authenticator *received_authenticator,
376 struct netr_Authenticator *return_authenticator)
377{
378 if (!received_authenticator || !return_authenticator) {
379 return NT_STATUS_INVALID_PARAMETER;
380 }
381
382 if (!creds) {
383 return NT_STATUS_ACCESS_DENIED;
384 }
385
386 /* TODO: this may allow the a replay attack on a non-signed
387 connection. Should we check that this is increasing? */
388 creds->sequence = received_authenticator->timestamp;
389 netlogon_creds_step(creds);
390 if (netlogon_creds_server_check_internal(creds, &received_authenticator->cred)) {
391 return_authenticator->cred = creds->server;
392 return_authenticator->timestamp = creds->sequence;
393 return NT_STATUS_OK;
394 } else {
395 ZERO_STRUCTP(return_authenticator);
396 return NT_STATUS_ACCESS_DENIED;
397 }
398}
399
400void netlogon_creds_decrypt_samlogon(struct netlogon_creds_CredentialState *creds,
401 uint16_t validation_level,
402 union netr_Validation *validation)
403{
404 static const char zeros[16];
405
406 struct netr_SamBaseInfo *base = NULL;
407 switch (validation_level) {
408 case 2:
409 if (validation->sam2) {
410 base = &validation->sam2->base;
411 }
412 break;
413 case 3:
414 if (validation->sam3) {
415 base = &validation->sam3->base;
416 }
417 break;
418 case 6:
419 if (validation->sam6) {
420 base = &validation->sam6->base;
421 }
422 break;
423 default:
424 /* If we can't find it, we can't very well decrypt it */
425 return;
426 }
427
428 if (!base) {
429 return;
430 }
431
432 /* find and decyrpt the session keys, return in parameters above */
433 if (validation_level == 6) {
434 /* they aren't encrypted! */
435 } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
436 if (memcmp(base->key.key, zeros,
437 sizeof(base->key.key)) != 0) {
438 netlogon_creds_arcfour_crypt(creds,
439 base->key.key,
440 sizeof(base->key.key));
441 }
442
443 if (memcmp(base->LMSessKey.key, zeros,
444 sizeof(base->LMSessKey.key)) != 0) {
445 netlogon_creds_arcfour_crypt(creds,
446 base->LMSessKey.key,
447 sizeof(base->LMSessKey.key));
448 }
449 } else {
450 if (memcmp(base->LMSessKey.key, zeros,
451 sizeof(base->LMSessKey.key)) != 0) {
452 netlogon_creds_des_decrypt_LMKey(creds,
453 &base->LMSessKey);
454 }
455 }
456}
457
458/*
459 copy a netlogon_creds_CredentialState struct
460*/
461
462struct netlogon_creds_CredentialState *netlogon_creds_copy(TALLOC_CTX *mem_ctx,
463 struct netlogon_creds_CredentialState *creds_in)
464{
465 struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
466
467 if (!creds) {
468 return NULL;
469 }
470
471 creds->sequence = creds_in->sequence;
472 creds->negotiate_flags = creds_in->negotiate_flags;
473 creds->secure_channel_type = creds_in->secure_channel_type;
474
475 creds->computer_name = talloc_strdup(creds, creds_in->computer_name);
476 if (!creds->computer_name) {
477 talloc_free(creds);
478 return NULL;
479 }
480 creds->account_name = talloc_strdup(creds, creds_in->account_name);
481 if (!creds->account_name) {
482 talloc_free(creds);
483 return NULL;
484 }
485
486 if (creds_in->sid) {
487 creds->sid = dom_sid_dup(creds, creds_in->sid);
488 if (!creds->sid) {
489 talloc_free(creds);
490 return NULL;
491 }
492 }
493
494 memcpy(creds->session_key, creds_in->session_key, sizeof(creds->session_key));
495 memcpy(creds->seed.data, creds_in->seed.data, sizeof(creds->seed.data));
496 memcpy(creds->client.data, creds_in->client.data, sizeof(creds->client.data));
497 memcpy(creds->server.data, creds_in->server.data, sizeof(creds->server.data));
498
499 return creds;
500}
Note: See TracBrowser for help on using the repository browser.