source: trunk/samba/source/libsmb/credentials.c @ 26

Last change on this file since 26 was 26, checked in by Paul Smedley, 14 years ago

Updated source to 3.0.25rc1

File size: 11.6 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        if (dc->mach_pw != mach_pw) {
105                memcpy(dc->mach_pw, mach_pw, 16);
106        }
107
108        sum[0] = IVAL(clnt_chal_in->data, 0) + IVAL(srv_chal_in->data, 0);
109        sum[1] = IVAL(clnt_chal_in->data, 4) + IVAL(srv_chal_in->data, 4);
110
111        SIVAL(sum2,0,sum[0]);
112        SIVAL(sum2,4,sum[1]);
113
114        ZERO_STRUCT(dc->sess_key);
115
116        des_crypt128(dc->sess_key, sum2, dc->mach_pw);
117
118        /* debug output */
119        DEBUG(5,("creds_init_64\n"));
120        DEBUG(5,("\tclnt_chal_in: %s\n", credstr(clnt_chal_in->data)));
121        DEBUG(5,("\tsrv_chal_in : %s\n", credstr(srv_chal_in->data)));
122        DEBUG(5,("\tclnt+srv : %s\n", credstr(sum2)));
123        DEBUG(5,("\tsess_key_out : %s\n", credstr(dc->sess_key)));
124
125        /* Generate the next client and server creds. */
126       
127        des_crypt112(dc->clnt_chal.data,                /* output */
128                        clnt_chal_in->data,             /* input */
129                        dc->sess_key,                   /* input */
130                        1);
131
132        des_crypt112(dc->srv_chal.data,                 /* output */
133                        srv_chal_in->data,              /* input */
134                        dc->sess_key,                   /* input */
135                        1);
136
137        /* Seed is the client chal. */
138        memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
139}
140
141/****************************************************************************
142 Utility function to step credential chain one forward.
143 Deliberately doesn't update the seed. See reseed comment below.
144****************************************************************************/
145
146static void creds_step(struct dcinfo *dc)
147{
148        DOM_CHAL time_chal;
149
150        DEBUG(5,("\tsequence = 0x%x\n", (unsigned int)dc->sequence ));
151
152        DEBUG(5,("\tseed:        %s\n", credstr(dc->seed_chal.data) ));
153
154        SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence);
155        SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
156                                                                                                   
157        DEBUG(5,("\tseed+seq   %s\n", credstr(time_chal.data) ));
158
159        des_crypt112(dc->clnt_chal.data, time_chal.data, dc->sess_key, 1);
160
161        DEBUG(5,("\tCLIENT      %s\n", credstr(dc->clnt_chal.data) ));
162
163        SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1);
164        SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
165
166        DEBUG(5,("\tseed+seq+1   %s\n", credstr(time_chal.data) ));
167
168        des_crypt112(dc->srv_chal.data, time_chal.data, dc->sess_key, 1);
169
170        DEBUG(5,("\tSERVER      %s\n", credstr(dc->srv_chal.data) ));
171}
172
173/****************************************************************************
174 Create a server credential struct.
175****************************************************************************/
176
177void creds_server_init(uint32 neg_flags,
178                        struct dcinfo *dc,
179                        DOM_CHAL *clnt_chal,
180                        DOM_CHAL *srv_chal,
181                        const unsigned char mach_pw[16],
182                        DOM_CHAL *init_chal_out)
183{
184        DEBUG(10,("creds_server_init: neg_flags : %x\n", (unsigned int)neg_flags));
185        DEBUG(10,("creds_server_init: client chal : %s\n", credstr(clnt_chal->data) ));
186        DEBUG(10,("creds_server_init: server chal : %s\n", credstr(srv_chal->data) ));
187        dump_data_pw("creds_server_init: machine pass", mach_pw, 16);
188
189        /* Generate the session key and the next client and server creds. */
190        if (neg_flags & NETLOGON_NEG_128BIT) {
191                creds_init_128(dc,
192                        clnt_chal,
193                        srv_chal,
194                        mach_pw);
195        } else {
196                creds_init_64(dc,
197                        clnt_chal,
198                        srv_chal,
199                        mach_pw);
200        }
201
202        dump_data_pw("creds_server_init: session key", dc->sess_key, 16);
203
204        DEBUG(10,("creds_server_init: clnt : %s\n", credstr(dc->clnt_chal.data) ));
205        DEBUG(10,("creds_server_init: server : %s\n", credstr(dc->srv_chal.data) ));
206        DEBUG(10,("creds_server_init: seed : %s\n", credstr(dc->seed_chal.data) ));
207
208        memcpy(init_chal_out->data, dc->srv_chal.data, 8);
209}
210
211/****************************************************************************
212 Check a credential sent by the client.
213****************************************************************************/
214
215BOOL creds_server_check(const struct dcinfo *dc, const DOM_CHAL *rcv_cli_chal_in)
216{
217        if (memcmp(dc->clnt_chal.data, rcv_cli_chal_in->data, 8)) {
218                DEBUG(5,("creds_server_check: challenge : %s\n", credstr(rcv_cli_chal_in->data)));
219                DEBUG(5,("calculated: %s\n", credstr(dc->clnt_chal.data)));
220                DEBUG(2,("creds_server_check: credentials check failed.\n"));
221                return False;
222        }
223        DEBUG(10,("creds_server_check: credentials check OK.\n"));
224        return True;
225}
226
227/****************************************************************************
228 Replace current seed chal. Internal function - due to split server step below.
229****************************************************************************/
230
231static void creds_reseed(struct dcinfo *dc)
232{
233        DOM_CHAL time_chal;
234
235        SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1);
236        SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
237
238        dc->seed_chal = time_chal;
239
240        DEBUG(5,("cred_reseed: seed %s\n", credstr(dc->seed_chal.data) ));
241}
242
243/****************************************************************************
244 Step the server credential chain one forward.
245****************************************************************************/
246
247BOOL creds_server_step(struct dcinfo *dc, const DOM_CRED *received_cred, DOM_CRED *cred_out)
248{
249        BOOL ret;
250        struct dcinfo tmp_dc = *dc;
251
252        /* Do all operations on a temporary copy of the dc,
253           which we throw away if the checks fail. */
254
255        tmp_dc.sequence = received_cred->timestamp.time;
256
257        creds_step(&tmp_dc);
258
259        /* Create the outgoing credentials */
260        cred_out->timestamp.time = tmp_dc.sequence + 1;
261        cred_out->challenge = tmp_dc.srv_chal;
262
263        creds_reseed(&tmp_dc);
264
265        ret = creds_server_check(&tmp_dc, &received_cred->challenge);
266        if (!ret) {
267                return False;
268        }
269
270        /* creds step succeeded - replace the current creds. */
271        *dc = tmp_dc;
272        return True;
273}
274
275/****************************************************************************
276 Create a client credential struct.
277****************************************************************************/
278
279void creds_client_init(uint32 neg_flags,
280                        struct dcinfo *dc,
281                        DOM_CHAL *clnt_chal,
282                        DOM_CHAL *srv_chal,
283                        const unsigned char mach_pw[16],
284                        DOM_CHAL *init_chal_out)
285{
286        dc->sequence = time(NULL);
287
288        DEBUG(10,("creds_client_init: neg_flags : %x\n", (unsigned int)neg_flags));
289        DEBUG(10,("creds_client_init: client chal : %s\n", credstr(clnt_chal->data) ));
290        DEBUG(10,("creds_client_init: server chal : %s\n", credstr(srv_chal->data) ));
291        dump_data_pw("creds_client_init: machine pass", (const unsigned char *)mach_pw, 16);
292
293        /* Generate the session key and the next client and server creds. */
294        if (neg_flags & NETLOGON_NEG_128BIT) {
295                creds_init_128(dc,
296                                clnt_chal,
297                                srv_chal,
298                                mach_pw);
299        } else {
300                creds_init_64(dc,
301                        clnt_chal,
302                        srv_chal,
303                        mach_pw);
304        }
305
306        dump_data_pw("creds_client_init: session key", dc->sess_key, 16);
307
308        DEBUG(10,("creds_client_init: clnt : %s\n", credstr(dc->clnt_chal.data) ));
309        DEBUG(10,("creds_client_init: server : %s\n", credstr(dc->srv_chal.data) ));
310        DEBUG(10,("creds_client_init: seed : %s\n", credstr(dc->seed_chal.data) ));
311
312        memcpy(init_chal_out->data, dc->clnt_chal.data, 8);
313}
314
315/****************************************************************************
316 Check a credential returned by the server.
317****************************************************************************/
318
319BOOL creds_client_check(const struct dcinfo *dc, const DOM_CHAL *rcv_srv_chal_in)
320{
321        if (memcmp(dc->srv_chal.data, rcv_srv_chal_in->data, 8)) {
322                DEBUG(5,("creds_client_check: challenge : %s\n", credstr(rcv_srv_chal_in->data)));
323                DEBUG(5,("calculated: %s\n", credstr(dc->srv_chal.data)));
324                DEBUG(0,("creds_client_check: credentials check failed.\n"));
325                return False;
326        }
327        DEBUG(10,("creds_client_check: credentials check OK.\n"));
328        return True;
329}
330
331/****************************************************************************
332  Step the client credentials to the next element in the chain, updating the
333  current client and server credentials and the seed
334  produce the next authenticator in the sequence ready to send to
335  the server
336****************************************************************************/
337
338void creds_client_step(struct dcinfo *dc, DOM_CRED *next_cred_out)
339{
340        dc->sequence += 2;
341        creds_step(dc);
342        creds_reseed(dc);
343
344        next_cred_out->challenge = dc->clnt_chal;
345        next_cred_out->timestamp.time = dc->sequence;
346}
Note: See TracBrowser for help on using the repository browser.