r11137: Compile with only 2 warnings (I'm still working on that code) on a gcc4
[Samba.git] / source / libsmb / credentials.c
blobedb242df7e802f56a7cf6f6176394013215d31a4
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.
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.
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, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "includes.h"
24 /****************************************************************************
25 Represent a credential as a string.
26 ****************************************************************************/
28 char *credstr(const uchar *cred)
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;
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 ****************************************************************************/
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])
52 uint32 sum[2];
53 unsigned char sum2[8];
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);
58 SIVAL(sum2,0,sum[0]);
59 SIVAL(sum2,4,sum[1]);
61 cred_hash1(session_key_out, sum2, pass_in);
62 memset(&session_key_out[8], '\0', 8);
64 /* debug output */
65 DEBUG(4,("cred_create_session_key\n"));
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)));
73 /****************************************************************************
74 Utility function to step credential chain one forward.
75 Deliberately doesn't update the seed. See reseed comment below.
76 ****************************************************************************/
78 static void creds_step(struct dcinfo *dc)
80 DOM_CHAL time_chal;
82 DEBUG(5,("\tsequence = 0x%x\n", (unsigned int)dc->sequence ));
84 DEBUG(5,("\tseed: %s\n", credstr(dc->seed_chal.data) ));
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));
89 DEBUG(5,("\tseed+seq %s\n", credstr(time_chal.data) ));
91 cred_hash2(dc->clnt_chal.data, time_chal.data, dc->sess_key);
93 DEBUG(5,("\tCLIENT %s\n", credstr(dc->clnt_chal.data) ));
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));
98 DEBUG(5,("\tseed+seq+1 %s\n", credstr(time_chal.data) ));
100 cred_hash2(dc->srv_chal.data, time_chal.data, dc->sess_key);
102 DEBUG(5,("\tSERVER %s\n", credstr(dc->srv_chal.data) ));
106 /****************************************************************************
107 Create a server credential struct.
108 ****************************************************************************/
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)
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);
120 /* Just in case this isn't already there */
121 memcpy(dc->mach_pw, mach_pw, 16);
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. */
129 dump_data_pw("creds_server_init: session key", dc->sess_key, 16);
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 */
136 cred_hash2(dc->srv_chal.data, /* output */
137 srv_chal->data, /* input */
138 dc->sess_key); /* input */
140 /* Seed is the client chal. */
141 memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
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) ));
147 memcpy(init_chal_out->data, dc->srv_chal.data, 8);
150 /****************************************************************************
151 Check a credential sent by the client.
152 ****************************************************************************/
154 BOOL creds_server_check(const struct dcinfo *dc, const DOM_CHAL *rcv_cli_chal_in)
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;
162 DEBUG(10,("creds_server_check: credentials check OK.\n"));
163 return True;
166 /****************************************************************************
167 Replace current seed chal. Internal function - due to split server step below.
168 ****************************************************************************/
170 static void creds_reseed(struct dcinfo *dc)
172 DOM_CHAL time_chal;
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));
177 dc->seed_chal = time_chal;
179 DEBUG(5,("cred_reseed: seed %s\n", credstr(dc->seed_chal.data) ));
182 /****************************************************************************
183 Step the server credential chain one forward.
184 ****************************************************************************/
186 BOOL creds_server_step(struct dcinfo *dc, const DOM_CRED *received_cred, DOM_CRED *cred_out)
188 dc->sequence = received_cred->timestamp.time;
190 creds_step(dc);
192 /* Create the outgoing credentials */
193 cred_out->timestamp.time = dc->sequence + 1;
194 cred_out->challenge = dc->srv_chal;
196 creds_reseed(dc);
198 return creds_server_check(dc, &received_cred->challenge);
201 /****************************************************************************
202 Create a client credential struct.
203 ****************************************************************************/
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)
211 dc->sequence = time(NULL);
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);
217 /* Just in case this isn't already there */
218 memcpy(dc->mach_pw, mach_pw, 16);
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. */
226 dump_data_pw("creds_client_init: session key", dc->sess_key, 16);
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 */
233 cred_hash2(dc->srv_chal.data, /* output */
234 srv_chal->data, /* input */
235 dc->sess_key); /* input */
237 /* Seed is the client cred. */
238 memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
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) ));
244 memcpy(init_chal_out->data, dc->clnt_chal.data, 8);
247 /****************************************************************************
248 Check a credential returned by the server.
249 ****************************************************************************/
251 BOOL creds_client_check(const struct dcinfo *dc, const DOM_CHAL *rcv_srv_chal_in)
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;
259 DEBUG(10,("creds_client_check: credentials check OK.\n"));
260 return True;
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 ****************************************************************************/
270 void creds_client_step(struct dcinfo *dc, DOM_CRED *next_cred_out)
272 dc->sequence += 2;
273 creds_step(dc);
274 creds_reseed(dc);
276 next_cred_out->challenge = dc->clnt_chal;
277 next_cred_out->timestamp.time = dc->sequence;