2
Unix SMB/CIFS implementation.
3
code to manipulate domain credentials
4
Copyright (C) Andrew Tridgell 1997-1998
5
Largely rewritten by Jeremy Allison 2005.
7
This program is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 3 of the License, or
10
(at your option) any later version.
12
This program is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with this program. If not, see <http://www.gnu.org/licenses/>.
23
/****************************************************************************
24
Represent a credential as a string.
25
****************************************************************************/
27
char *credstr(const unsigned char *cred)
30
result = talloc_asprintf(talloc_tos(),
31
"%02X%02X%02X%02X%02X%02X%02X%02X",
32
cred[0], cred[1], cred[2], cred[3],
33
cred[4], cred[5], cred[6], cred[7]);
34
SMB_ASSERT(result != NULL);
38
/****************************************************************************
39
Setup the session key and the client and server creds in dc.
40
ADS-style 128 bit session keys.
41
Used by both client and server creds setup.
42
****************************************************************************/
44
static void creds_init_128(struct dcinfo *dc,
45
const struct netr_Credential *clnt_chal_in,
46
const struct netr_Credential *srv_chal_in,
47
const unsigned char mach_pw[16])
49
unsigned char zero[4], tmp[16];
51
struct MD5Context md5;
53
/* Just in case this isn't already there */
54
memcpy(dc->mach_pw, mach_pw, 16);
56
ZERO_STRUCT(dc->sess_key);
58
memset(zero, 0, sizeof(zero));
60
hmac_md5_init_rfc2104(mach_pw, 16, &ctx);
62
MD5Update(&md5, zero, sizeof(zero));
63
MD5Update(&md5, clnt_chal_in->data, 8);
64
MD5Update(&md5, srv_chal_in->data, 8);
66
hmac_md5_update(tmp, sizeof(tmp), &ctx);
67
hmac_md5_final(dc->sess_key, &ctx);
70
DEBUG(5,("creds_init_128\n"));
71
DEBUG(5,("\tclnt_chal_in: %s\n", credstr(clnt_chal_in->data)));
72
DEBUG(5,("\tsrv_chal_in : %s\n", credstr(srv_chal_in->data)));
73
dump_data_pw("\tsession_key ", (const unsigned char *)dc->sess_key, 16);
75
/* Generate the next client and server creds. */
77
des_crypt112(dc->clnt_chal.data, /* output */
78
clnt_chal_in->data, /* input */
79
dc->sess_key, /* input */
82
des_crypt112(dc->srv_chal.data, /* output */
83
srv_chal_in->data, /* input */
84
dc->sess_key, /* input */
87
/* Seed is the client chal. */
88
memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
91
/****************************************************************************
92
Setup the session key and the client and server creds in dc.
93
Used by both client and server creds setup.
94
****************************************************************************/
96
static void creds_init_64(struct dcinfo *dc,
97
const struct netr_Credential *clnt_chal_in,
98
const struct netr_Credential *srv_chal_in,
99
const unsigned char mach_pw[16])
102
unsigned char sum2[8];
104
/* Just in case this isn't already there */
105
if (dc->mach_pw != mach_pw) {
106
memcpy(dc->mach_pw, mach_pw, 16);
109
sum[0] = IVAL(clnt_chal_in->data, 0) + IVAL(srv_chal_in->data, 0);
110
sum[1] = IVAL(clnt_chal_in->data, 4) + IVAL(srv_chal_in->data, 4);
112
SIVAL(sum2,0,sum[0]);
113
SIVAL(sum2,4,sum[1]);
115
ZERO_STRUCT(dc->sess_key);
117
des_crypt128(dc->sess_key, sum2, dc->mach_pw);
120
DEBUG(5,("creds_init_64\n"));
121
DEBUG(5,("\tclnt_chal_in: %s\n", credstr(clnt_chal_in->data)));
122
DEBUG(5,("\tsrv_chal_in : %s\n", credstr(srv_chal_in->data)));
123
DEBUG(5,("\tclnt+srv : %s\n", credstr(sum2)));
124
DEBUG(5,("\tsess_key_out : %s\n", credstr(dc->sess_key)));
126
/* Generate the next client and server creds. */
128
des_crypt112(dc->clnt_chal.data, /* output */
129
clnt_chal_in->data, /* input */
130
dc->sess_key, /* input */
133
des_crypt112(dc->srv_chal.data, /* output */
134
srv_chal_in->data, /* input */
135
dc->sess_key, /* input */
138
/* Seed is the client chal. */
139
memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
142
/****************************************************************************
143
Utility function to step credential chain one forward.
144
Deliberately doesn't update the seed. See reseed comment below.
145
****************************************************************************/
147
static void creds_step(struct dcinfo *dc)
149
struct netr_Credential time_chal;
151
DEBUG(5,("\tsequence = 0x%x\n", (unsigned int)dc->sequence ));
153
DEBUG(5,("\tseed: %s\n", credstr(dc->seed_chal.data) ));
155
SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence);
156
SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
158
DEBUG(5,("\tseed+seq %s\n", credstr(time_chal.data) ));
160
des_crypt112(dc->clnt_chal.data, time_chal.data, dc->sess_key, 1);
162
DEBUG(5,("\tCLIENT %s\n", credstr(dc->clnt_chal.data) ));
164
SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1);
165
SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
167
DEBUG(5,("\tseed+seq+1 %s\n", credstr(time_chal.data) ));
169
des_crypt112(dc->srv_chal.data, time_chal.data, dc->sess_key, 1);
171
DEBUG(5,("\tSERVER %s\n", credstr(dc->srv_chal.data) ));
174
/****************************************************************************
175
Create a server credential struct.
176
****************************************************************************/
178
void creds_server_init(uint32 neg_flags,
180
struct netr_Credential *clnt_chal,
181
struct netr_Credential *srv_chal,
182
const unsigned char mach_pw[16],
183
struct netr_Credential *init_chal_out)
185
DEBUG(10,("creds_server_init: neg_flags : %x\n", (unsigned int)neg_flags));
186
DEBUG(10,("creds_server_init: client chal : %s\n", credstr(clnt_chal->data) ));
187
DEBUG(10,("creds_server_init: server chal : %s\n", credstr(srv_chal->data) ));
188
dump_data_pw("creds_server_init: machine pass", mach_pw, 16);
190
/* Generate the session key and the next client and server creds. */
191
if (neg_flags & NETLOGON_NEG_128BIT) {
203
dump_data_pw("creds_server_init: session key", dc->sess_key, 16);
205
DEBUG(10,("creds_server_init: clnt : %s\n", credstr(dc->clnt_chal.data) ));
206
DEBUG(10,("creds_server_init: server : %s\n", credstr(dc->srv_chal.data) ));
207
DEBUG(10,("creds_server_init: seed : %s\n", credstr(dc->seed_chal.data) ));
209
memcpy(init_chal_out->data, dc->srv_chal.data, 8);
212
/****************************************************************************
213
Check a credential sent by the client.
214
****************************************************************************/
216
bool netlogon_creds_server_check(const struct dcinfo *dc,
217
const struct netr_Credential *rcv_cli_chal_in)
219
if (memcmp(dc->clnt_chal.data, rcv_cli_chal_in->data, 8)) {
220
DEBUG(5,("netlogon_creds_server_check: challenge : %s\n",
221
credstr(rcv_cli_chal_in->data)));
222
DEBUG(5,("calculated: %s\n", credstr(dc->clnt_chal.data)));
223
DEBUG(2,("netlogon_creds_server_check: credentials check failed.\n"));
227
DEBUG(10,("netlogon_creds_server_check: credentials check OK.\n"));
231
/****************************************************************************
232
Replace current seed chal. Internal function - due to split server step below.
233
****************************************************************************/
235
static void creds_reseed(struct dcinfo *dc)
237
struct netr_Credential time_chal;
239
SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1);
240
SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
242
dc->seed_chal = time_chal;
244
DEBUG(5,("cred_reseed: seed %s\n", credstr(dc->seed_chal.data) ));
247
/****************************************************************************
248
Step the server credential chain one forward.
249
****************************************************************************/
251
bool netlogon_creds_server_step(struct dcinfo *dc,
252
const struct netr_Authenticator *received_cred,
253
struct netr_Authenticator *cred_out)
256
struct dcinfo tmp_dc = *dc;
258
if (!received_cred || !cred_out) {
262
/* Do all operations on a temporary copy of the dc,
263
which we throw away if the checks fail. */
265
tmp_dc.sequence = received_cred->timestamp;
269
/* Create the outgoing credentials */
270
cred_out->timestamp = tmp_dc.sequence + 1;
271
memcpy(&cred_out->cred, &tmp_dc.srv_chal, sizeof(cred_out->cred));
273
creds_reseed(&tmp_dc);
275
ret = netlogon_creds_server_check(&tmp_dc, &received_cred->cred);
280
/* creds step succeeded - replace the current creds. */
285
/****************************************************************************
286
Create a client credential struct.
287
****************************************************************************/
289
void creds_client_init(uint32 neg_flags,
291
struct netr_Credential *clnt_chal,
292
struct netr_Credential *srv_chal,
293
const unsigned char mach_pw[16],
294
struct netr_Credential *init_chal_out)
296
dc->sequence = time(NULL);
298
DEBUG(10,("creds_client_init: neg_flags : %x\n", (unsigned int)neg_flags));
299
DEBUG(10,("creds_client_init: client chal : %s\n", credstr(clnt_chal->data) ));
300
DEBUG(10,("creds_client_init: server chal : %s\n", credstr(srv_chal->data) ));
301
dump_data_pw("creds_client_init: machine pass", (const unsigned char *)mach_pw, 16);
303
/* Generate the session key and the next client and server creds. */
304
if (neg_flags & NETLOGON_NEG_128BIT) {
316
dump_data_pw("creds_client_init: session key", dc->sess_key, 16);
318
DEBUG(10,("creds_client_init: clnt : %s\n", credstr(dc->clnt_chal.data) ));
319
DEBUG(10,("creds_client_init: server : %s\n", credstr(dc->srv_chal.data) ));
320
DEBUG(10,("creds_client_init: seed : %s\n", credstr(dc->seed_chal.data) ));
322
memcpy(init_chal_out->data, dc->clnt_chal.data, 8);
325
/****************************************************************************
326
Check a credential returned by the server.
327
****************************************************************************/
329
bool netlogon_creds_client_check(const struct dcinfo *dc,
330
const struct netr_Credential *rcv_srv_chal_in)
332
if (memcmp(dc->srv_chal.data, rcv_srv_chal_in->data,
333
sizeof(dc->srv_chal.data))) {
335
DEBUG(0,("netlogon_creds_client_check: credentials check failed.\n"));
336
DEBUGADD(5,("netlogon_creds_client_check: challenge : %s\n",
337
credstr(rcv_srv_chal_in->data)));
338
DEBUGADD(5,("calculated: %s\n", credstr(dc->srv_chal.data)));
342
DEBUG(10,("netlogon_creds_client_check: credentials check OK.\n"));
348
/****************************************************************************
349
Step the client credentials to the next element in the chain, updating the
350
current client and server credentials and the seed
351
produce the next authenticator in the sequence ready to send to
353
****************************************************************************/
355
void netlogon_creds_client_step(struct dcinfo *dc,
356
struct netr_Authenticator *next_cred_out)
362
memcpy(&next_cred_out->cred.data, &dc->clnt_chal.data,
363
sizeof(next_cred_out->cred.data));
364
next_cred_out->timestamp = dc->sequence;