r17509: same for old woody packaging stuff
[Samba.git] / source / libsmb / credentials.c
blob76fc5fc062127d641af3a2ce53220eec03d63647
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 unsigned char *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;
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 ****************************************************************************/
43 static 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])
48 unsigned char zero[4], tmp[16];
49 HMACMD5Context ctx;
50 struct MD5Context md5;
52 /* Just in case this isn't already there */
53 memcpy(dc->mach_pw, mach_pw, 16);
55 ZERO_STRUCT(dc->sess_key);
57 memset(zero, 0, sizeof(zero));
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);
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);
74 /* Generate the next client and server creds. */
76 des_crypt112(dc->clnt_chal.data, /* output */
77 clnt_chal_in->data, /* input */
78 dc->sess_key, /* input */
79 1);
81 des_crypt112(dc->srv_chal.data, /* output */
82 srv_chal_in->data, /* input */
83 dc->sess_key, /* input */
84 1);
86 /* Seed is the client chal. */
87 memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
90 /****************************************************************************
91 Setup the session key and the client and server creds in dc.
92 Used by both client and server creds setup.
93 ****************************************************************************/
95 static 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])
100 uint32 sum[2];
101 unsigned char sum2[8];
103 /* Just in case this isn't already there */
104 memcpy(dc->mach_pw, mach_pw, 16);
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);
109 SIVAL(sum2,0,sum[0]);
110 SIVAL(sum2,4,sum[1]);
112 ZERO_STRUCT(dc->sess_key);
114 des_crypt128(dc->sess_key, sum2, dc->mach_pw);
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)));
123 /* Generate the next client and server creds. */
125 des_crypt112(dc->clnt_chal.data, /* output */
126 clnt_chal_in->data, /* input */
127 dc->sess_key, /* input */
130 des_crypt112(dc->srv_chal.data, /* output */
131 srv_chal_in->data, /* input */
132 dc->sess_key, /* input */
135 /* Seed is the client chal. */
136 memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
139 /****************************************************************************
140 Utility function to step credential chain one forward.
141 Deliberately doesn't update the seed. See reseed comment below.
142 ****************************************************************************/
144 static void creds_step(struct dcinfo *dc)
146 DOM_CHAL time_chal;
148 DEBUG(5,("\tsequence = 0x%x\n", (unsigned int)dc->sequence ));
150 DEBUG(5,("\tseed: %s\n", credstr(dc->seed_chal.data) ));
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));
155 DEBUG(5,("\tseed+seq %s\n", credstr(time_chal.data) ));
157 des_crypt112(dc->clnt_chal.data, time_chal.data, dc->sess_key, 1);
159 DEBUG(5,("\tCLIENT %s\n", credstr(dc->clnt_chal.data) ));
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));
164 DEBUG(5,("\tseed+seq+1 %s\n", credstr(time_chal.data) ));
166 des_crypt112(dc->srv_chal.data, time_chal.data, dc->sess_key, 1);
168 DEBUG(5,("\tSERVER %s\n", credstr(dc->srv_chal.data) ));
171 /****************************************************************************
172 Create a server credential struct.
173 ****************************************************************************/
175 void 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)
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);
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);
200 dump_data_pw("creds_server_init: session key", dc->sess_key, 16);
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) ));
206 memcpy(init_chal_out->data, dc->srv_chal.data, 8);
209 /****************************************************************************
210 Check a credential sent by the client.
211 ****************************************************************************/
213 BOOL creds_server_check(const struct dcinfo *dc, const DOM_CHAL *rcv_cli_chal_in)
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;
221 DEBUG(10,("creds_server_check: credentials check OK.\n"));
222 return True;
225 /****************************************************************************
226 Replace current seed chal. Internal function - due to split server step below.
227 ****************************************************************************/
229 static void creds_reseed(struct dcinfo *dc)
231 DOM_CHAL time_chal;
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));
236 dc->seed_chal = time_chal;
238 DEBUG(5,("cred_reseed: seed %s\n", credstr(dc->seed_chal.data) ));
241 /****************************************************************************
242 Step the server credential chain one forward.
243 ****************************************************************************/
245 BOOL creds_server_step(struct dcinfo *dc, const DOM_CRED *received_cred, DOM_CRED *cred_out)
247 BOOL ret;
248 struct dcinfo tmp_dc = *dc;
250 /* Do all operations on a temporary copy of the dc,
251 which we throw away if the checks fail. */
253 tmp_dc.sequence = received_cred->timestamp.time;
255 creds_step(&tmp_dc);
257 /* Create the outgoing credentials */
258 cred_out->timestamp.time = tmp_dc.sequence + 1;
259 cred_out->challenge = tmp_dc.srv_chal;
261 creds_reseed(&tmp_dc);
263 ret = creds_server_check(&tmp_dc, &received_cred->challenge);
264 if (!ret) {
265 return False;
268 /* creds step succeeded - replace the current creds. */
269 *dc = tmp_dc;
270 return True;
273 /****************************************************************************
274 Create a client credential struct.
275 ****************************************************************************/
277 void 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)
284 dc->sequence = time(NULL);
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);
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);
304 dump_data_pw("creds_client_init: session key", dc->sess_key, 16);
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) ));
310 memcpy(init_chal_out->data, dc->clnt_chal.data, 8);
313 /****************************************************************************
314 Check a credential returned by the server.
315 ****************************************************************************/
317 BOOL creds_client_check(const struct dcinfo *dc, const DOM_CHAL *rcv_srv_chal_in)
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;
325 DEBUG(10,("creds_client_check: credentials check OK.\n"));
326 return True;
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 ****************************************************************************/
336 void creds_client_step(struct dcinfo *dc, DOM_CRED *next_cred_out)
338 dc->sequence += 2;
339 creds_step(dc);
340 creds_reseed(dc);
342 next_cred_out->challenge = dc->clnt_chal;
343 next_cred_out->timestamp.time = dc->sequence;