s3:selftest: fix warnings with empty *_TEST_LOG variables
[metze/samba/wip.git] / source3 / 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 3 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, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22
23 /****************************************************************************
24  Represent a credential as a string.
25 ****************************************************************************/
26
27 char *credstr(const unsigned char *cred)
28 {
29         char *result;
30         result = talloc_asprintf(talloc_tos(),
31                                  "%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         SMB_ASSERT(result != NULL);
35         return result;
36 }
37
38 /****************************************************************************
39  Setup the session key and the client and server creds in dc.
40  ADS-style 128 bit session keys.
41  Used by both client and server creds setup.
42 ****************************************************************************/
43
44 static void creds_init_128(struct dcinfo *dc,
45                            const struct netr_Credential *clnt_chal_in,
46                            const struct netr_Credential *srv_chal_in,
47                            const unsigned char mach_pw[16])
48 {
49         unsigned char zero[4], tmp[16];
50         HMACMD5Context ctx;
51         struct MD5Context md5;
52
53         /* Just in case this isn't already there */
54         memcpy(dc->mach_pw, mach_pw, 16);
55
56         ZERO_STRUCT(dc->sess_key);
57
58         memset(zero, 0, sizeof(zero));
59
60         hmac_md5_init_rfc2104(mach_pw, 16, &ctx);
61         MD5Init(&md5);
62         MD5Update(&md5, zero, sizeof(zero));
63         MD5Update(&md5, clnt_chal_in->data, 8);
64         MD5Update(&md5, srv_chal_in->data, 8);
65         MD5Final(tmp, &md5);
66         hmac_md5_update(tmp, sizeof(tmp), &ctx);
67         hmac_md5_final(dc->sess_key, &ctx);
68
69         /* debug output */
70         DEBUG(5,("creds_init_128\n"));
71         DEBUG(5,("\tclnt_chal_in: %s\n", credstr(clnt_chal_in->data)));
72         DEBUG(5,("\tsrv_chal_in : %s\n", credstr(srv_chal_in->data)));
73         dump_data_pw("\tsession_key ", (const unsigned char *)dc->sess_key, 16);
74
75         /* Generate the next client and server creds. */
76         
77         des_crypt112(dc->clnt_chal.data,                /* output */
78                         clnt_chal_in->data,             /* input */
79                         dc->sess_key,                   /* input */
80                         1);
81
82         des_crypt112(dc->srv_chal.data,                 /* output */
83                         srv_chal_in->data,              /* input */
84                         dc->sess_key,                   /* input */
85                         1);
86
87         /* Seed is the client chal. */
88         memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
89 }
90
91 /****************************************************************************
92  Setup the session key and the client and server creds in dc.
93  Used by both client and server creds setup.
94 ****************************************************************************/
95
96 static void creds_init_64(struct dcinfo *dc,
97                           const struct netr_Credential *clnt_chal_in,
98                           const struct netr_Credential *srv_chal_in,
99                           const unsigned char mach_pw[16])
100 {
101         uint32 sum[2];
102         unsigned char sum2[8];
103
104         /* Just in case this isn't already there */
105         if (dc->mach_pw != mach_pw) {
106                 memcpy(dc->mach_pw, mach_pw, 16);
107         }
108
109         sum[0] = IVAL(clnt_chal_in->data, 0) + IVAL(srv_chal_in->data, 0);
110         sum[1] = IVAL(clnt_chal_in->data, 4) + IVAL(srv_chal_in->data, 4);
111
112         SIVAL(sum2,0,sum[0]);
113         SIVAL(sum2,4,sum[1]);
114
115         ZERO_STRUCT(dc->sess_key);
116
117         des_crypt128(dc->sess_key, sum2, dc->mach_pw);
118
119         /* debug output */
120         DEBUG(5,("creds_init_64\n"));
121         DEBUG(5,("\tclnt_chal_in: %s\n", credstr(clnt_chal_in->data)));
122         DEBUG(5,("\tsrv_chal_in : %s\n", credstr(srv_chal_in->data)));
123         DEBUG(5,("\tclnt+srv : %s\n", credstr(sum2)));
124         DEBUG(5,("\tsess_key_out : %s\n", credstr(dc->sess_key)));
125
126         /* Generate the next client and server creds. */
127         
128         des_crypt112(dc->clnt_chal.data,                /* output */
129                         clnt_chal_in->data,             /* input */
130                         dc->sess_key,                   /* input */
131                         1);
132
133         des_crypt112(dc->srv_chal.data,                 /* output */
134                         srv_chal_in->data,              /* input */
135                         dc->sess_key,                   /* input */
136                         1);
137
138         /* Seed is the client chal. */
139         memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
140 }
141
142 /****************************************************************************
143  Utility function to step credential chain one forward.
144  Deliberately doesn't update the seed. See reseed comment below.
145 ****************************************************************************/
146
147 static void creds_step(struct dcinfo *dc)
148 {
149         DOM_CHAL time_chal;
150
151         DEBUG(5,("\tsequence = 0x%x\n", (unsigned int)dc->sequence ));
152
153         DEBUG(5,("\tseed:        %s\n", credstr(dc->seed_chal.data) ));
154
155         SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence);
156         SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
157                                                                                                    
158         DEBUG(5,("\tseed+seq   %s\n", credstr(time_chal.data) ));
159
160         des_crypt112(dc->clnt_chal.data, time_chal.data, dc->sess_key, 1);
161
162         DEBUG(5,("\tCLIENT      %s\n", credstr(dc->clnt_chal.data) ));
163
164         SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1);
165         SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
166
167         DEBUG(5,("\tseed+seq+1   %s\n", credstr(time_chal.data) ));
168
169         des_crypt112(dc->srv_chal.data, time_chal.data, dc->sess_key, 1);
170
171         DEBUG(5,("\tSERVER      %s\n", credstr(dc->srv_chal.data) ));
172 }
173
174 /****************************************************************************
175  Create a server credential struct.
176 ****************************************************************************/
177
178 void creds_server_init(uint32 neg_flags,
179                         struct dcinfo *dc,
180                         struct netr_Credential *clnt_chal,
181                         struct netr_Credential *srv_chal,
182                         const unsigned char mach_pw[16],
183                         struct netr_Credential *init_chal_out)
184 {
185         DEBUG(10,("creds_server_init: neg_flags : %x\n", (unsigned int)neg_flags));
186         DEBUG(10,("creds_server_init: client chal : %s\n", credstr(clnt_chal->data) ));
187         DEBUG(10,("creds_server_init: server chal : %s\n", credstr(srv_chal->data) ));
188         dump_data_pw("creds_server_init: machine pass", mach_pw, 16);
189
190         /* Generate the session key and the next client and server creds. */
191         if (neg_flags & NETLOGON_NEG_128BIT) {
192                 creds_init_128(dc,
193                         clnt_chal,
194                         srv_chal,
195                         mach_pw);
196         } else {
197                 creds_init_64(dc,
198                         clnt_chal,
199                         srv_chal,
200                         mach_pw);
201         }
202
203         dump_data_pw("creds_server_init: session key", dc->sess_key, 16);
204
205         DEBUG(10,("creds_server_init: clnt : %s\n", credstr(dc->clnt_chal.data) ));
206         DEBUG(10,("creds_server_init: server : %s\n", credstr(dc->srv_chal.data) ));
207         DEBUG(10,("creds_server_init: seed : %s\n", credstr(dc->seed_chal.data) ));
208
209         memcpy(init_chal_out->data, dc->srv_chal.data, 8);
210 }
211
212 /****************************************************************************
213  Check a credential sent by the client.
214 ****************************************************************************/
215
216 bool netlogon_creds_server_check(const struct dcinfo *dc,
217                                  const struct netr_Credential *rcv_cli_chal_in)
218 {
219         if (memcmp(dc->clnt_chal.data, rcv_cli_chal_in->data, 8)) {
220                 DEBUG(5,("netlogon_creds_server_check: challenge : %s\n",
221                         credstr(rcv_cli_chal_in->data)));
222                 DEBUG(5,("calculated: %s\n", credstr(dc->clnt_chal.data)));
223                 DEBUG(2,("netlogon_creds_server_check: credentials check failed.\n"));
224                 return false;
225         }
226
227         DEBUG(10,("netlogon_creds_server_check: credentials check OK.\n"));
228
229         return true;
230 }
231 /****************************************************************************
232  Replace current seed chal. Internal function - due to split server step below.
233 ****************************************************************************/
234
235 static void creds_reseed(struct dcinfo *dc)
236 {
237         struct netr_Credential time_chal;
238
239         SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1);
240         SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
241
242         dc->seed_chal = time_chal;
243
244         DEBUG(5,("cred_reseed: seed %s\n", credstr(dc->seed_chal.data) ));
245 }
246
247 /****************************************************************************
248  Step the server credential chain one forward. 
249 ****************************************************************************/
250
251 bool netlogon_creds_server_step(struct dcinfo *dc,
252                                 const struct netr_Authenticator *received_cred,
253                                 struct netr_Authenticator *cred_out)
254 {
255         bool ret;
256         struct dcinfo tmp_dc = *dc;
257
258         /* Do all operations on a temporary copy of the dc,
259            which we throw away if the checks fail. */
260
261         tmp_dc.sequence = received_cred->timestamp;
262
263         creds_step(&tmp_dc);
264
265         /* Create the outgoing credentials */
266         cred_out->timestamp = tmp_dc.sequence + 1;
267         memcpy(&cred_out->cred, &tmp_dc.srv_chal, sizeof(cred_out->cred));
268
269         creds_reseed(&tmp_dc);
270
271         ret = netlogon_creds_server_check(&tmp_dc, &received_cred->cred);
272         if (!ret) {
273                 return false;
274         }
275
276         /* creds step succeeded - replace the current creds. */
277         *dc = tmp_dc;
278         return true;
279 }
280
281 /****************************************************************************
282  Create a client credential struct.
283 ****************************************************************************/
284
285 void creds_client_init(uint32 neg_flags,
286                         struct dcinfo *dc,
287                         struct netr_Credential *clnt_chal,
288                         struct netr_Credential *srv_chal,
289                         const unsigned char mach_pw[16],
290                         struct netr_Credential *init_chal_out)
291 {
292         dc->sequence = time(NULL);
293
294         DEBUG(10,("creds_client_init: neg_flags : %x\n", (unsigned int)neg_flags));
295         DEBUG(10,("creds_client_init: client chal : %s\n", credstr(clnt_chal->data) ));
296         DEBUG(10,("creds_client_init: server chal : %s\n", credstr(srv_chal->data) ));
297         dump_data_pw("creds_client_init: machine pass", (const unsigned char *)mach_pw, 16);
298
299         /* Generate the session key and the next client and server creds. */
300         if (neg_flags & NETLOGON_NEG_128BIT) {
301                 creds_init_128(dc,
302                                 clnt_chal,
303                                 srv_chal,
304                                 mach_pw);
305         } else {
306                 creds_init_64(dc,
307                         clnt_chal,
308                         srv_chal,
309                         mach_pw);
310         }
311
312         dump_data_pw("creds_client_init: session key", dc->sess_key, 16);
313
314         DEBUG(10,("creds_client_init: clnt : %s\n", credstr(dc->clnt_chal.data) ));
315         DEBUG(10,("creds_client_init: server : %s\n", credstr(dc->srv_chal.data) ));
316         DEBUG(10,("creds_client_init: seed : %s\n", credstr(dc->seed_chal.data) ));
317
318         memcpy(init_chal_out->data, dc->clnt_chal.data, 8);
319 }
320
321 /****************************************************************************
322  Check a credential returned by the server.
323 ****************************************************************************/
324
325 bool netlogon_creds_client_check(const struct dcinfo *dc,
326                                  const struct netr_Credential *rcv_srv_chal_in)
327 {
328         if (memcmp(dc->srv_chal.data, rcv_srv_chal_in->data,
329                    sizeof(dc->srv_chal.data))) {
330
331                 DEBUG(0,("netlogon_creds_client_check: credentials check failed.\n"));
332                 DEBUGADD(5,("netlogon_creds_client_check: challenge : %s\n",
333                         credstr(rcv_srv_chal_in->data)));
334                 DEBUGADD(5,("calculated: %s\n", credstr(dc->srv_chal.data)));
335                 return false;
336         }
337
338         DEBUG(10,("netlogon_creds_client_check: credentials check OK.\n"));
339
340         return true;
341 }
342
343
344 /****************************************************************************
345   Step the client credentials to the next element in the chain, updating the
346   current client and server credentials and the seed
347   produce the next authenticator in the sequence ready to send to
348   the server
349 ****************************************************************************/
350
351 void netlogon_creds_client_step(struct dcinfo *dc,
352                                 struct netr_Authenticator *next_cred_out)
353 {
354         dc->sequence += 2;
355         creds_step(dc);
356         creds_reseed(dc);
357
358         memcpy(&next_cred_out->cred.data, &dc->clnt_chal.data,
359                 sizeof(next_cred_out->cred.data));
360         next_cred_out->timestamp = dc->sequence;
361 }