~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/libsmb/credentials.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
        struct netr_Credential 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
        if (!received_cred || !cred_out) {
 
259
                return false;
 
260
        }
 
261
 
 
262
        /* Do all operations on a temporary copy of the dc,
 
263
           which we throw away if the checks fail. */
 
264
 
 
265
        tmp_dc.sequence = received_cred->timestamp;
 
266
 
 
267
        creds_step(&tmp_dc);
 
268
 
 
269
        /* Create the outgoing credentials */
 
270
        cred_out->timestamp = tmp_dc.sequence + 1;
 
271
        memcpy(&cred_out->cred, &tmp_dc.srv_chal, sizeof(cred_out->cred));
 
272
 
 
273
        creds_reseed(&tmp_dc);
 
274
 
 
275
        ret = netlogon_creds_server_check(&tmp_dc, &received_cred->cred);
 
276
        if (!ret) {
 
277
                return false;
 
278
        }
 
279
 
 
280
        /* creds step succeeded - replace the current creds. */
 
281
        *dc = tmp_dc;
 
282
        return true;
 
283
}
 
284
 
 
285
/****************************************************************************
 
286
 Create a client credential struct.
 
287
****************************************************************************/
 
288
 
 
289
void creds_client_init(uint32 neg_flags,
 
290
                        struct dcinfo *dc,
 
291
                        struct netr_Credential *clnt_chal,
 
292
                        struct netr_Credential *srv_chal,
 
293
                        const unsigned char mach_pw[16],
 
294
                        struct netr_Credential *init_chal_out)
 
295
{
 
296
        dc->sequence = time(NULL);
 
297
 
 
298
        DEBUG(10,("creds_client_init: neg_flags : %x\n", (unsigned int)neg_flags));
 
299
        DEBUG(10,("creds_client_init: client chal : %s\n", credstr(clnt_chal->data) ));
 
300
        DEBUG(10,("creds_client_init: server chal : %s\n", credstr(srv_chal->data) ));
 
301
        dump_data_pw("creds_client_init: machine pass", (const unsigned char *)mach_pw, 16);
 
302
 
 
303
        /* Generate the session key and the next client and server creds. */
 
304
        if (neg_flags & NETLOGON_NEG_128BIT) {
 
305
                creds_init_128(dc,
 
306
                                clnt_chal,
 
307
                                srv_chal,
 
308
                                mach_pw);
 
309
        } else {
 
310
                creds_init_64(dc,
 
311
                        clnt_chal,
 
312
                        srv_chal,
 
313
                        mach_pw);
 
314
        }
 
315
 
 
316
        dump_data_pw("creds_client_init: session key", dc->sess_key, 16);
 
317
 
 
318
        DEBUG(10,("creds_client_init: clnt : %s\n", credstr(dc->clnt_chal.data) ));
 
319
        DEBUG(10,("creds_client_init: server : %s\n", credstr(dc->srv_chal.data) ));
 
320
        DEBUG(10,("creds_client_init: seed : %s\n", credstr(dc->seed_chal.data) ));
 
321
 
 
322
        memcpy(init_chal_out->data, dc->clnt_chal.data, 8);
 
323
}
 
324
 
 
325
/****************************************************************************
 
326
 Check a credential returned by the server.
 
327
****************************************************************************/
 
328
 
 
329
bool netlogon_creds_client_check(const struct dcinfo *dc,
 
330
                                 const struct netr_Credential *rcv_srv_chal_in)
 
331
{
 
332
        if (memcmp(dc->srv_chal.data, rcv_srv_chal_in->data,
 
333
                   sizeof(dc->srv_chal.data))) {
 
334
 
 
335
                DEBUG(0,("netlogon_creds_client_check: credentials check failed.\n"));
 
336
                DEBUGADD(5,("netlogon_creds_client_check: challenge : %s\n",
 
337
                        credstr(rcv_srv_chal_in->data)));
 
338
                DEBUGADD(5,("calculated: %s\n", credstr(dc->srv_chal.data)));
 
339
                return false;
 
340
        }
 
341
 
 
342
        DEBUG(10,("netlogon_creds_client_check: credentials check OK.\n"));
 
343
 
 
344
        return true;
 
345
}
 
346
 
 
347
 
 
348
/****************************************************************************
 
349
  Step the client credentials to the next element in the chain, updating the
 
350
  current client and server credentials and the seed
 
351
  produce the next authenticator in the sequence ready to send to
 
352
  the server
 
353
****************************************************************************/
 
354
 
 
355
void netlogon_creds_client_step(struct dcinfo *dc,
 
356
                                struct netr_Authenticator *next_cred_out)
 
357
{
 
358
        dc->sequence += 2;
 
359
        creds_step(dc);
 
360
        creds_reseed(dc);
 
361
 
 
362
        memcpy(&next_cred_out->cred.data, &dc->clnt_chal.data,
 
363
                sizeof(next_cred_out->cred.data));
 
364
        next_cred_out->timestamp = dc->sequence;
 
365
}