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 20179 : 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 20179 : struct GUID *object = NULL;
41 :
42 20179 : p->object = dcerpc_binding_get_object(p->binding);
43 20179 : if (!GUID_all_zero(&p->object)) {
44 10 : object = &p->object;
45 : }
46 :
47 20179 : p->binding_handle = dcerpc_pipe_binding_handle(p, object, table);
48 20179 : if (p->binding_handle == NULL) {
49 0 : return NT_STATUS_NO_MEMORY;
50 : }
51 :
52 20179 : syntax->uuid = table->syntax_id.uuid;
53 20179 : syntax->if_version = table->syntax_id.if_version;
54 :
55 20179 : if (p->conn->flags & DCERPC_NDR64) {
56 0 : *transfer_syntax = ndr_transfer_syntax_ndr64;
57 : } else {
58 20179 : *transfer_syntax = ndr_transfer_syntax_ndr;
59 : }
60 :
61 20179 : 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 11420 : 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 440 : struct ndr_syntax_id syntax;
75 440 : struct ndr_syntax_id transfer_syntax;
76 :
77 440 : struct composite_context *c;
78 440 : struct tevent_req *subreq;
79 :
80 11420 : c = composite_create(mem_ctx, p->conn->event_ctx);
81 11420 : if (c == NULL) return NULL;
82 :
83 11420 : c->status = dcerpc_init_syntaxes(p, table,
84 : &syntax, &transfer_syntax);
85 11420 : 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 11420 : subreq = dcerpc_bind_send(mem_ctx, p->conn->event_ctx, p,
93 : &syntax, &transfer_syntax);
94 11420 : if (composite_nomem(subreq, c)) return c;
95 11420 : tevent_req_set_callback(subreq, dcerpc_bind_auth_none_done, c);
96 :
97 11420 : return c;
98 : }
99 :
100 11420 : static void dcerpc_bind_auth_none_done(struct tevent_req *subreq)
101 : {
102 440 : struct composite_context *ctx =
103 11420 : tevent_req_callback_data(subreq,
104 : struct composite_context);
105 :
106 11420 : ctx->status = dcerpc_bind_recv(subreq);
107 11420 : TALLOC_FREE(subreq);
108 11420 : if (!composite_is_ok(ctx)) return;
109 :
110 11351 : composite_done(ctx);
111 : }
112 :
113 : /*
114 : Receive result of a non-authenticated dcerpc bind
115 : */
116 11420 : NTSTATUS dcerpc_bind_auth_none_recv(struct composite_context *ctx)
117 : {
118 11420 : NTSTATUS result = composite_wait(ctx);
119 11420 : TALLOC_FREE(ctx);
120 11420 : return result;
121 : }
122 :
123 :
124 : /*
125 : Perform sync non-authenticated dcerpc bind
126 : */
127 175 : _PUBLIC_ NTSTATUS dcerpc_bind_auth_none(struct dcerpc_pipe *p,
128 : const struct ndr_interface_table *table)
129 : {
130 0 : struct composite_context *ctx;
131 :
132 175 : ctx = dcerpc_bind_auth_none_send(p, p, table);
133 175 : 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 14434 : static void bind_auth_next_step(struct composite_context *c)
151 : {
152 520 : struct bind_auth_state *state;
153 520 : struct dcecli_security *sec;
154 520 : struct tevent_req *subreq;
155 :
156 14434 : state = talloc_get_type(c->private_data, struct bind_auth_state);
157 14434 : sec = &state->pipe->conn->security_state;
158 :
159 14434 : 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 14434 : 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 14434 : 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 14434 : state->out_auth_info = (struct dcerpc_auth) {
175 13914 : .auth_type = sec->auth_type,
176 13914 : .auth_level = sec->auth_level,
177 13914 : .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 mutual 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 14434 : state->pipe->inhibit_timeout_processing = true;
191 14434 : state->pipe->timed_out = false;
192 :
193 14434 : subreq = gensec_update_send(state,
194 13914 : state->pipe->conn->event_ctx,
195 : sec->generic_state,
196 : state->in_auth_info.credentials);
197 14434 : if (composite_nomem(subreq, c)) return;
198 14434 : tevent_req_set_callback(subreq, bind_auth_next_gensec_done, c);
199 : }
200 :
201 14434 : static void bind_auth_next_gensec_done(struct tevent_req *subreq)
202 : {
203 520 : struct composite_context *c =
204 14434 : tevent_req_callback_data(subreq,
205 : struct composite_context);
206 520 : struct bind_auth_state *state =
207 14434 : talloc_get_type_abort(c->private_data,
208 : struct bind_auth_state);
209 14434 : struct dcerpc_pipe *p = state->pipe;
210 14434 : struct dcecli_security *sec = &p->conn->security_state;
211 14434 : bool more_processing = false;
212 :
213 14434 : state->pipe->inhibit_timeout_processing = false;
214 :
215 14434 : c->status = gensec_update_recv(subreq, state,
216 : &state->out_auth_info.credentials);
217 14434 : TALLOC_FREE(subreq);
218 :
219 14434 : if (NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
220 5730 : more_processing = true;
221 5730 : c->status = NT_STATUS_OK;
222 : }
223 :
224 22714 : if (!composite_is_ok(c)) return;
225 :
226 14434 : if (!more_processing) {
227 8704 : if (state->pipe->conn->flags & DCERPC_HEADER_SIGNING) {
228 7730 : gensec_want_feature(sec->generic_state,
229 : GENSEC_FEATURE_SIGN_PKT_HEADER);
230 : }
231 : }
232 :
233 14434 : if (state->out_auth_info.credentials.length == 0) {
234 8519 : composite_done(c);
235 8519 : return;
236 : }
237 :
238 5915 : state->in_auth_info = (struct dcerpc_auth) {
239 : .auth_type = DCERPC_AUTH_TYPE_NONE,
240 : };
241 5915 : sec->tmp_auth_info.in = &state->in_auth_info;
242 5915 : sec->tmp_auth_info.mem = state;
243 5915 : sec->tmp_auth_info.out = &state->out_auth_info;
244 :
245 5915 : if (!more_processing) {
246 : /* NO reply expected, so just send it */
247 185 : c->status = dcerpc_auth3(state->pipe, state);
248 185 : if (!composite_is_ok(c)) return;
249 :
250 185 : composite_done(c);
251 185 : return;
252 : }
253 :
254 : /* We are demanding a reply, so use a request that will get us one */
255 :
256 5826 : subreq = dcerpc_alter_context_send(state, state->pipe->conn->event_ctx,
257 : state->pipe,
258 5730 : &state->pipe->syntax,
259 5730 : &state->pipe->transfer_syntax);
260 5730 : if (composite_nomem(subreq, c)) return;
261 5730 : tevent_req_set_callback(subreq, bind_auth_recv_alter, c);
262 : }
263 :
264 :
265 5730 : static void bind_auth_recv_alter(struct tevent_req *subreq)
266 : {
267 96 : struct composite_context *c =
268 5730 : tevent_req_callback_data(subreq,
269 : struct composite_context);
270 5730 : struct bind_auth_state *state = talloc_get_type(c->private_data,
271 : struct bind_auth_state);
272 5730 : struct dcecli_security *sec = &state->pipe->conn->security_state;
273 :
274 5730 : ZERO_STRUCT(sec->tmp_auth_info);
275 :
276 5730 : c->status = dcerpc_alter_context_recv(subreq);
277 5730 : TALLOC_FREE(subreq);
278 5730 : if (!composite_is_ok(c)) return;
279 :
280 5730 : bind_auth_next_step(c);
281 : }
282 :
283 :
284 8735 : static void bind_auth_recv_bindreply(struct tevent_req *subreq)
285 : {
286 430 : struct composite_context *c =
287 8735 : tevent_req_callback_data(subreq,
288 : struct composite_context);
289 8735 : struct bind_auth_state *state = talloc_get_type(c->private_data,
290 : struct bind_auth_state);
291 8735 : struct dcecli_security *sec = &state->pipe->conn->security_state;
292 :
293 8735 : ZERO_STRUCT(sec->tmp_auth_info);
294 :
295 8735 : c->status = dcerpc_bind_recv(subreq);
296 8735 : TALLOC_FREE(subreq);
297 8735 : if (!composite_is_ok(c)) return;
298 :
299 8704 : 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 8704 : 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 8759 : 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 430 : struct composite_context *c;
333 430 : struct bind_auth_state *state;
334 430 : struct dcecli_security *sec;
335 430 : struct tevent_req *subreq;
336 8759 : const char *target_principal = NULL;
337 :
338 : /* composite context allocation and setup */
339 8759 : c = composite_create(mem_ctx, p->conn->event_ctx);
340 8759 : if (c == NULL) return NULL;
341 :
342 8759 : state = talloc(c, struct bind_auth_state);
343 8759 : if (composite_nomem(state, c)) return c;
344 8759 : c->private_data = state;
345 :
346 8759 : state->pipe = p;
347 :
348 8759 : c->status = dcerpc_init_syntaxes(p, table,
349 : &state->syntax,
350 : &state->transfer_syntax);
351 8759 : if (!composite_is_ok(c)) return c;
352 :
353 8759 : sec = &p->conn->security_state;
354 :
355 8759 : c->status = gensec_client_start(p, &sec->generic_state,
356 : gensec_settings);
357 8759 : 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 8759 : c->status = gensec_set_credentials(sec->generic_state, credentials);
365 8759 : 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 8759 : c->status = gensec_set_target_hostname(sec->generic_state,
373 : dcerpc_server_name(p));
374 8759 : 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 8759 : if (service != NULL) {
382 8258 : c->status = gensec_set_target_service(sec->generic_state,
383 : service);
384 8258 : 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 8759 : if (p->binding != NULL) {
393 8759 : target_principal = dcerpc_binding_get_string_option(p->binding,
394 : "target_principal");
395 : }
396 8759 : if (target_principal != NULL) {
397 209 : c->status = gensec_set_target_principal(sec->generic_state,
398 : target_principal);
399 209 : 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 8759 : c->status = gensec_start_mech_by_authtype(sec->generic_state,
408 : auth_type, auth_level);
409 8759 : if (!NT_STATUS_IS_OK(c->status)) {
410 24 : 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 24 : composite_error(c, c->status);
414 24 : return c;
415 : }
416 :
417 8735 : sec->auth_type = auth_type;
418 8735 : 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 8735 : sec->auth_context_id = 1;
425 :
426 8735 : state->out_auth_info = (struct dcerpc_auth) {
427 8305 : .auth_type = sec->auth_type,
428 8305 : .auth_level = sec->auth_level,
429 8305 : .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 mutual 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 8735 : state->pipe->inhibit_timeout_processing = true;
443 8735 : state->pipe->timed_out = false;
444 :
445 9165 : subreq = gensec_update_send(state,
446 8735 : p->conn->event_ctx,
447 : sec->generic_state,
448 : data_blob_null);
449 8735 : if (composite_nomem(subreq, c)) return c;
450 8735 : tevent_req_set_callback(subreq, dcerpc_bind_auth_gensec_done, c);
451 :
452 8735 : return c;
453 : }
454 :
455 8735 : static void dcerpc_bind_auth_gensec_done(struct tevent_req *subreq)
456 : {
457 430 : struct composite_context *c =
458 8735 : tevent_req_callback_data(subreq,
459 : struct composite_context);
460 430 : struct bind_auth_state *state =
461 8735 : talloc_get_type_abort(c->private_data,
462 : struct bind_auth_state);
463 8735 : struct dcerpc_pipe *p = state->pipe;
464 8735 : struct dcecli_security *sec = &p->conn->security_state;
465 :
466 8735 : state->pipe->inhibit_timeout_processing = false;
467 :
468 8735 : c->status = gensec_update_recv(subreq, state,
469 : &state->out_auth_info.credentials);
470 8735 : TALLOC_FREE(subreq);
471 8735 : if (!NT_STATUS_IS_OK(c->status) &&
472 8305 : !NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
473 0 : composite_error(c, c->status);
474 0 : return;
475 : }
476 :
477 8735 : state->more_processing = NT_STATUS_EQUAL(c->status,
478 : NT_STATUS_MORE_PROCESSING_REQUIRED);
479 :
480 8735 : if (state->out_auth_info.credentials.length == 0) {
481 0 : composite_done(c);
482 0 : return;
483 : }
484 :
485 8735 : if (gensec_have_feature(sec->generic_state, GENSEC_FEATURE_SIGN_PKT_HEADER)) {
486 8295 : if (sec->auth_level >= DCERPC_AUTH_LEVEL_PACKET) {
487 8259 : state->pipe->conn->flags |= DCERPC_PROPOSE_HEADER_SIGNING;
488 : }
489 : }
490 :
491 8735 : state->in_auth_info = (struct dcerpc_auth) {
492 : .auth_type = DCERPC_AUTH_TYPE_NONE,
493 : };
494 8735 : sec->tmp_auth_info.in = &state->in_auth_info;
495 8735 : sec->tmp_auth_info.mem = state;
496 8735 : 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 9165 : subreq = dcerpc_bind_send(state, p->conn->event_ctx, p,
501 8735 : &state->syntax, &state->transfer_syntax);
502 8735 : if (composite_nomem(subreq, c)) return;
503 8735 : tevent_req_set_callback(subreq, bind_auth_recv_bindreply, c);
504 :
505 8735 : 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 8759 : NTSTATUS dcerpc_bind_auth_recv(struct composite_context *creq)
516 : {
517 8759 : NTSTATUS result = composite_wait(creq);
518 8759 : struct bind_auth_state *state = talloc_get_type(creq->private_data,
519 : struct bind_auth_state);
520 :
521 8759 : 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 8704 : state->pipe->conn->security_state.session_key = dcecli_generic_session_key;
527 : }
528 :
529 8759 : talloc_free(creq);
530 8759 : 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 32 : _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 0 : struct composite_context *creq;
553 32 : creq = dcerpc_bind_auth_send(p, p, table, credentials, gensec_settings,
554 : auth_type, auth_level, service);
555 32 : return dcerpc_bind_auth_recv(creq);
556 : }
|