Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : Generic Authentication Interface
5 :
6 : Copyright (C) Andrew Tridgell 2003
7 : Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
8 : Copyright (C) Stefan Metzmacher 2004
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 <tevent.h>
26 : #include "libcli/composite/composite.h"
27 : #include "auth/gensec/gensec.h"
28 : #include "librpc/rpc/dcerpc.h"
29 : #include "librpc/rpc/dcerpc_proto.h"
30 : #include "param/param.h"
31 :
32 : /*
33 : return the rpc syntax and transfer syntax given the pipe uuid and version
34 : */
35 14493 : static NTSTATUS dcerpc_init_syntaxes(struct dcerpc_pipe *p,
36 : const struct ndr_interface_table *table,
37 : struct ndr_syntax_id *syntax,
38 : struct ndr_syntax_id *transfer_syntax)
39 : {
40 14493 : struct GUID *object = NULL;
41 :
42 14493 : p->object = dcerpc_binding_get_object(p->binding);
43 14493 : if (!GUID_all_zero(&p->object)) {
44 0 : object = &p->object;
45 : }
46 :
47 14493 : p->binding_handle = dcerpc_pipe_binding_handle(p, object, table);
48 14493 : if (p->binding_handle == NULL) {
49 0 : return NT_STATUS_NO_MEMORY;
50 : }
51 :
52 14493 : syntax->uuid = table->syntax_id.uuid;
53 14493 : syntax->if_version = table->syntax_id.if_version;
54 :
55 14493 : if (p->conn->flags & DCERPC_NDR64) {
56 0 : *transfer_syntax = ndr_transfer_syntax_ndr64;
57 : } else {
58 14493 : *transfer_syntax = ndr_transfer_syntax_ndr;
59 : }
60 :
61 14493 : return NT_STATUS_OK;
62 : }
63 :
64 :
65 : /*
66 : Send request to do a non-authenticated dcerpc bind
67 : */
68 : static void dcerpc_bind_auth_none_done(struct tevent_req *subreq);
69 :
70 7992 : struct composite_context *dcerpc_bind_auth_none_send(TALLOC_CTX *mem_ctx,
71 : struct dcerpc_pipe *p,
72 : const struct ndr_interface_table *table)
73 : {
74 : struct ndr_syntax_id syntax;
75 : struct ndr_syntax_id transfer_syntax;
76 :
77 : struct composite_context *c;
78 : struct tevent_req *subreq;
79 :
80 7992 : c = composite_create(mem_ctx, p->conn->event_ctx);
81 7992 : if (c == NULL) return NULL;
82 :
83 7992 : c->status = dcerpc_init_syntaxes(p, table,
84 : &syntax, &transfer_syntax);
85 7992 : if (!NT_STATUS_IS_OK(c->status)) {
86 0 : DEBUG(2,("Invalid uuid string in "
87 : "dcerpc_bind_auth_none_send\n"));
88 0 : composite_error(c, c->status);
89 0 : return c;
90 : }
91 :
92 7992 : subreq = dcerpc_bind_send(mem_ctx, p->conn->event_ctx, p,
93 : &syntax, &transfer_syntax);
94 7992 : if (composite_nomem(subreq, c)) return c;
95 7992 : tevent_req_set_callback(subreq, dcerpc_bind_auth_none_done, c);
96 :
97 7992 : return c;
98 : }
99 :
100 7992 : static void dcerpc_bind_auth_none_done(struct tevent_req *subreq)
101 : {
102 6898 : struct composite_context *ctx =
103 7992 : tevent_req_callback_data(subreq,
104 : struct composite_context);
105 :
106 7992 : ctx->status = dcerpc_bind_recv(subreq);
107 7992 : TALLOC_FREE(subreq);
108 7992 : if (!composite_is_ok(ctx)) return;
109 :
110 7980 : composite_done(ctx);
111 : }
112 :
113 : /*
114 : Receive result of a non-authenticated dcerpc bind
115 : */
116 7992 : NTSTATUS dcerpc_bind_auth_none_recv(struct composite_context *ctx)
117 : {
118 7992 : NTSTATUS result = composite_wait(ctx);
119 7992 : TALLOC_FREE(ctx);
120 7992 : return result;
121 : }
122 :
123 :
124 : /*
125 : Perform sync non-authenticated dcerpc bind
126 : */
127 11 : _PUBLIC_ NTSTATUS dcerpc_bind_auth_none(struct dcerpc_pipe *p,
128 : const struct ndr_interface_table *table)
129 : {
130 : struct composite_context *ctx;
131 :
132 11 : ctx = dcerpc_bind_auth_none_send(p, p, table);
133 11 : return dcerpc_bind_auth_none_recv(ctx);
134 : }
135 :
136 :
137 : struct bind_auth_state {
138 : struct dcerpc_pipe *pipe;
139 : struct ndr_syntax_id syntax;
140 : struct ndr_syntax_id transfer_syntax;
141 : struct dcerpc_auth out_auth_info;
142 : struct dcerpc_auth in_auth_info;
143 : bool more_processing; /* Is there anything more to do after the
144 : * first bind itself received? */
145 : };
146 :
147 : static void bind_auth_next_gensec_done(struct tevent_req *subreq);
148 : static void bind_auth_recv_alter(struct tevent_req *subreq);
149 :
150 11516 : static void bind_auth_next_step(struct composite_context *c)
151 : {
152 : struct bind_auth_state *state;
153 : struct dcecli_security *sec;
154 : struct tevent_req *subreq;
155 :
156 11516 : state = talloc_get_type(c->private_data, struct bind_auth_state);
157 11516 : sec = &state->pipe->conn->security_state;
158 :
159 11516 : if (state->in_auth_info.auth_type != sec->auth_type) {
160 0 : composite_error(c, NT_STATUS_RPC_PROTOCOL_ERROR);
161 0 : return;
162 : }
163 :
164 11516 : if (state->in_auth_info.auth_level != sec->auth_level) {
165 0 : composite_error(c, NT_STATUS_RPC_PROTOCOL_ERROR);
166 0 : return;
167 : }
168 :
169 11516 : if (state->in_auth_info.auth_context_id != sec->auth_context_id) {
170 0 : composite_error(c, NT_STATUS_RPC_PROTOCOL_ERROR);
171 0 : return;
172 : }
173 :
174 11516 : state->out_auth_info = (struct dcerpc_auth) {
175 11516 : .auth_type = sec->auth_type,
176 11516 : .auth_level = sec->auth_level,
177 11516 : .auth_context_id = sec->auth_context_id,
178 : };
179 :
180 : /* The status value here, from GENSEC is vital to the security
181 : * of the system. Even if the other end accepts, if GENSEC
182 : * claims 'MORE_PROCESSING_REQUIRED' then you must keep
183 : * feeding it blobs, or else the remote host/attacker might
184 : * avoid mutal authentication requirements.
185 : *
186 : * Likewise, you must not feed GENSEC too much (after the OK),
187 : * it doesn't like that either
188 : */
189 :
190 11516 : state->pipe->inhibit_timeout_processing = true;
191 11516 : state->pipe->timed_out = false;
192 :
193 21686 : subreq = gensec_update_send(state,
194 11516 : state->pipe->conn->event_ctx,
195 : sec->generic_state,
196 : state->in_auth_info.credentials);
197 11516 : if (composite_nomem(subreq, c)) return;
198 11516 : tevent_req_set_callback(subreq, bind_auth_next_gensec_done, c);
199 : }
200 :
201 11516 : static void bind_auth_next_gensec_done(struct tevent_req *subreq)
202 : {
203 10170 : struct composite_context *c =
204 11516 : tevent_req_callback_data(subreq,
205 : struct composite_context);
206 10170 : struct bind_auth_state *state =
207 11516 : talloc_get_type_abort(c->private_data,
208 : struct bind_auth_state);
209 11516 : struct dcerpc_pipe *p = state->pipe;
210 11516 : struct dcecli_security *sec = &p->conn->security_state;
211 11516 : bool more_processing = false;
212 :
213 11516 : state->pipe->inhibit_timeout_processing = false;
214 :
215 11516 : c->status = gensec_update_recv(subreq, state,
216 : &state->out_auth_info.credentials);
217 11516 : TALLOC_FREE(subreq);
218 :
219 11516 : if (NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
220 5035 : more_processing = true;
221 5035 : c->status = NT_STATUS_OK;
222 : }
223 :
224 12296 : if (!composite_is_ok(c)) return;
225 :
226 11516 : if (!more_processing) {
227 6481 : if (state->pipe->conn->flags & DCERPC_HEADER_SIGNING) {
228 5517 : gensec_want_feature(sec->generic_state,
229 : GENSEC_FEATURE_SIGN_PKT_HEADER);
230 : }
231 : }
232 :
233 11516 : if (state->out_auth_info.credentials.length == 0) {
234 6372 : composite_done(c);
235 6372 : return;
236 : }
237 :
238 5144 : state->in_auth_info = (struct dcerpc_auth) {
239 : .auth_type = DCERPC_AUTH_TYPE_NONE,
240 : };
241 5144 : sec->tmp_auth_info.in = &state->in_auth_info;
242 5144 : sec->tmp_auth_info.mem = state;
243 5144 : sec->tmp_auth_info.out = &state->out_auth_info;
244 :
245 5144 : if (!more_processing) {
246 : /* NO reply expected, so just send it */
247 109 : c->status = dcerpc_auth3(state->pipe, state);
248 109 : if (!composite_is_ok(c)) return;
249 :
250 109 : composite_done(c);
251 109 : return;
252 : }
253 :
254 : /* We are demanding a reply, so use a request that will get us one */
255 :
256 5035 : subreq = dcerpc_alter_context_send(state, state->pipe->conn->event_ctx,
257 : state->pipe,
258 5035 : &state->pipe->syntax,
259 5035 : &state->pipe->transfer_syntax);
260 5035 : if (composite_nomem(subreq, c)) return;
261 5035 : tevent_req_set_callback(subreq, bind_auth_recv_alter, c);
262 : }
263 :
264 :
265 5035 : static void bind_auth_recv_alter(struct tevent_req *subreq)
266 : {
267 4469 : struct composite_context *c =
268 5035 : tevent_req_callback_data(subreq,
269 : struct composite_context);
270 5035 : struct bind_auth_state *state = talloc_get_type(c->private_data,
271 : struct bind_auth_state);
272 5035 : struct dcecli_security *sec = &state->pipe->conn->security_state;
273 :
274 5035 : ZERO_STRUCT(sec->tmp_auth_info);
275 :
276 5035 : c->status = dcerpc_alter_context_recv(subreq);
277 5035 : TALLOC_FREE(subreq);
278 5035 : if (!composite_is_ok(c)) return;
279 :
280 5035 : bind_auth_next_step(c);
281 : }
282 :
283 :
284 6493 : static void bind_auth_recv_bindreply(struct tevent_req *subreq)
285 : {
286 5713 : struct composite_context *c =
287 6493 : tevent_req_callback_data(subreq,
288 : struct composite_context);
289 6493 : struct bind_auth_state *state = talloc_get_type(c->private_data,
290 : struct bind_auth_state);
291 6493 : struct dcecli_security *sec = &state->pipe->conn->security_state;
292 :
293 6493 : ZERO_STRUCT(sec->tmp_auth_info);
294 :
295 6493 : c->status = dcerpc_bind_recv(subreq);
296 6493 : TALLOC_FREE(subreq);
297 6493 : if (!composite_is_ok(c)) return;
298 :
299 6481 : if (!state->more_processing) {
300 : /* The first gensec_update has not requested a second run, so
301 : * we're done here. */
302 0 : composite_done(c);
303 0 : return;
304 : }
305 :
306 6481 : bind_auth_next_step(c);
307 : }
308 :
309 :
310 : static void dcerpc_bind_auth_gensec_done(struct tevent_req *subreq);
311 :
312 : /**
313 : Bind to a DCE/RPC pipe, send async request
314 : @param mem_ctx TALLOC_CTX for the allocation of the composite_context
315 : @param p The dcerpc_pipe to bind (must already be connected)
316 : @param table The interface table to use (the DCE/RPC bind both selects and interface and authenticates)
317 : @param credentials The credentials of the account to connect with
318 : @param auth_type Select the authentication scheme to use
319 : @param auth_level Chooses between unprotected (connect), signed or sealed
320 : @param service The service (used by Kerberos to select the service principal to contact)
321 : @retval A composite context describing the partial state of the bind
322 : */
323 :
324 6501 : struct composite_context *dcerpc_bind_auth_send(TALLOC_CTX *mem_ctx,
325 : struct dcerpc_pipe *p,
326 : const struct ndr_interface_table *table,
327 : struct cli_credentials *credentials,
328 : struct gensec_settings *gensec_settings,
329 : uint8_t auth_type, uint8_t auth_level,
330 : const char *service)
331 : {
332 : struct composite_context *c;
333 : struct bind_auth_state *state;
334 : struct dcecli_security *sec;
335 : struct tevent_req *subreq;
336 6501 : const char *target_principal = NULL;
337 :
338 : /* composite context allocation and setup */
339 6501 : c = composite_create(mem_ctx, p->conn->event_ctx);
340 6501 : if (c == NULL) return NULL;
341 :
342 6501 : state = talloc(c, struct bind_auth_state);
343 6501 : if (composite_nomem(state, c)) return c;
344 6501 : c->private_data = state;
345 :
346 6501 : state->pipe = p;
347 :
348 6501 : c->status = dcerpc_init_syntaxes(p, table,
349 : &state->syntax,
350 : &state->transfer_syntax);
351 6501 : if (!composite_is_ok(c)) return c;
352 :
353 6501 : sec = &p->conn->security_state;
354 :
355 6501 : c->status = gensec_client_start(p, &sec->generic_state,
356 : gensec_settings);
357 6501 : if (!NT_STATUS_IS_OK(c->status)) {
358 0 : DEBUG(1, ("Failed to start GENSEC client mode: %s\n",
359 : nt_errstr(c->status)));
360 0 : composite_error(c, c->status);
361 0 : return c;
362 : }
363 :
364 6501 : c->status = gensec_set_credentials(sec->generic_state, credentials);
365 6501 : if (!NT_STATUS_IS_OK(c->status)) {
366 0 : DEBUG(1, ("Failed to set GENSEC client credentials: %s\n",
367 : nt_errstr(c->status)));
368 0 : composite_error(c, c->status);
369 0 : return c;
370 : }
371 :
372 6501 : c->status = gensec_set_target_hostname(sec->generic_state,
373 : dcerpc_server_name(p));
374 6501 : if (!NT_STATUS_IS_OK(c->status)) {
375 0 : DEBUG(1, ("Failed to set GENSEC target hostname: %s\n",
376 : nt_errstr(c->status)));
377 0 : composite_error(c, c->status);
378 0 : return c;
379 : }
380 :
381 6501 : if (service != NULL) {
382 6308 : c->status = gensec_set_target_service(sec->generic_state,
383 : service);
384 6308 : if (!NT_STATUS_IS_OK(c->status)) {
385 0 : DEBUG(1, ("Failed to set GENSEC target service: %s\n",
386 : nt_errstr(c->status)));
387 0 : composite_error(c, c->status);
388 0 : return c;
389 : }
390 : }
391 :
392 6501 : if (p->binding != NULL) {
393 6501 : target_principal = dcerpc_binding_get_string_option(p->binding,
394 : "target_principal");
395 : }
396 6501 : if (target_principal != NULL) {
397 210 : c->status = gensec_set_target_principal(sec->generic_state,
398 : target_principal);
399 210 : if (!NT_STATUS_IS_OK(c->status)) {
400 0 : DEBUG(1, ("Failed to set GENSEC target principal to %s: %s\n",
401 : target_principal, nt_errstr(c->status)));
402 0 : composite_error(c, c->status);
403 0 : return c;
404 : }
405 : }
406 :
407 6501 : c->status = gensec_start_mech_by_authtype(sec->generic_state,
408 : auth_type, auth_level);
409 6501 : if (!NT_STATUS_IS_OK(c->status)) {
410 8 : DEBUG(1, ("Failed to start GENSEC client mechanism %s: %s\n",
411 : gensec_get_name_by_authtype(sec->generic_state, auth_type),
412 : nt_errstr(c->status)));
413 8 : composite_error(c, c->status);
414 8 : return c;
415 : }
416 :
417 6493 : sec->auth_type = auth_type;
418 6493 : sec->auth_level = auth_level,
419 : /*
420 : * We use auth_context_id = 1 as some older
421 : * Samba versions (<= 4.2.3) use that value hardcoded
422 : * in a response.
423 : */
424 6493 : sec->auth_context_id = 1;
425 :
426 6493 : state->out_auth_info = (struct dcerpc_auth) {
427 6493 : .auth_type = sec->auth_type,
428 6493 : .auth_level = sec->auth_level,
429 6493 : .auth_context_id = sec->auth_context_id,
430 : };
431 :
432 : /* The status value here, from GENSEC is vital to the security
433 : * of the system. Even if the other end accepts, if GENSEC
434 : * claims 'MORE_PROCESSING_REQUIRED' then you must keep
435 : * feeding it blobs, or else the remote host/attacker might
436 : * avoid mutal authentication requirements.
437 : *
438 : * Likewise, you must not feed GENSEC too much (after the OK),
439 : * it doesn't like that either
440 : */
441 :
442 6493 : state->pipe->inhibit_timeout_processing = true;
443 6493 : state->pipe->timed_out = false;
444 :
445 12206 : subreq = gensec_update_send(state,
446 6493 : p->conn->event_ctx,
447 : sec->generic_state,
448 : data_blob_null);
449 6493 : if (composite_nomem(subreq, c)) return c;
450 6493 : tevent_req_set_callback(subreq, dcerpc_bind_auth_gensec_done, c);
451 :
452 6493 : return c;
453 : }
454 :
455 6493 : static void dcerpc_bind_auth_gensec_done(struct tevent_req *subreq)
456 : {
457 5713 : struct composite_context *c =
458 6493 : tevent_req_callback_data(subreq,
459 : struct composite_context);
460 5713 : struct bind_auth_state *state =
461 6493 : talloc_get_type_abort(c->private_data,
462 : struct bind_auth_state);
463 6493 : struct dcerpc_pipe *p = state->pipe;
464 6493 : struct dcecli_security *sec = &p->conn->security_state;
465 :
466 6493 : state->pipe->inhibit_timeout_processing = false;
467 :
468 6493 : c->status = gensec_update_recv(subreq, state,
469 : &state->out_auth_info.credentials);
470 6493 : TALLOC_FREE(subreq);
471 12206 : if (!NT_STATUS_IS_OK(c->status) &&
472 6493 : !NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
473 0 : composite_error(c, c->status);
474 0 : return;
475 : }
476 :
477 6493 : state->more_processing = NT_STATUS_EQUAL(c->status,
478 : NT_STATUS_MORE_PROCESSING_REQUIRED);
479 :
480 6493 : if (state->out_auth_info.credentials.length == 0) {
481 0 : composite_done(c);
482 0 : return;
483 : }
484 :
485 6493 : if (gensec_have_feature(sec->generic_state, GENSEC_FEATURE_SIGN_PKT_HEADER)) {
486 6093 : if (sec->auth_level >= DCERPC_AUTH_LEVEL_PACKET) {
487 6083 : state->pipe->conn->flags |= DCERPC_PROPOSE_HEADER_SIGNING;
488 : }
489 : }
490 :
491 6493 : state->in_auth_info = (struct dcerpc_auth) {
492 : .auth_type = DCERPC_AUTH_TYPE_NONE,
493 : };
494 6493 : sec->tmp_auth_info.in = &state->in_auth_info;
495 6493 : sec->tmp_auth_info.mem = state;
496 6493 : sec->tmp_auth_info.out = &state->out_auth_info;
497 :
498 : /* The first request always is a dcerpc_bind. The subsequent ones
499 : * depend on gensec results */
500 6493 : subreq = dcerpc_bind_send(state, p->conn->event_ctx, p,
501 6493 : &state->syntax, &state->transfer_syntax);
502 6493 : if (composite_nomem(subreq, c)) return;
503 6493 : tevent_req_set_callback(subreq, bind_auth_recv_bindreply, c);
504 :
505 6493 : return;
506 : }
507 :
508 :
509 : /**
510 : Bind to a DCE/RPC pipe, receive result
511 : @param creq A composite context describing state of async call
512 : @retval NTSTATUS code
513 : */
514 :
515 6501 : NTSTATUS dcerpc_bind_auth_recv(struct composite_context *creq)
516 : {
517 6501 : NTSTATUS result = composite_wait(creq);
518 6501 : struct bind_auth_state *state = talloc_get_type(creq->private_data,
519 : struct bind_auth_state);
520 :
521 6501 : if (NT_STATUS_IS_OK(result)) {
522 : /*
523 : after a successful authenticated bind the session
524 : key reverts to the generic session key
525 : */
526 6481 : state->pipe->conn->security_state.session_key = dcecli_generic_session_key;
527 : }
528 :
529 6501 : talloc_free(creq);
530 6501 : return result;
531 : }
532 :
533 :
534 : /**
535 : Perform a GENSEC authenticated bind to a DCE/RPC pipe, sync
536 : @param p The dcerpc_pipe to bind (must already be connected)
537 : @param table The interface table to use (the DCE/RPC bind both selects and interface and authenticates)
538 : @param credentials The credentials of the account to connect with
539 : @param auth_type Select the authentication scheme to use
540 : @param auth_level Chooses between unprotected (connect), signed or sealed
541 : @param service The service (used by Kerberos to select the service principal to contact)
542 : @retval NTSTATUS status code
543 : */
544 :
545 0 : _PUBLIC_ NTSTATUS dcerpc_bind_auth(struct dcerpc_pipe *p,
546 : const struct ndr_interface_table *table,
547 : struct cli_credentials *credentials,
548 : struct gensec_settings *gensec_settings,
549 : uint8_t auth_type, uint8_t auth_level,
550 : const char *service)
551 : {
552 : struct composite_context *creq;
553 0 : creq = dcerpc_bind_auth_send(p, p, table, credentials, gensec_settings,
554 : auth_type, auth_level, service);
555 0 : return dcerpc_bind_auth_recv(creq);
556 : }
|