2
Unix SMB/CIFS implementation.
4
dcerpc schannel operations
6
Copyright (C) Andrew Tridgell 2004
7
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
8
Copyright (C) Rafal Szczesniak 2006
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.
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.
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/>.
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"
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;
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);
57
Stage 2 of schannel_key: Receive endpoint mapping and request secondary
60
static void continue_epm_map_binding(struct composite_context *ctx)
62
struct composite_context *c;
63
struct schannel_key_state *s;
64
struct composite_context *sec_conn_req;
66
c = talloc_get_type(ctx->async.private_data, struct composite_context);
67
s = talloc_get_type(c->private_data, struct schannel_key_state);
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);
78
/* send a request for secondary rpc connection */
79
sec_conn_req = dcerpc_secondary_connection_send(s->pipe,
81
if (composite_nomem(sec_conn_req, c)) return;
83
composite_continue(c, sec_conn_req, continue_secondary_connection, c);
88
Stage 3 of schannel_key: Receive secondary rpc connection and perform
89
non-authenticated bind request
91
static void continue_secondary_connection(struct composite_context *ctx)
93
struct composite_context *c;
94
struct schannel_key_state *s;
95
struct composite_context *auth_none_req;
97
c = talloc_get_type(ctx->async.private_data, struct composite_context);
98
s = talloc_get_type(c->private_data, struct schannel_key_state);
100
/* receive secondary rpc connection */
101
c->status = dcerpc_secondary_connection_recv(ctx, &s->pipe2);
102
if (!composite_is_ok(c)) return;
104
talloc_steal(s, s->pipe2);
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;
110
composite_continue(c, auth_none_req, continue_bind_auth_none, c);
115
Stage 4 of schannel_key: Receive non-authenticated bind and get
118
static void continue_bind_auth_none(struct composite_context *ctx)
120
struct composite_context *c;
121
struct schannel_key_state *s;
122
struct rpc_request *srv_challenge_req;
124
c = talloc_get_type(ctx->async.private_data, struct composite_context);
125
s = talloc_get_type(c->private_data, struct schannel_key_state);
127
/* receive result of non-authenticated bind request */
128
c->status = dcerpc_bind_auth_none_recv(ctx);
129
if (!composite_is_ok(c)) return;
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;
138
generate_random_buffer(s->credentials1.data, sizeof(s->credentials1.data));
141
request a netlogon challenge - a rpc request over opened secondary pipe
143
srv_challenge_req = dcerpc_netr_ServerReqChallenge_send(s->pipe2, c, &s->r);
144
if (composite_nomem(srv_challenge_req, c)) return;
146
composite_continue_rpc(c, srv_challenge_req, continue_srv_challenge, c);
151
Stage 5 of schannel_key: Receive a challenge and perform authentication
154
static void continue_srv_challenge(struct rpc_request *req)
156
struct composite_context *c;
157
struct schannel_key_state *s;
158
struct rpc_request *srv_auth2_req;
160
c = talloc_get_type(req->async.private_data, struct composite_context);
161
s = talloc_get_type(c->private_data, struct schannel_key_state);
163
/* receive rpc request result - netlogon challenge */
164
c->status = dcerpc_ndr_request_recv(req);
165
if (!composite_is_ok(c)) return;
167
/* prepare credentials for auth2 request */
168
s->mach_pwd = cli_credentials_get_nt_hash(s->credentials, c);
170
creds_client_init(s->creds, &s->credentials1, &s->credentials2,
171
s->mach_pwd, &s->credentials3, s->negotiate_flags);
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;
185
authenticate on the netlogon pipe - a rpc request over secondary pipe
187
srv_auth2_req = dcerpc_netr_ServerAuthenticate2_send(s->pipe2, c, &s->a);
188
if (composite_nomem(srv_auth2_req, c)) return;
190
composite_continue_rpc(c, srv_auth2_req, continue_srv_auth2, c);
195
Stage 6 of schannel_key: Receive authentication request result and verify
198
static void continue_srv_auth2(struct rpc_request *req)
200
struct composite_context *c;
201
struct schannel_key_state *s;
203
c = talloc_get_type(req->async.private_data, struct composite_context);
204
s = talloc_get_type(c->private_data, struct schannel_key_state);
206
/* receive rpc request result - auth2 credentials */
207
c->status = dcerpc_ndr_request_recv(req);
208
if (!composite_is_ok(c)) return;
210
/* verify credentials */
211
if (!creds_client_check(s->creds, s->a.out.return_credentials)) {
212
composite_error(c, NT_STATUS_UNSUCCESSFUL);
216
/* setup current netlogon credentials */
217
cli_credentials_set_netlogon_creds(s->credentials, s->creds);
224
Initiate establishing a schannel key using netlogon challenge
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)
232
struct composite_context *c;
233
struct schannel_key_state *s;
234
struct composite_context *epm_map_req;
236
/* composite context allocation and setup */
237
c = composite_create(mem_ctx, p->conn->event_ctx);
238
if (c == NULL) return NULL;
240
s = talloc_zero(c, struct schannel_key_state);
241
if (composite_nomem(s, c)) return c;
244
/* store parameters in the state structure */
246
s->credentials = credentials;
248
/* allocate credentials */
249
s->creds = talloc(c, struct creds_CredentialState);
250
if (composite_nomem(s->creds, c)) return c;
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;
256
s->negotiate_flags = NETLOGON_NEG_AUTH2_FLAGS;
259
/* allocate binding structure */
260
s->binding = talloc(c, struct dcerpc_binding);
261
if (composite_nomem(s->binding, c)) return c;
263
*s->binding = *s->pipe->binding;
265
/* request the netlogon endpoint mapping */
266
epm_map_req = dcerpc_epm_map_binding_send(c, s->binding,
268
s->pipe->conn->event_ctx,
270
if (composite_nomem(epm_map_req, c)) return c;
272
composite_continue(c, epm_map_req, continue_epm_map_binding, c);
278
Receive result of schannel key request
280
NTSTATUS dcerpc_schannel_key_recv(struct composite_context *c)
282
NTSTATUS status = composite_wait(c);
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;
298
static void continue_bind_auth(struct composite_context *ctx);
302
Stage 2 of auth_schannel: Receive schannel key and intitiate an
303
authenticated bind using received credentials
305
static void continue_schannel_key(struct composite_context *ctx)
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);
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)));
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,
326
if (composite_nomem(auth_req, c)) return;
328
composite_continue(c, auth_req, continue_bind_auth, c);
333
Stage 3 of auth_schannel: Receivce result of authenticated bind
334
and say if we're done ok.
336
static void continue_bind_auth(struct composite_context *ctx)
338
struct composite_context *c = talloc_get_type(ctx->async.private_data,
339
struct composite_context);
341
c->status = dcerpc_bind_auth_recv(ctx);
342
if (!composite_is_ok(c)) return;
349
Initiate schannel authentication request
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,
358
struct composite_context *c;
359
struct auth_schannel_state *s;
360
struct composite_context *schan_key_req;
362
/* composite context allocation and setup */
363
c = composite_create(tmp_ctx, p->conn->event_ctx);
364
if (c == NULL) return NULL;
366
s = talloc_zero(c, struct auth_schannel_state);
367
if (composite_nomem(s, c)) return c;
370
/* store parameters in the state structure */
372
s->credentials = credentials;
374
s->auth_level = auth_level;
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;
381
composite_continue(c, schan_key_req, continue_schannel_key, c);
387
Receive result of schannel authentication request
389
NTSTATUS dcerpc_bind_auth_schannel_recv(struct composite_context *c)
391
NTSTATUS status = composite_wait(c);
399
Perform schannel authenticated bind - sync version
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,
408
struct composite_context *c;
410
c = dcerpc_bind_auth_schannel_send(tmp_ctx, p, table, credentials, lp_ctx,
412
return dcerpc_bind_auth_schannel_recv(c);