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.
40 Input: 8 byte challenge block
41 8 byte server challenge block
42 16 byte md4 encrypted password
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
,
50 uchar session_key_out
[16])
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);
61 cred_hash1(session_key_out
, sum2
, pass_in
);
62 memset(&session_key_out
[8], '\0', 8);
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
)
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
,
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"));
162 DEBUG(10,("creds_server_check: credentials check OK.\n"));
166 /****************************************************************************
167 Replace current seed chal. Internal function - due to split server step below.
168 ****************************************************************************/
170 static void creds_reseed(struct dcinfo
*dc
)
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
;
192 /* Create the outgoing credentials */
193 cred_out
->timestamp
.time
= dc
->sequence
+ 1;
194 cred_out
->challenge
= dc
->srv_chal
;
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
,
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"));
259 DEBUG(10,("creds_client_check: credentials check OK.\n"));
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
268 ****************************************************************************/
270 void creds_client_step(struct dcinfo
*dc
, DOM_CRED
*next_cred_out
)
276 next_cred_out
->challenge
= dc
->clnt_chal
;
277 next_cred_out
->timestamp
.time
= dc
->sequence
;