~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/librpc/rpc/dcerpc_schannel.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
 
 
4
   dcerpc schannel operations
 
5
 
 
6
   Copyright (C) Andrew Tridgell 2004
 
7
   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
 
8
   Copyright (C) Rafal Szczesniak 2006
 
9
 
 
10
   This program is free software; you can redistribute it and/or modify
 
11
   it under the terms of the GNU General Public License as published by
 
12
   the Free Software Foundation; either version 3 of the License, or
 
13
   (at your option) any later version.
 
14
   
 
15
   This program is distributed in the hope that it will be useful,
 
16
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
18
   GNU General Public License for more details.
 
19
   
 
20
   You should have received a copy of the GNU General Public License
 
21
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
22
*/
 
23
 
 
24
#include "includes.h"
 
25
#include "auth/auth.h"
 
26
#include "libcli/composite/composite.h"
 
27
#include "libcli/auth/libcli_auth.h"
 
28
#include "librpc/gen_ndr/ndr_netlogon.h"
 
29
#include "librpc/gen_ndr/ndr_netlogon_c.h"
 
30
#include "auth/credentials/credentials.h"
 
31
#include "librpc/rpc/dcerpc_proto.h"
 
32
#include "param/param.h"
 
33
 
 
34
struct schannel_key_state {
 
35
        struct dcerpc_pipe *pipe;
 
36
        struct dcerpc_pipe *pipe2;
 
37
        struct dcerpc_binding *binding;
 
38
        struct cli_credentials *credentials;
 
39
        struct creds_CredentialState *creds;
 
40
        uint32_t negotiate_flags;
 
41
        struct netr_Credential credentials1;
 
42
        struct netr_Credential credentials2;
 
43
        struct netr_Credential credentials3;
 
44
        struct netr_ServerReqChallenge r;
 
45
        struct netr_ServerAuthenticate2 a;
 
46
        const struct samr_Password *mach_pwd;
 
47
};
 
48
 
 
49
 
 
50
static void continue_secondary_connection(struct composite_context *ctx);
 
51
static void continue_bind_auth_none(struct composite_context *ctx);
 
52
static void continue_srv_challenge(struct rpc_request *req);
 
53
static void continue_srv_auth2(struct rpc_request *req);
 
54
 
 
55
 
 
56
/*
 
57
  Stage 2 of schannel_key: Receive endpoint mapping and request secondary
 
58
  rpc connection
 
59
*/
 
60
static void continue_epm_map_binding(struct composite_context *ctx)
 
61
{
 
62
        struct composite_context *c;
 
63
        struct schannel_key_state *s;
 
64
        struct composite_context *sec_conn_req;
 
65
 
 
66
        c = talloc_get_type(ctx->async.private_data, struct composite_context);
 
67
        s = talloc_get_type(c->private_data, struct schannel_key_state);
 
68
 
 
69
        /* receive endpoint mapping */
 
70
        c->status = dcerpc_epm_map_binding_recv(ctx);
 
71
        if (!NT_STATUS_IS_OK(c->status)) {
 
72
                DEBUG(0,("Failed to map DCERPC/TCP NCACN_NP pipe for '%s' - %s\n",
 
73
                         NDR_NETLOGON_UUID, nt_errstr(c->status)));
 
74
                composite_error(c, c->status);
 
75
                return;
 
76
        }
 
77
 
 
78
        /* send a request for secondary rpc connection */
 
79
        sec_conn_req = dcerpc_secondary_connection_send(s->pipe,
 
80
                                                        s->binding);
 
81
        if (composite_nomem(sec_conn_req, c)) return;
 
82
 
 
83
        composite_continue(c, sec_conn_req, continue_secondary_connection, c);
 
84
}
 
85
 
 
86
 
 
87
/*
 
88
  Stage 3 of schannel_key: Receive secondary rpc connection and perform
 
89
  non-authenticated bind request
 
90
*/
 
91
static void continue_secondary_connection(struct composite_context *ctx)
 
92
{
 
93
        struct composite_context *c;
 
94
        struct schannel_key_state *s;
 
95
        struct composite_context *auth_none_req;
 
96
 
 
97
        c = talloc_get_type(ctx->async.private_data, struct composite_context);
 
98
        s = talloc_get_type(c->private_data, struct schannel_key_state);
 
99
 
 
100
        /* receive secondary rpc connection */
 
101
        c->status = dcerpc_secondary_connection_recv(ctx, &s->pipe2);
 
102
        if (!composite_is_ok(c)) return;
 
103
 
 
104
        talloc_steal(s, s->pipe2);
 
105
 
 
106
        /* initiate a non-authenticated bind */
 
107
        auth_none_req = dcerpc_bind_auth_none_send(c, s->pipe2, &ndr_table_netlogon);
 
108
        if (composite_nomem(auth_none_req, c)) return;
 
109
 
 
110
        composite_continue(c, auth_none_req, continue_bind_auth_none, c);
 
111
}
 
112
 
 
113
 
 
114
/*
 
115
  Stage 4 of schannel_key: Receive non-authenticated bind and get
 
116
  a netlogon challenge
 
117
*/
 
118
static void continue_bind_auth_none(struct composite_context *ctx)
 
119
{
 
120
        struct composite_context *c;
 
121
        struct schannel_key_state *s;
 
122
        struct rpc_request *srv_challenge_req;
 
123
 
 
124
        c = talloc_get_type(ctx->async.private_data, struct composite_context);
 
125
        s = talloc_get_type(c->private_data, struct schannel_key_state);
 
126
 
 
127
        /* receive result of non-authenticated bind request */
 
128
        c->status = dcerpc_bind_auth_none_recv(ctx);
 
129
        if (!composite_is_ok(c)) return;
 
130
        
 
131
        /* prepare a challenge request */
 
132
        s->r.in.server_name   = talloc_asprintf(c, "\\\\%s", dcerpc_server_name(s->pipe));
 
133
        if (composite_nomem(s->r.in.server_name, c)) return;
 
134
        s->r.in.computer_name = cli_credentials_get_workstation(s->credentials);
 
135
        s->r.in.credentials   = &s->credentials1;
 
136
        s->r.out.return_credentials  = &s->credentials2;
 
137
        
 
138
        generate_random_buffer(s->credentials1.data, sizeof(s->credentials1.data));
 
139
 
 
140
        /*
 
141
          request a netlogon challenge - a rpc request over opened secondary pipe
 
142
        */
 
143
        srv_challenge_req = dcerpc_netr_ServerReqChallenge_send(s->pipe2, c, &s->r);
 
144
        if (composite_nomem(srv_challenge_req, c)) return;
 
145
 
 
146
        composite_continue_rpc(c, srv_challenge_req, continue_srv_challenge, c);
 
147
}
 
148
 
 
149
 
 
150
/*
 
151
  Stage 5 of schannel_key: Receive a challenge and perform authentication
 
152
  on the netlogon pipe
 
153
*/
 
154
static void continue_srv_challenge(struct rpc_request *req)
 
155
{
 
156
        struct composite_context *c;
 
157
        struct schannel_key_state *s;
 
158
        struct rpc_request *srv_auth2_req;
 
159
 
 
160
        c = talloc_get_type(req->async.private_data, struct composite_context);
 
161
        s = talloc_get_type(c->private_data, struct schannel_key_state);
 
162
 
 
163
        /* receive rpc request result - netlogon challenge */
 
164
        c->status = dcerpc_ndr_request_recv(req);
 
165
        if (!composite_is_ok(c)) return;
 
166
 
 
167
        /* prepare credentials for auth2 request */
 
168
        s->mach_pwd = cli_credentials_get_nt_hash(s->credentials, c);
 
169
 
 
170
        creds_client_init(s->creds, &s->credentials1, &s->credentials2,
 
171
                          s->mach_pwd, &s->credentials3, s->negotiate_flags);
 
172
 
 
173
        /* auth2 request arguments */
 
174
        s->a.in.server_name      = s->r.in.server_name;
 
175
        s->a.in.account_name     = cli_credentials_get_username(s->credentials);
 
176
        s->a.in.secure_channel_type =
 
177
                cli_credentials_get_secure_channel_type(s->credentials);
 
178
        s->a.in.computer_name    = cli_credentials_get_workstation(s->credentials);
 
179
        s->a.in.negotiate_flags  = &s->negotiate_flags;
 
180
        s->a.in.credentials      = &s->credentials3;
 
181
        s->a.out.negotiate_flags = &s->negotiate_flags;
 
182
        s->a.out.return_credentials     = &s->credentials3;
 
183
 
 
184
        /*
 
185
          authenticate on the netlogon pipe - a rpc request over secondary pipe
 
186
        */
 
187
        srv_auth2_req = dcerpc_netr_ServerAuthenticate2_send(s->pipe2, c, &s->a);
 
188
        if (composite_nomem(srv_auth2_req, c)) return;
 
189
 
 
190
        composite_continue_rpc(c, srv_auth2_req, continue_srv_auth2, c);
 
191
}
 
192
 
 
193
 
 
194
/*
 
195
  Stage 6 of schannel_key: Receive authentication request result and verify
 
196
  received credentials
 
197
*/
 
198
static void continue_srv_auth2(struct rpc_request *req)
 
199
{
 
200
        struct composite_context *c;
 
201
        struct schannel_key_state *s;
 
202
 
 
203
        c = talloc_get_type(req->async.private_data, struct composite_context);
 
204
        s = talloc_get_type(c->private_data, struct schannel_key_state);
 
205
 
 
206
        /* receive rpc request result - auth2 credentials */ 
 
207
        c->status = dcerpc_ndr_request_recv(req);
 
208
        if (!composite_is_ok(c)) return;
 
209
 
 
210
        /* verify credentials */
 
211
        if (!creds_client_check(s->creds, s->a.out.return_credentials)) {
 
212
                composite_error(c, NT_STATUS_UNSUCCESSFUL);
 
213
                return;
 
214
        }
 
215
 
 
216
        /* setup current netlogon credentials */
 
217
        cli_credentials_set_netlogon_creds(s->credentials, s->creds);
 
218
 
 
219
        composite_done(c);
 
220
}
 
221
 
 
222
 
 
223
/*
 
224
  Initiate establishing a schannel key using netlogon challenge
 
225
  on a secondary pipe
 
226
*/
 
227
struct composite_context *dcerpc_schannel_key_send(TALLOC_CTX *mem_ctx,
 
228
                                                   struct dcerpc_pipe *p,
 
229
                                                   struct cli_credentials *credentials,
 
230
                                                   struct loadparm_context *lp_ctx)
 
231
{
 
232
        struct composite_context *c;
 
233
        struct schannel_key_state *s;
 
234
        struct composite_context *epm_map_req;
 
235
        
 
236
        /* composite context allocation and setup */
 
237
        c = composite_create(mem_ctx, p->conn->event_ctx);
 
238
        if (c == NULL) return NULL;
 
239
 
 
240
        s = talloc_zero(c, struct schannel_key_state);
 
241
        if (composite_nomem(s, c)) return c;
 
242
        c->private_data = s;
 
243
 
 
244
        /* store parameters in the state structure */
 
245
        s->pipe        = p;
 
246
        s->credentials = credentials;
 
247
 
 
248
        /* allocate credentials */
 
249
        s->creds = talloc(c, struct creds_CredentialState);
 
250
        if (composite_nomem(s->creds, c)) return c;
 
251
 
 
252
        /* type of authentication depends on schannel type */
 
253
        if (s->pipe->conn->flags & DCERPC_SCHANNEL_128) {
 
254
                s->negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
 
255
        } else {
 
256
                s->negotiate_flags = NETLOGON_NEG_AUTH2_FLAGS;
 
257
        }
 
258
 
 
259
        /* allocate binding structure */
 
260
        s->binding = talloc(c, struct dcerpc_binding);
 
261
        if (composite_nomem(s->binding, c)) return c;
 
262
 
 
263
        *s->binding = *s->pipe->binding;
 
264
 
 
265
        /* request the netlogon endpoint mapping */
 
266
        epm_map_req = dcerpc_epm_map_binding_send(c, s->binding,
 
267
                                                  &ndr_table_netlogon,
 
268
                                                  s->pipe->conn->event_ctx,
 
269
                                                  lp_ctx);
 
270
        if (composite_nomem(epm_map_req, c)) return c;
 
271
 
 
272
        composite_continue(c, epm_map_req, continue_epm_map_binding, c);
 
273
        return c;
 
274
}
 
275
 
 
276
 
 
277
/*
 
278
  Receive result of schannel key request
 
279
 */
 
280
NTSTATUS dcerpc_schannel_key_recv(struct composite_context *c)
 
281
{
 
282
        NTSTATUS status = composite_wait(c);
 
283
        
 
284
        talloc_free(c);
 
285
        return status;
 
286
}
 
287
 
 
288
 
 
289
struct auth_schannel_state {
 
290
        struct dcerpc_pipe *pipe;
 
291
        struct cli_credentials *credentials;
 
292
        const struct ndr_interface_table *table;
 
293
        struct loadparm_context *lp_ctx;
 
294
        uint8_t auth_level;
 
295
};
 
296
 
 
297
 
 
298
static void continue_bind_auth(struct composite_context *ctx);
 
299
 
 
300
 
 
301
/*
 
302
  Stage 2 of auth_schannel: Receive schannel key and intitiate an
 
303
  authenticated bind using received credentials
 
304
 */
 
305
static void continue_schannel_key(struct composite_context *ctx)
 
306
{
 
307
        struct composite_context *auth_req;
 
308
        struct composite_context *c = talloc_get_type(ctx->async.private_data,
 
309
                                                      struct composite_context);
 
310
        struct auth_schannel_state *s = talloc_get_type(c->private_data,
 
311
                                                        struct auth_schannel_state);
 
312
 
 
313
        /* receive schannel key */
 
314
        c->status = dcerpc_schannel_key_recv(ctx);
 
315
        if (!composite_is_ok(c)) {
 
316
                DEBUG(1, ("Failed to setup credentials for account %s: %s\n",
 
317
                          cli_credentials_get_username(s->credentials), nt_errstr(c->status)));
 
318
                return;
 
319
        }
 
320
 
 
321
        /* send bind auth request with received creds */
 
322
        auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table, s->credentials, 
 
323
                                         lp_gensec_settings(c, s->lp_ctx),
 
324
                                         DCERPC_AUTH_TYPE_SCHANNEL, s->auth_level,
 
325
                                         NULL);
 
326
        if (composite_nomem(auth_req, c)) return;
 
327
        
 
328
        composite_continue(c, auth_req, continue_bind_auth, c);
 
329
}
 
330
 
 
331
 
 
332
/*
 
333
  Stage 3 of auth_schannel: Receivce result of authenticated bind
 
334
  and say if we're done ok.
 
335
*/
 
336
static void continue_bind_auth(struct composite_context *ctx)
 
337
{
 
338
        struct composite_context *c = talloc_get_type(ctx->async.private_data,
 
339
                                                      struct composite_context);
 
340
 
 
341
        c->status = dcerpc_bind_auth_recv(ctx);
 
342
        if (!composite_is_ok(c)) return;
 
343
 
 
344
        composite_done(c);
 
345
}
 
346
 
 
347
 
 
348
/*
 
349
  Initiate schannel authentication request
 
350
*/
 
351
struct composite_context *dcerpc_bind_auth_schannel_send(TALLOC_CTX *tmp_ctx, 
 
352
                                                         struct dcerpc_pipe *p,
 
353
                                                         const struct ndr_interface_table *table,
 
354
                                                         struct cli_credentials *credentials,
 
355
                                                         struct loadparm_context *lp_ctx,
 
356
                                                         uint8_t auth_level)
 
357
{
 
358
        struct composite_context *c;
 
359
        struct auth_schannel_state *s;
 
360
        struct composite_context *schan_key_req;
 
361
 
 
362
        /* composite context allocation and setup */
 
363
        c = composite_create(tmp_ctx, p->conn->event_ctx);
 
364
        if (c == NULL) return NULL;
 
365
        
 
366
        s = talloc_zero(c, struct auth_schannel_state);
 
367
        if (composite_nomem(s, c)) return c;
 
368
        c->private_data = s;
 
369
 
 
370
        /* store parameters in the state structure */
 
371
        s->pipe        = p;
 
372
        s->credentials = credentials;
 
373
        s->table       = table;
 
374
        s->auth_level  = auth_level;
 
375
        s->lp_ctx      = lp_ctx;
 
376
 
 
377
        /* start getting schannel key first */
 
378
        schan_key_req = dcerpc_schannel_key_send(c, p, credentials, lp_ctx);
 
379
        if (composite_nomem(schan_key_req, c)) return c;
 
380
 
 
381
        composite_continue(c, schan_key_req, continue_schannel_key, c);
 
382
        return c;
 
383
}
 
384
 
 
385
 
 
386
/*
 
387
  Receive result of schannel authentication request
 
388
*/
 
389
NTSTATUS dcerpc_bind_auth_schannel_recv(struct composite_context *c)
 
390
{
 
391
        NTSTATUS status = composite_wait(c);
 
392
        
 
393
        talloc_free(c);
 
394
        return status;
 
395
}
 
396
 
 
397
 
 
398
/*
 
399
  Perform schannel authenticated bind - sync version
 
400
 */
 
401
_PUBLIC_ NTSTATUS dcerpc_bind_auth_schannel(TALLOC_CTX *tmp_ctx, 
 
402
                                   struct dcerpc_pipe *p,
 
403
                                   const struct ndr_interface_table *table,
 
404
                                   struct cli_credentials *credentials,
 
405
                                   struct loadparm_context *lp_ctx,
 
406
                                   uint8_t auth_level)
 
407
{
 
408
        struct composite_context *c;
 
409
 
 
410
        c = dcerpc_bind_auth_schannel_send(tmp_ctx, p, table, credentials, lp_ctx,
 
411
                                           auth_level);
 
412
        return dcerpc_bind_auth_schannel_recv(c);
 
413
}