source: branches/samba-3.3.x/source/libsmb/credentials.c@ 715

Last change on this file since 715 was 274, checked in by Herwig Bauernfeind, 16 years ago

Update 3.3 branch to 3.3.5

File size: 12.1 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 3 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, see <http://www.gnu.org/licenses/>.
19*/
20
21#include "includes.h"
22
23/****************************************************************************
24 Represent a credential as a string.
25****************************************************************************/
26
27char *credstr(const unsigned char *cred)
28{
29 char *result;
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);
35 return result;
36}
37
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****************************************************************************/
43
44static 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])
48{
49 unsigned char zero[4], tmp[16];
50 HMACMD5Context ctx;
51 struct MD5Context md5;
52
53 /* Just in case this isn't already there */
54 memcpy(dc->mach_pw, mach_pw, 16);
55
56 ZERO_STRUCT(dc->sess_key);
57
58 memset(zero, 0, sizeof(zero));
59
60 hmac_md5_init_rfc2104(mach_pw, 16, &ctx);
61 MD5Init(&md5);
62 MD5Update(&md5, zero, sizeof(zero));
63 MD5Update(&md5, clnt_chal_in->data, 8);
64 MD5Update(&md5, srv_chal_in->data, 8);
65 MD5Final(tmp, &md5);
66 hmac_md5_update(tmp, sizeof(tmp), &ctx);
67 hmac_md5_final(dc->sess_key, &ctx);
68
69 /* debug output */
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);
74
75 /* Generate the next client and server creds. */
76
77 des_crypt112(dc->clnt_chal.data, /* output */
78 clnt_chal_in->data, /* input */
79 dc->sess_key, /* input */
80 1);
81
82 des_crypt112(dc->srv_chal.data, /* output */
83 srv_chal_in->data, /* input */
84 dc->sess_key, /* input */
85 1);
86
87 /* Seed is the client chal. */
88 memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
89}
90
91/****************************************************************************
92 Setup the session key and the client and server creds in dc.
93 Used by both client and server creds setup.
94****************************************************************************/
95
96static 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])
100{
101 uint32 sum[2];
102 unsigned char sum2[8];
103
104 /* Just in case this isn't already there */
105 if (dc->mach_pw != mach_pw) {
106 memcpy(dc->mach_pw, mach_pw, 16);
107 }
108
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);
111
112 SIVAL(sum2,0,sum[0]);
113 SIVAL(sum2,4,sum[1]);
114
115 ZERO_STRUCT(dc->sess_key);
116
117 des_crypt128(dc->sess_key, sum2, dc->mach_pw);
118
119 /* debug output */
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)));
125
126 /* Generate the next client and server creds. */
127
128 des_crypt112(dc->clnt_chal.data, /* output */
129 clnt_chal_in->data, /* input */
130 dc->sess_key, /* input */
131 1);
132
133 des_crypt112(dc->srv_chal.data, /* output */
134 srv_chal_in->data, /* input */
135 dc->sess_key, /* input */
136 1);
137
138 /* Seed is the client chal. */
139 memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
140}
141
142/****************************************************************************
143 Utility function to step credential chain one forward.
144 Deliberately doesn't update the seed. See reseed comment below.
145****************************************************************************/
146
147static void creds_step(struct dcinfo *dc)
148{
149 DOM_CHAL time_chal;
150
151 DEBUG(5,("\tsequence = 0x%x\n", (unsigned int)dc->sequence ));
152
153 DEBUG(5,("\tseed: %s\n", credstr(dc->seed_chal.data) ));
154
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));
157
158 DEBUG(5,("\tseed+seq %s\n", credstr(time_chal.data) ));
159
160 des_crypt112(dc->clnt_chal.data, time_chal.data, dc->sess_key, 1);
161
162 DEBUG(5,("\tCLIENT %s\n", credstr(dc->clnt_chal.data) ));
163
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));
166
167 DEBUG(5,("\tseed+seq+1 %s\n", credstr(time_chal.data) ));
168
169 des_crypt112(dc->srv_chal.data, time_chal.data, dc->sess_key, 1);
170
171 DEBUG(5,("\tSERVER %s\n", credstr(dc->srv_chal.data) ));
172}
173
174/****************************************************************************
175 Create a server credential struct.
176****************************************************************************/
177
178void creds_server_init(uint32 neg_flags,
179 struct dcinfo *dc,
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)
184{
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);
189
190 /* Generate the session key and the next client and server creds. */
191 if (neg_flags & NETLOGON_NEG_128BIT) {
192 creds_init_128(dc,
193 clnt_chal,
194 srv_chal,
195 mach_pw);
196 } else {
197 creds_init_64(dc,
198 clnt_chal,
199 srv_chal,
200 mach_pw);
201 }
202
203 dump_data_pw("creds_server_init: session key", dc->sess_key, 16);
204
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) ));
208
209 memcpy(init_chal_out->data, dc->srv_chal.data, 8);
210}
211
212/****************************************************************************
213 Check a credential sent by the client.
214****************************************************************************/
215
216bool netlogon_creds_server_check(const struct dcinfo *dc,
217 const struct netr_Credential *rcv_cli_chal_in)
218{
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"));
224 return false;
225 }
226
227 DEBUG(10,("netlogon_creds_server_check: credentials check OK.\n"));
228
229 return true;
230}
231/****************************************************************************
232 Replace current seed chal. Internal function - due to split server step below.
233****************************************************************************/
234
235static void creds_reseed(struct dcinfo *dc)
236{
237 struct netr_Credential time_chal;
238
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));
241
242 dc->seed_chal = time_chal;
243
244 DEBUG(5,("cred_reseed: seed %s\n", credstr(dc->seed_chal.data) ));
245}
246
247/****************************************************************************
248 Step the server credential chain one forward.
249****************************************************************************/
250
251bool netlogon_creds_server_step(struct dcinfo *dc,
252 const struct netr_Authenticator *received_cred,
253 struct netr_Authenticator *cred_out)
254{
255 bool ret;
256 struct dcinfo tmp_dc = *dc;
257
258 if (!received_cred || !cred_out) {
259 return false;
260 }
261
262 /* Do all operations on a temporary copy of the dc,
263 which we throw away if the checks fail. */
264
265 tmp_dc.sequence = received_cred->timestamp;
266
267 creds_step(&tmp_dc);
268
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));
272
273 creds_reseed(&tmp_dc);
274
275 ret = netlogon_creds_server_check(&tmp_dc, &received_cred->cred);
276 if (!ret) {
277 return false;
278 }
279
280 /* creds step succeeded - replace the current creds. */
281 *dc = tmp_dc;
282 return true;
283}
284
285/****************************************************************************
286 Create a client credential struct.
287****************************************************************************/
288
289void creds_client_init(uint32 neg_flags,
290 struct dcinfo *dc,
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)
295{
296 dc->sequence = time(NULL);
297
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);
302
303 /* Generate the session key and the next client and server creds. */
304 if (neg_flags & NETLOGON_NEG_128BIT) {
305 creds_init_128(dc,
306 clnt_chal,
307 srv_chal,
308 mach_pw);
309 } else {
310 creds_init_64(dc,
311 clnt_chal,
312 srv_chal,
313 mach_pw);
314 }
315
316 dump_data_pw("creds_client_init: session key", dc->sess_key, 16);
317
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) ));
321
322 memcpy(init_chal_out->data, dc->clnt_chal.data, 8);
323}
324
325/****************************************************************************
326 Check a credential returned by the server.
327****************************************************************************/
328
329bool netlogon_creds_client_check(const struct dcinfo *dc,
330 const struct netr_Credential *rcv_srv_chal_in)
331{
332 if (memcmp(dc->srv_chal.data, rcv_srv_chal_in->data,
333 sizeof(dc->srv_chal.data))) {
334
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)));
339 return false;
340 }
341
342 DEBUG(10,("netlogon_creds_client_check: credentials check OK.\n"));
343
344 return true;
345}
346
347
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
352 the server
353****************************************************************************/
354
355void netlogon_creds_client_step(struct dcinfo *dc,
356 struct netr_Authenticator *next_cred_out)
357{
358 dc->sequence += 2;
359 creds_step(dc);
360 creds_reseed(dc);
361
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;
365}
Note: See TracBrowser for help on using the repository browser.