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.
24 /****************************************************************************
25 Represent a credential as a string.
26 ****************************************************************************/
28 char *credstr(const uchar *cred)
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]);
38 /****************************************************************************
39 Setup the session key and the client and server creds in dc.
40 Used by both client and server creds setup.
41 ****************************************************************************/
43 static void creds_init_64(struct dcinfo *dc,
44 const DOM_CHAL *clnt_chal_in,
45 const DOM_CHAL *srv_chal_in,
46 const char mach_pw[16])
49 unsigned char sum2[8];
51 /* Just in case this isn't already there */
52 memcpy(dc->mach_pw, mach_pw, 16);
54 sum[0] = IVAL(clnt_chal_in->data, 0) + IVAL(srv_chal_in->data, 0);
55 sum[1] = IVAL(clnt_chal_in->data, 4) + IVAL(srv_chal_in->data, 4);
60 ZERO_STRUCT(dc->sess_key);
62 des_crypt128(dc->sess_key, sum2, dc->mach_pw);
65 DEBUG(5,("creds_init_64\n"));
66 DEBUG(5,(" clnt_chal_in: %s\n", credstr(clnt_chal_in->data)));
67 DEBUG(5,(" srv_chal_in : %s\n", credstr(srv_chal_in->data)));
68 DEBUG(5,(" clnt+srv : %s\n", credstr(sum2)));
69 DEBUG(5,(" sess_key_out : %s\n", credstr(dc->sess_key)));
71 /* Generate the next client and server creds. */
73 des_crypt112(dc->clnt_chal.data, /* output */
74 clnt_chal_in->data, /* input */
75 dc->sess_key, /* input */
78 des_crypt112(dc->srv_chal.data, /* output */
79 srv_chal_in->data, /* input */
80 dc->sess_key, /* input */
83 /* Seed is the client chal. */
84 memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
87 /****************************************************************************
88 Utility function to step credential chain one forward.
89 Deliberately doesn't update the seed. See reseed comment below.
90 ****************************************************************************/
92 static void creds_step(struct dcinfo *dc)
96 DEBUG(5,("\tsequence = 0x%x\n", (unsigned int)dc->sequence ));
98 DEBUG(5,("\tseed: %s\n", credstr(dc->seed_chal.data) ));
100 SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence);
101 SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
103 DEBUG(5,("\tseed+seq %s\n", credstr(time_chal.data) ));
105 des_crypt112(dc->clnt_chal.data, time_chal.data, dc->sess_key, 1);
107 DEBUG(5,("\tCLIENT %s\n", credstr(dc->clnt_chal.data) ));
109 SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1);
110 SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
112 DEBUG(5,("\tseed+seq+1 %s\n", credstr(time_chal.data) ));
114 des_crypt112(dc->srv_chal.data, time_chal.data, dc->sess_key, 1);
116 DEBUG(5,("\tSERVER %s\n", credstr(dc->srv_chal.data) ));
119 /****************************************************************************
120 Create a server credential struct.
121 ****************************************************************************/
123 void creds_server_init(struct dcinfo *dc,
126 const char mach_pw[16],
127 DOM_CHAL *init_chal_out)
129 DEBUG(10,("creds_server_init: client chal : %s\n", credstr(clnt_chal->data) ));
130 DEBUG(10,("creds_server_init: server chal : %s\n", credstr(srv_chal->data) ));
131 dump_data_pw("creds_server_init: machine pass", (const unsigned char *)mach_pw, 16);
133 /* Generate the session key and the next client and server creds. */
139 dump_data_pw("creds_server_init: session key", dc->sess_key, 16);
141 DEBUG(10,("creds_server_init: clnt : %s\n", credstr(dc->clnt_chal.data) ));
142 DEBUG(10,("creds_server_init: server : %s\n", credstr(dc->srv_chal.data) ));
143 DEBUG(10,("creds_server_init: seed : %s\n", credstr(dc->seed_chal.data) ));
145 memcpy(init_chal_out->data, dc->srv_chal.data, 8);
148 /****************************************************************************
149 Check a credential sent by the client.
150 ****************************************************************************/
152 BOOL creds_server_check(const struct dcinfo *dc, const DOM_CHAL *rcv_cli_chal_in)
154 if (memcmp(dc->clnt_chal.data, rcv_cli_chal_in->data, 8)) {
155 DEBUG(5,("creds_server_check: challenge : %s\n", credstr(rcv_cli_chal_in->data)));
156 DEBUG(5,("calculated: %s\n", credstr(dc->clnt_chal.data)));
157 DEBUG(2,("creds_server_check: credentials check failed.\n"));
160 DEBUG(10,("creds_server_check: credentials check OK.\n"));
164 /****************************************************************************
165 Replace current seed chal. Internal function - due to split server step below.
166 ****************************************************************************/
168 static void creds_reseed(struct dcinfo *dc)
172 SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1);
173 SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
175 dc->seed_chal = time_chal;
177 DEBUG(5,("cred_reseed: seed %s\n", credstr(dc->seed_chal.data) ));
180 /****************************************************************************
181 Step the server credential chain one forward.
182 ****************************************************************************/
184 BOOL creds_server_step(struct dcinfo *dc, const DOM_CRED *received_cred, DOM_CRED *cred_out)
186 dc->sequence = received_cred->timestamp.time;
190 /* Create the outgoing credentials */
191 cred_out->timestamp.time = dc->sequence + 1;
192 cred_out->challenge = dc->srv_chal;
196 return creds_server_check(dc, &received_cred->challenge);
199 /****************************************************************************
200 Create a client credential struct.
201 ****************************************************************************/
203 void creds_client_init(struct dcinfo *dc,
206 const unsigned char mach_pw[16],
207 DOM_CHAL *init_chal_out)
209 dc->sequence = time(NULL);
211 DEBUG(10,("creds_client_init: client chal : %s\n", credstr(clnt_chal->data) ));
212 DEBUG(10,("creds_client_init: server chal : %s\n", credstr(srv_chal->data) ));
213 dump_data_pw("creds_client_init: machine pass", (const unsigned char *)mach_pw, 16);
215 /* Generate the session key and the next client and server creds. */
221 dump_data_pw("creds_client_init: session key", dc->sess_key, 16);
223 DEBUG(10,("creds_client_init: clnt : %s\n", credstr(dc->clnt_chal.data) ));
224 DEBUG(10,("creds_client_init: server : %s\n", credstr(dc->srv_chal.data) ));
225 DEBUG(10,("creds_client_init: seed : %s\n", credstr(dc->seed_chal.data) ));
227 memcpy(init_chal_out->data, dc->clnt_chal.data, 8);
230 /****************************************************************************
231 Check a credential returned by the server.
232 ****************************************************************************/
234 BOOL creds_client_check(const struct dcinfo *dc, const DOM_CHAL *rcv_srv_chal_in)
236 if (memcmp(dc->srv_chal.data, rcv_srv_chal_in->data, 8)) {
237 DEBUG(5,("creds_client_check: challenge : %s\n", credstr(rcv_srv_chal_in->data)));
238 DEBUG(5,("calculated: %s\n", credstr(dc->srv_chal.data)));
239 DEBUG(0,("creds_client_check: credentials check failed.\n"));
242 DEBUG(10,("creds_client_check: credentials check OK.\n"));
246 /****************************************************************************
247 Step the client credentials to the next element in the chain, updating the
248 current client and server credentials and the seed
249 produce the next authenticator in the sequence ready to send to
251 ****************************************************************************/
253 void creds_client_step(struct dcinfo *dc, DOM_CRED *next_cred_out)
259 next_cred_out->challenge = dc->clnt_chal;
260 next_cred_out->timestamp.time = dc->sequence;