2 Unix SMB/CIFS implementation.
4 Generic Authentication Interface
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
8 Copyright (C) Stefan Metzmacher 2004
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/>.
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"
33 return the rpc syntax and transfer syntax given the pipe uuid and version
35 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
)
40 struct GUID
*object
= NULL
;
42 p
->object
= dcerpc_binding_get_object(p
->binding
);
43 if (!GUID_all_zero(&p
->object
)) {
47 p
->binding_handle
= dcerpc_pipe_binding_handle(p
, object
, table
);
48 if (p
->binding_handle
== NULL
) {
49 return NT_STATUS_NO_MEMORY
;
52 syntax
->uuid
= table
->syntax_id
.uuid
;
53 syntax
->if_version
= table
->syntax_id
.if_version
;
55 if (p
->conn
->flags
& DCERPC_NDR64
) {
56 *transfer_syntax
= ndr_transfer_syntax_ndr64
;
58 *transfer_syntax
= ndr_transfer_syntax_ndr
;
66 Send request to do a non-authenticated dcerpc bind
68 static void dcerpc_bind_auth_none_done(struct tevent_req
*subreq
);
70 struct composite_context
*dcerpc_bind_auth_none_send(TALLOC_CTX
*mem_ctx
,
71 struct dcerpc_pipe
*p
,
72 const struct ndr_interface_table
*table
)
74 struct ndr_syntax_id syntax
;
75 struct ndr_syntax_id transfer_syntax
;
77 struct composite_context
*c
;
78 struct tevent_req
*subreq
;
80 c
= composite_create(mem_ctx
, p
->conn
->event_ctx
);
81 if (c
== NULL
) return NULL
;
83 c
->status
= dcerpc_init_syntaxes(p
, table
,
84 &syntax
, &transfer_syntax
);
85 if (!NT_STATUS_IS_OK(c
->status
)) {
86 DEBUG(2,("Invalid uuid string in "
87 "dcerpc_bind_auth_none_send\n"));
88 composite_error(c
, c
->status
);
92 subreq
= dcerpc_bind_send(mem_ctx
, p
->conn
->event_ctx
, p
,
93 &syntax
, &transfer_syntax
);
94 if (composite_nomem(subreq
, c
)) return c
;
95 tevent_req_set_callback(subreq
, dcerpc_bind_auth_none_done
, c
);
100 static void dcerpc_bind_auth_none_done(struct tevent_req
*subreq
)
102 struct composite_context
*ctx
=
103 tevent_req_callback_data(subreq
,
104 struct composite_context
);
106 ctx
->status
= dcerpc_bind_recv(subreq
);
108 if (!composite_is_ok(ctx
)) return;
114 Receive result of a non-authenticated dcerpc bind
116 NTSTATUS
dcerpc_bind_auth_none_recv(struct composite_context
*ctx
)
118 NTSTATUS result
= composite_wait(ctx
);
125 Perform sync non-authenticated dcerpc bind
127 _PUBLIC_ NTSTATUS
dcerpc_bind_auth_none(struct dcerpc_pipe
*p
,
128 const struct ndr_interface_table
*table
)
130 struct composite_context
*ctx
;
132 ctx
= dcerpc_bind_auth_none_send(p
, p
, table
);
133 return dcerpc_bind_auth_none_recv(ctx
);
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? */
147 static void bind_auth_next_gensec_done(struct tevent_req
*subreq
);
148 static void bind_auth_recv_alter(struct tevent_req
*subreq
);
150 static void bind_auth_next_step(struct composite_context
*c
)
152 struct bind_auth_state
*state
;
153 struct dcecli_security
*sec
;
154 struct tevent_req
*subreq
;
156 state
= talloc_get_type(c
->private_data
, struct bind_auth_state
);
157 sec
= &state
->pipe
->conn
->security_state
;
159 if (state
->in_auth_info
.auth_type
!= sec
->auth_type
) {
160 composite_error(c
, NT_STATUS_RPC_PROTOCOL_ERROR
);
164 if (state
->in_auth_info
.auth_level
!= sec
->auth_level
) {
165 composite_error(c
, NT_STATUS_RPC_PROTOCOL_ERROR
);
169 if (state
->in_auth_info
.auth_context_id
!= sec
->auth_context_id
) {
170 composite_error(c
, NT_STATUS_RPC_PROTOCOL_ERROR
);
174 state
->out_auth_info
= (struct dcerpc_auth
) {
175 .auth_type
= sec
->auth_type
,
176 .auth_level
= sec
->auth_level
,
177 .auth_context_id
= sec
->auth_context_id
,
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.
186 * Likewise, you must not feed GENSEC too much (after the OK),
187 * it doesn't like that either
190 state
->pipe
->inhibit_timeout_processing
= true;
191 state
->pipe
->timed_out
= false;
193 subreq
= gensec_update_send(state
,
194 state
->pipe
->conn
->event_ctx
,
196 state
->in_auth_info
.credentials
);
197 if (composite_nomem(subreq
, c
)) return;
198 tevent_req_set_callback(subreq
, bind_auth_next_gensec_done
, c
);
201 static void bind_auth_next_gensec_done(struct tevent_req
*subreq
)
203 struct composite_context
*c
=
204 tevent_req_callback_data(subreq
,
205 struct composite_context
);
206 struct bind_auth_state
*state
=
207 talloc_get_type_abort(c
->private_data
,
208 struct bind_auth_state
);
209 struct dcerpc_pipe
*p
= state
->pipe
;
210 struct dcecli_security
*sec
= &p
->conn
->security_state
;
211 bool more_processing
= false;
213 state
->pipe
->inhibit_timeout_processing
= false;
215 c
->status
= gensec_update_recv(subreq
, state
,
216 &state
->out_auth_info
.credentials
);
219 if (NT_STATUS_EQUAL(c
->status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
220 more_processing
= true;
221 c
->status
= NT_STATUS_OK
;
224 if (!composite_is_ok(c
)) return;
226 if (!more_processing
) {
227 if (state
->pipe
->conn
->flags
& DCERPC_HEADER_SIGNING
) {
228 gensec_want_feature(sec
->generic_state
,
229 GENSEC_FEATURE_SIGN_PKT_HEADER
);
233 if (state
->out_auth_info
.credentials
.length
== 0) {
238 state
->in_auth_info
= (struct dcerpc_auth
) {
239 .auth_type
= DCERPC_AUTH_TYPE_NONE
,
241 sec
->tmp_auth_info
.in
= &state
->in_auth_info
;
242 sec
->tmp_auth_info
.mem
= state
;
243 sec
->tmp_auth_info
.out
= &state
->out_auth_info
;
245 if (!more_processing
) {
246 /* NO reply expected, so just send it */
247 c
->status
= dcerpc_auth3(state
->pipe
, state
);
248 if (!composite_is_ok(c
)) return;
254 /* We are demanding a reply, so use a request that will get us one */
256 subreq
= dcerpc_alter_context_send(state
, state
->pipe
->conn
->event_ctx
,
258 &state
->pipe
->syntax
,
259 &state
->pipe
->transfer_syntax
);
260 if (composite_nomem(subreq
, c
)) return;
261 tevent_req_set_callback(subreq
, bind_auth_recv_alter
, c
);
265 static void bind_auth_recv_alter(struct tevent_req
*subreq
)
267 struct composite_context
*c
=
268 tevent_req_callback_data(subreq
,
269 struct composite_context
);
270 struct bind_auth_state
*state
= talloc_get_type(c
->private_data
,
271 struct bind_auth_state
);
272 struct dcecli_security
*sec
= &state
->pipe
->conn
->security_state
;
274 ZERO_STRUCT(sec
->tmp_auth_info
);
276 c
->status
= dcerpc_alter_context_recv(subreq
);
278 if (!composite_is_ok(c
)) return;
280 bind_auth_next_step(c
);
284 static void bind_auth_recv_bindreply(struct tevent_req
*subreq
)
286 struct composite_context
*c
=
287 tevent_req_callback_data(subreq
,
288 struct composite_context
);
289 struct bind_auth_state
*state
= talloc_get_type(c
->private_data
,
290 struct bind_auth_state
);
291 struct dcecli_security
*sec
= &state
->pipe
->conn
->security_state
;
293 ZERO_STRUCT(sec
->tmp_auth_info
);
295 c
->status
= dcerpc_bind_recv(subreq
);
297 if (!composite_is_ok(c
)) return;
299 if (!state
->more_processing
) {
300 /* The first gensec_update has not requested a second run, so
301 * we're done here. */
306 bind_auth_next_step(c
);
310 static void dcerpc_bind_auth_gensec_done(struct tevent_req
*subreq
);
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
324 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
,
332 struct composite_context
*c
;
333 struct bind_auth_state
*state
;
334 struct dcecli_security
*sec
;
335 struct tevent_req
*subreq
;
336 const char *target_principal
= NULL
;
338 /* composite context allocation and setup */
339 c
= composite_create(mem_ctx
, p
->conn
->event_ctx
);
340 if (c
== NULL
) return NULL
;
342 state
= talloc(c
, struct bind_auth_state
);
343 if (composite_nomem(state
, c
)) return c
;
344 c
->private_data
= state
;
348 c
->status
= dcerpc_init_syntaxes(p
, table
,
350 &state
->transfer_syntax
);
351 if (!composite_is_ok(c
)) return c
;
353 sec
= &p
->conn
->security_state
;
355 c
->status
= gensec_client_start(p
, &sec
->generic_state
,
357 if (!NT_STATUS_IS_OK(c
->status
)) {
358 DEBUG(1, ("Failed to start GENSEC client mode: %s\n",
359 nt_errstr(c
->status
)));
360 composite_error(c
, c
->status
);
364 c
->status
= gensec_set_credentials(sec
->generic_state
, credentials
);
365 if (!NT_STATUS_IS_OK(c
->status
)) {
366 DEBUG(1, ("Failed to set GENSEC client credentials: %s\n",
367 nt_errstr(c
->status
)));
368 composite_error(c
, c
->status
);
372 c
->status
= gensec_set_target_hostname(sec
->generic_state
,
373 dcerpc_server_name(p
));
374 if (!NT_STATUS_IS_OK(c
->status
)) {
375 DEBUG(1, ("Failed to set GENSEC target hostname: %s\n",
376 nt_errstr(c
->status
)));
377 composite_error(c
, c
->status
);
381 if (service
!= NULL
) {
382 c
->status
= gensec_set_target_service(sec
->generic_state
,
384 if (!NT_STATUS_IS_OK(c
->status
)) {
385 DEBUG(1, ("Failed to set GENSEC target service: %s\n",
386 nt_errstr(c
->status
)));
387 composite_error(c
, c
->status
);
392 if (p
->binding
!= NULL
) {
393 target_principal
= dcerpc_binding_get_string_option(p
->binding
,
396 if (target_principal
!= NULL
) {
397 c
->status
= gensec_set_target_principal(sec
->generic_state
,
399 if (!NT_STATUS_IS_OK(c
->status
)) {
400 DEBUG(1, ("Failed to set GENSEC target principal to %s: %s\n",
401 target_principal
, nt_errstr(c
->status
)));
402 composite_error(c
, c
->status
);
407 c
->status
= gensec_start_mech_by_authtype(sec
->generic_state
,
408 auth_type
, auth_level
);
409 if (!NT_STATUS_IS_OK(c
->status
)) {
410 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 composite_error(c
, c
->status
);
417 sec
->auth_type
= auth_type
;
418 sec
->auth_level
= auth_level
,
420 * We use auth_context_id = 1 as some older
421 * Samba versions (<= 4.2.3) use that value hardcoded
424 sec
->auth_context_id
= 1;
426 state
->out_auth_info
= (struct dcerpc_auth
) {
427 .auth_type
= sec
->auth_type
,
428 .auth_level
= sec
->auth_level
,
429 .auth_context_id
= sec
->auth_context_id
,
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.
438 * Likewise, you must not feed GENSEC too much (after the OK),
439 * it doesn't like that either
442 state
->pipe
->inhibit_timeout_processing
= true;
443 state
->pipe
->timed_out
= false;
445 subreq
= gensec_update_send(state
,
449 if (composite_nomem(subreq
, c
)) return c
;
450 tevent_req_set_callback(subreq
, dcerpc_bind_auth_gensec_done
, c
);
455 static void dcerpc_bind_auth_gensec_done(struct tevent_req
*subreq
)
457 struct composite_context
*c
=
458 tevent_req_callback_data(subreq
,
459 struct composite_context
);
460 struct bind_auth_state
*state
=
461 talloc_get_type_abort(c
->private_data
,
462 struct bind_auth_state
);
463 struct dcerpc_pipe
*p
= state
->pipe
;
464 struct dcecli_security
*sec
= &p
->conn
->security_state
;
466 state
->pipe
->inhibit_timeout_processing
= false;
468 c
->status
= gensec_update_recv(subreq
, state
,
469 &state
->out_auth_info
.credentials
);
471 if (!NT_STATUS_IS_OK(c
->status
) &&
472 !NT_STATUS_EQUAL(c
->status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
473 composite_error(c
, c
->status
);
477 state
->more_processing
= NT_STATUS_EQUAL(c
->status
,
478 NT_STATUS_MORE_PROCESSING_REQUIRED
);
480 if (state
->out_auth_info
.credentials
.length
== 0) {
485 if (gensec_have_feature(sec
->generic_state
, GENSEC_FEATURE_SIGN_PKT_HEADER
)) {
486 if (sec
->auth_level
>= DCERPC_AUTH_LEVEL_PACKET
) {
487 state
->pipe
->conn
->flags
|= DCERPC_PROPOSE_HEADER_SIGNING
;
491 state
->in_auth_info
= (struct dcerpc_auth
) {
492 .auth_type
= DCERPC_AUTH_TYPE_NONE
,
494 sec
->tmp_auth_info
.in
= &state
->in_auth_info
;
495 sec
->tmp_auth_info
.mem
= state
;
496 sec
->tmp_auth_info
.out
= &state
->out_auth_info
;
498 /* The first request always is a dcerpc_bind. The subsequent ones
499 * depend on gensec results */
500 subreq
= dcerpc_bind_send(state
, p
->conn
->event_ctx
, p
,
501 &state
->syntax
, &state
->transfer_syntax
);
502 if (composite_nomem(subreq
, c
)) return;
503 tevent_req_set_callback(subreq
, bind_auth_recv_bindreply
, c
);
510 Bind to a DCE/RPC pipe, receive result
511 @param creq A composite context describing state of async call
512 @retval NTSTATUS code
515 NTSTATUS
dcerpc_bind_auth_recv(struct composite_context
*creq
)
517 NTSTATUS result
= composite_wait(creq
);
518 struct bind_auth_state
*state
= talloc_get_type(creq
->private_data
,
519 struct bind_auth_state
);
521 if (NT_STATUS_IS_OK(result
)) {
523 after a successful authenticated bind the session
524 key reverts to the generic session key
526 state
->pipe
->conn
->security_state
.session_key
= dcecli_generic_session_key
;
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
545 _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
,
552 struct composite_context
*creq
;
553 creq
= dcerpc_bind_auth_send(p
, p
, table
, credentials
, gensec_settings
,
554 auth_type
, auth_level
, service
);
555 return dcerpc_bind_auth_recv(creq
);