r11137: Compile with only 2 warnings (I'm still working on that code) on a gcc4
[tprouty/samba.git] / source / libsmb / credentials.c
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
28 char *credstr(const uchar *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 /****************************************************************************
39  Setup the session key. 
40  Input: 8 byte challenge block
41        8 byte server challenge block
42       16 byte md4 encrypted password
43  Output:
44       16 byte session key (last 8 bytes zero).
45 ****************************************************************************/
46
47 static void cred_create_session_key(const DOM_CHAL *clnt_chal_in,
48                         const DOM_CHAL *srv_chal_in,
49                         const uchar *pass_in, 
50                         uchar session_key_out[16])
51 {
52         uint32 sum[2];
53         unsigned char sum2[8];
54
55         sum[0] = IVAL(clnt_chal_in->data, 0) + IVAL(srv_chal_in->data, 0);
56         sum[1] = IVAL(clnt_chal_in->data, 4) + IVAL(srv_chal_in->data, 4);
57
58         SIVAL(sum2,0,sum[0]);
59         SIVAL(sum2,4,sum[1]);
60
61         cred_hash1(session_key_out, sum2, pass_in);
62         memset(&session_key_out[8], '\0', 8);
63
64         /* debug output */
65         DEBUG(4,("cred_create_session_key\n"));
66
67         DEBUG(5,("      clnt_chal_in: %s\n", credstr(clnt_chal_in->data)));
68         DEBUG(5,("      srv_chal_in : %s\n", credstr(srv_chal_in->data)));
69         DEBUG(5,("      clnt+srv : %s\n", credstr(sum2)));
70         DEBUG(5,("      sess_key_out : %s\n", credstr(session_key_out)));
71 }
72
73 /****************************************************************************
74  Utility function to step credential chain one forward.
75  Deliberately doesn't update the seed. See reseed comment below.
76 ****************************************************************************/
77
78 static void creds_step(struct dcinfo *dc)
79 {
80         DOM_CHAL time_chal;
81
82         DEBUG(5,("\tsequence = 0x%x\n", (unsigned int)dc->sequence ));
83
84         DEBUG(5,("\tseed:        %s\n", credstr(dc->seed_chal.data) ));
85
86         SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence);
87         SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
88                                                                                                    
89         DEBUG(5,("\tseed+seq   %s\n", credstr(time_chal.data) ));
90
91         cred_hash2(dc->clnt_chal.data, time_chal.data, dc->sess_key);
92
93         DEBUG(5,("\tCLIENT      %s\n", credstr(dc->clnt_chal.data) ));
94
95         SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1);
96         SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
97
98         DEBUG(5,("\tseed+seq+1   %s\n", credstr(time_chal.data) ));
99
100         cred_hash2(dc->srv_chal.data, time_chal.data, dc->sess_key);
101
102         DEBUG(5,("\tSERVER      %s\n", credstr(dc->srv_chal.data) ));
103 }
104
105
106 /****************************************************************************
107  Create a server credential struct.
108 ****************************************************************************/
109
110 void creds_server_init(struct dcinfo *dc,
111                         DOM_CHAL *clnt_chal,
112                         DOM_CHAL *srv_chal,
113                         const char mach_pw[16],
114                         DOM_CHAL *init_chal_out)
115 {
116         DEBUG(10,("creds_server_init: client chal : %s\n", credstr(clnt_chal->data) ));
117         DEBUG(10,("creds_server_init: server chal : %s\n", credstr(srv_chal->data) ));
118         dump_data_pw("creds_server_init: machine pass", (const unsigned char *)mach_pw, 16);
119
120         /* Just in case this isn't already there */
121         memcpy(dc->mach_pw, mach_pw, 16);
122
123         /* Generate the session key. */
124         cred_create_session_key(clnt_chal,              /* Stored client challenge. */
125                                 srv_chal,               /* Stored server challenge. */
126                                 dc->mach_pw,              /* input machine password. */
127                                 dc->sess_key);            /* output session key. */
128
129         dump_data_pw("creds_server_init: session key", dc->sess_key, 16);
130
131         /* Generate the next client and server creds. */
132         cred_hash2(dc->clnt_chal.data,                  /* output */
133                         clnt_chal->data,                /* input */
134                         dc->sess_key);                  /* input */
135
136         cred_hash2(dc->srv_chal.data,                   /* output */
137                         srv_chal->data,                 /* input */
138                         dc->sess_key);                  /* input */
139
140         /* Seed is the client chal. */
141         memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
142
143         DEBUG(10,("creds_server_init: clnt : %s\n", credstr(dc->clnt_chal.data) ));
144         DEBUG(10,("creds_server_init: server : %s\n", credstr(dc->srv_chal.data) ));
145         DEBUG(10,("creds_server_init: seed : %s\n", credstr(dc->seed_chal.data) ));
146
147         memcpy(init_chal_out->data, dc->srv_chal.data, 8);
148 }
149
150 /****************************************************************************
151  Check a credential sent by the client.
152 ****************************************************************************/
153
154 BOOL creds_server_check(const struct dcinfo *dc, const DOM_CHAL *rcv_cli_chal_in)
155 {
156         if (memcmp(dc->clnt_chal.data, rcv_cli_chal_in->data, 8)) {
157                 DEBUG(5,("creds_server_check: challenge : %s\n", credstr(rcv_cli_chal_in->data)));
158                 DEBUG(5,("calculated: %s\n", credstr(dc->clnt_chal.data)));
159                 DEBUG(0,("creds_server_check: credentials check failed.\n"));
160                 return False;
161         }
162         DEBUG(10,("creds_server_check: credentials check OK.\n"));
163         return True;
164 }
165
166 /****************************************************************************
167  Replace current seed chal. Internal function - due to split server step below.
168 ****************************************************************************/
169
170 static void creds_reseed(struct dcinfo *dc)
171 {
172         DOM_CHAL time_chal;
173
174         SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1);
175         SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
176
177         dc->seed_chal = time_chal;
178
179         DEBUG(5,("cred_reseed: seed %s\n", credstr(dc->seed_chal.data) ));
180 }
181
182 /****************************************************************************
183  Step the server credential chain one forward. 
184 ****************************************************************************/
185
186 BOOL creds_server_step(struct dcinfo *dc, const DOM_CRED *received_cred, DOM_CRED *cred_out)
187 {
188         dc->sequence = received_cred->timestamp.time;
189
190         creds_step(dc);
191
192         /* Create the outgoing credentials */
193         cred_out->timestamp.time = dc->sequence + 1;
194         cred_out->challenge = dc->srv_chal;
195
196         creds_reseed(dc);
197
198         return creds_server_check(dc, &received_cred->challenge);
199 }
200
201 /****************************************************************************
202  Create a client credential struct.
203 ****************************************************************************/
204
205 void creds_client_init(struct dcinfo *dc,
206                         DOM_CHAL *clnt_chal,
207                         DOM_CHAL *srv_chal,
208                         const unsigned char mach_pw[16],
209                         DOM_CHAL *init_chal_out)
210 {
211         dc->sequence = time(NULL);
212
213         DEBUG(10,("creds_client_init: client chal : %s\n", credstr(clnt_chal->data) ));
214         DEBUG(10,("creds_client_init: server chal : %s\n", credstr(srv_chal->data) ));
215         dump_data_pw("creds_client_init: machine pass", (const unsigned char *)mach_pw, 16);
216
217         /* Just in case this isn't already there */
218         memcpy(dc->mach_pw, mach_pw, 16);
219
220         /* Generate the session key. */
221         cred_create_session_key(clnt_chal,              /* Stored client challenge. */
222                                 srv_chal,               /* Stored server challenge. */
223                                 dc->mach_pw,              /* input machine password. */
224                                 dc->sess_key);            /* output session key. */
225
226         dump_data_pw("creds_client_init: session key", dc->sess_key, 16);
227
228         /* Generate the next client and server creds. */
229         cred_hash2(dc->clnt_chal.data,  /* output */
230                         clnt_chal->data,                /* input */
231                         dc->sess_key);                  /* input */
232
233         cred_hash2(dc->srv_chal.data,           /* output */
234                         srv_chal->data,                 /* input */
235                         dc->sess_key);                  /* input */
236
237         /* Seed is the client cred. */
238         memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
239
240         DEBUG(10,("creds_client_init: clnt : %s\n", credstr(dc->clnt_chal.data) ));
241         DEBUG(10,("creds_client_init: server : %s\n", credstr(dc->srv_chal.data) ));
242         DEBUG(10,("creds_client_init: seed : %s\n", credstr(dc->seed_chal.data) ));
243
244         memcpy(init_chal_out->data, dc->clnt_chal.data, 8);
245 }
246
247 /****************************************************************************
248  Check a credential returned by the server.
249 ****************************************************************************/
250
251 BOOL creds_client_check(const struct dcinfo *dc, const DOM_CHAL *rcv_srv_chal_in)
252 {
253         if (memcmp(dc->srv_chal.data, rcv_srv_chal_in->data, 8)) {
254                 DEBUG(5,("creds_client_check: challenge : %s\n", credstr(rcv_srv_chal_in->data)));
255                 DEBUG(5,("calculated: %s\n", credstr(dc->srv_chal.data)));
256                 DEBUG(0,("creds_client_check: credentials check failed.\n"));
257                 return False;
258         }
259         DEBUG(10,("creds_client_check: credentials check OK.\n"));
260         return True;
261 }
262
263 /****************************************************************************
264   Step the client credentials to the next element in the chain, updating the
265   current client and server credentials and the seed
266   produce the next authenticator in the sequence ready to send to
267   the server
268 ****************************************************************************/
269
270 void creds_client_step(struct dcinfo *dc, DOM_CRED *next_cred_out)
271 {
272         dc->sequence += 2;
273         creds_step(dc);
274         creds_reseed(dc);
275
276         next_cred_out->challenge = dc->clnt_chal;
277         next_cred_out->timestamp.time = dc->sequence;
278 }