source: trunk/samba-3.0.25pre1/source/libsmb/credentials.c@ 16

Last change on this file since 16 was 1, checked in by Paul Smedley, 18 years ago

Initial code import

File size: 11.2 KB
Line 
1/*
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.
6
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 2 of the License, or
10 (at your option) any later version.
11
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.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20*/
21
22#include "includes.h"
23
24/****************************************************************************
25 Represent a credential as a string.
26****************************************************************************/
27
28char *credstr(const unsigned char *cred)
29{
30 static fstring buf;
31 slprintf(buf, sizeof(buf) - 1, "%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 return buf;
35}
36
37/****************************************************************************
38 Setup the session key and the client and server creds in dc.
39 ADS-style 128 bit session keys.
40 Used by both client and server creds setup.
41****************************************************************************/
42
43static void creds_init_128(struct dcinfo *dc,
44 const DOM_CHAL *clnt_chal_in,
45 const DOM_CHAL *srv_chal_in,
46 const unsigned char mach_pw[16])
47{
48 unsigned char zero[4], tmp[16];
49 HMACMD5Context ctx;
50 struct MD5Context md5;
51
52 /* Just in case this isn't already there */
53 memcpy(dc->mach_pw, mach_pw, 16);
54
55 ZERO_STRUCT(dc->sess_key);
56
57 memset(zero, 0, sizeof(zero));
58
59 hmac_md5_init_rfc2104(mach_pw, 16, &ctx);
60 MD5Init(&md5);
61 MD5Update(&md5, zero, sizeof(zero));
62 MD5Update(&md5, clnt_chal_in->data, 8);
63 MD5Update(&md5, srv_chal_in->data, 8);
64 MD5Final(tmp, &md5);
65 hmac_md5_update(tmp, sizeof(tmp), &ctx);
66 hmac_md5_final(dc->sess_key, &ctx);
67
68 /* debug output */
69 DEBUG(5,("creds_init_128\n"));
70 DEBUG(5,("\tclnt_chal_in: %s\n", credstr(clnt_chal_in->data)));
71 DEBUG(5,("\tsrv_chal_in : %s\n", credstr(srv_chal_in->data)));
72 dump_data_pw("\tsession_key ", (const unsigned char *)dc->sess_key, 16);
73
74 /* Generate the next client and server creds. */
75
76 des_crypt112(dc->clnt_chal.data, /* output */
77 clnt_chal_in->data, /* input */
78 dc->sess_key, /* input */
79 1);
80
81 des_crypt112(dc->srv_chal.data, /* output */
82 srv_chal_in->data, /* input */
83 dc->sess_key, /* input */
84 1);
85
86 /* Seed is the client chal. */
87 memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
88}
89
90/****************************************************************************
91 Setup the session key and the client and server creds in dc.
92 Used by both client and server creds setup.
93****************************************************************************/
94
95static void creds_init_64(struct dcinfo *dc,
96 const DOM_CHAL *clnt_chal_in,
97 const DOM_CHAL *srv_chal_in,
98 const unsigned char mach_pw[16])
99{
100 uint32 sum[2];
101 unsigned char sum2[8];
102
103 /* Just in case this isn't already there */
104 memcpy(dc->mach_pw, mach_pw, 16);
105
106 sum[0] = IVAL(clnt_chal_in->data, 0) + IVAL(srv_chal_in->data, 0);
107 sum[1] = IVAL(clnt_chal_in->data, 4) + IVAL(srv_chal_in->data, 4);
108
109 SIVAL(sum2,0,sum[0]);
110 SIVAL(sum2,4,sum[1]);
111
112 ZERO_STRUCT(dc->sess_key);
113
114 des_crypt128(dc->sess_key, sum2, dc->mach_pw);
115
116 /* debug output */
117 DEBUG(5,("creds_init_64\n"));
118 DEBUG(5,("\tclnt_chal_in: %s\n", credstr(clnt_chal_in->data)));
119 DEBUG(5,("\tsrv_chal_in : %s\n", credstr(srv_chal_in->data)));
120 DEBUG(5,("\tclnt+srv : %s\n", credstr(sum2)));
121 DEBUG(5,("\tsess_key_out : %s\n", credstr(dc->sess_key)));
122
123 /* Generate the next client and server creds. */
124
125 des_crypt112(dc->clnt_chal.data, /* output */
126 clnt_chal_in->data, /* input */
127 dc->sess_key, /* input */
128 1);
129
130 des_crypt112(dc->srv_chal.data, /* output */
131 srv_chal_in->data, /* input */
132 dc->sess_key, /* input */
133 1);
134
135 /* Seed is the client chal. */
136 memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
137}
138
139/****************************************************************************
140 Utility function to step credential chain one forward.
141 Deliberately doesn't update the seed. See reseed comment below.
142****************************************************************************/
143
144static void creds_step(struct dcinfo *dc)
145{
146 DOM_CHAL time_chal;
147
148 DEBUG(5,("\tsequence = 0x%x\n", (unsigned int)dc->sequence ));
149
150 DEBUG(5,("\tseed: %s\n", credstr(dc->seed_chal.data) ));
151
152 SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence);
153 SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
154
155 DEBUG(5,("\tseed+seq %s\n", credstr(time_chal.data) ));
156
157 des_crypt112(dc->clnt_chal.data, time_chal.data, dc->sess_key, 1);
158
159 DEBUG(5,("\tCLIENT %s\n", credstr(dc->clnt_chal.data) ));
160
161 SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1);
162 SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
163
164 DEBUG(5,("\tseed+seq+1 %s\n", credstr(time_chal.data) ));
165
166 des_crypt112(dc->srv_chal.data, time_chal.data, dc->sess_key, 1);
167
168 DEBUG(5,("\tSERVER %s\n", credstr(dc->srv_chal.data) ));
169}
170
171/****************************************************************************
172 Create a server credential struct.
173****************************************************************************/
174
175void creds_server_init(uint32 neg_flags,
176 struct dcinfo *dc,
177 DOM_CHAL *clnt_chal,
178 DOM_CHAL *srv_chal,
179 const unsigned char mach_pw[16],
180 DOM_CHAL *init_chal_out)
181{
182 DEBUG(10,("creds_server_init: neg_flags : %x\n", (unsigned int)neg_flags));
183 DEBUG(10,("creds_server_init: client chal : %s\n", credstr(clnt_chal->data) ));
184 DEBUG(10,("creds_server_init: server chal : %s\n", credstr(srv_chal->data) ));
185 dump_data_pw("creds_server_init: machine pass", mach_pw, 16);
186
187 /* Generate the session key and the next client and server creds. */
188 if (neg_flags & NETLOGON_NEG_128BIT) {
189 creds_init_128(dc,
190 clnt_chal,
191 srv_chal,
192 mach_pw);
193 } else {
194 creds_init_64(dc,
195 clnt_chal,
196 srv_chal,
197 mach_pw);
198 }
199
200 dump_data_pw("creds_server_init: session key", dc->sess_key, 16);
201
202 DEBUG(10,("creds_server_init: clnt : %s\n", credstr(dc->clnt_chal.data) ));
203 DEBUG(10,("creds_server_init: server : %s\n", credstr(dc->srv_chal.data) ));
204 DEBUG(10,("creds_server_init: seed : %s\n", credstr(dc->seed_chal.data) ));
205
206 memcpy(init_chal_out->data, dc->srv_chal.data, 8);
207}
208
209/****************************************************************************
210 Check a credential sent by the client.
211****************************************************************************/
212
213BOOL creds_server_check(const struct dcinfo *dc, const DOM_CHAL *rcv_cli_chal_in)
214{
215 if (memcmp(dc->clnt_chal.data, rcv_cli_chal_in->data, 8)) {
216 DEBUG(5,("creds_server_check: challenge : %s\n", credstr(rcv_cli_chal_in->data)));
217 DEBUG(5,("calculated: %s\n", credstr(dc->clnt_chal.data)));
218 DEBUG(2,("creds_server_check: credentials check failed.\n"));
219 return False;
220 }
221 DEBUG(10,("creds_server_check: credentials check OK.\n"));
222 return True;
223}
224
225/****************************************************************************
226 Replace current seed chal. Internal function - due to split server step below.
227****************************************************************************/
228
229static void creds_reseed(struct dcinfo *dc)
230{
231 DOM_CHAL time_chal;
232
233 SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1);
234 SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
235
236 dc->seed_chal = time_chal;
237
238 DEBUG(5,("cred_reseed: seed %s\n", credstr(dc->seed_chal.data) ));
239}
240
241/****************************************************************************
242 Step the server credential chain one forward.
243****************************************************************************/
244
245BOOL creds_server_step(struct dcinfo *dc, const DOM_CRED *received_cred, DOM_CRED *cred_out)
246{
247 BOOL ret;
248 struct dcinfo tmp_dc = *dc;
249
250 /* Do all operations on a temporary copy of the dc,
251 which we throw away if the checks fail. */
252
253 tmp_dc.sequence = received_cred->timestamp.time;
254
255 creds_step(&tmp_dc);
256
257 /* Create the outgoing credentials */
258 cred_out->timestamp.time = tmp_dc.sequence + 1;
259 cred_out->challenge = tmp_dc.srv_chal;
260
261 creds_reseed(&tmp_dc);
262
263 ret = creds_server_check(&tmp_dc, &received_cred->challenge);
264 if (!ret) {
265 return False;
266 }
267
268 /* creds step succeeded - replace the current creds. */
269 *dc = tmp_dc;
270 return True;
271}
272
273/****************************************************************************
274 Create a client credential struct.
275****************************************************************************/
276
277void creds_client_init(uint32 neg_flags,
278 struct dcinfo *dc,
279 DOM_CHAL *clnt_chal,
280 DOM_CHAL *srv_chal,
281 const unsigned char mach_pw[16],
282 DOM_CHAL *init_chal_out)
283{
284 dc->sequence = time(NULL);
285
286 DEBUG(10,("creds_client_init: neg_flags : %x\n", (unsigned int)neg_flags));
287 DEBUG(10,("creds_client_init: client chal : %s\n", credstr(clnt_chal->data) ));
288 DEBUG(10,("creds_client_init: server chal : %s\n", credstr(srv_chal->data) ));
289 dump_data_pw("creds_client_init: machine pass", (const unsigned char *)mach_pw, 16);
290
291 /* Generate the session key and the next client and server creds. */
292 if (neg_flags & NETLOGON_NEG_128BIT) {
293 creds_init_128(dc,
294 clnt_chal,
295 srv_chal,
296 mach_pw);
297 } else {
298 creds_init_64(dc,
299 clnt_chal,
300 srv_chal,
301 mach_pw);
302 }
303
304 dump_data_pw("creds_client_init: session key", dc->sess_key, 16);
305
306 DEBUG(10,("creds_client_init: clnt : %s\n", credstr(dc->clnt_chal.data) ));
307 DEBUG(10,("creds_client_init: server : %s\n", credstr(dc->srv_chal.data) ));
308 DEBUG(10,("creds_client_init: seed : %s\n", credstr(dc->seed_chal.data) ));
309
310 memcpy(init_chal_out->data, dc->clnt_chal.data, 8);
311}
312
313/****************************************************************************
314 Check a credential returned by the server.
315****************************************************************************/
316
317BOOL creds_client_check(const struct dcinfo *dc, const DOM_CHAL *rcv_srv_chal_in)
318{
319 if (memcmp(dc->srv_chal.data, rcv_srv_chal_in->data, 8)) {
320 DEBUG(5,("creds_client_check: challenge : %s\n", credstr(rcv_srv_chal_in->data)));
321 DEBUG(5,("calculated: %s\n", credstr(dc->srv_chal.data)));
322 DEBUG(0,("creds_client_check: credentials check failed.\n"));
323 return False;
324 }
325 DEBUG(10,("creds_client_check: credentials check OK.\n"));
326 return True;
327}
328
329/****************************************************************************
330 Step the client credentials to the next element in the chain, updating the
331 current client and server credentials and the seed
332 produce the next authenticator in the sequence ready to send to
333 the server
334****************************************************************************/
335
336void creds_client_step(struct dcinfo *dc, DOM_CRED *next_cred_out)
337{
338 dc->sequence += 2;
339 creds_step(dc);
340 creds_reseed(dc);
341
342 next_cred_out->challenge = dc->clnt_chal;
343 next_cred_out->timestamp.time = dc->sequence;
344}
Note: See TracBrowser for help on using the repository browser.