2 Unix SMB/CIFS implementation.
4 dcerpc utility functions
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Jelmer Vernooij 2004
8 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
9 Copyright (C) Rafal Szczesniak 2006
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include "lib/events/events.h"
27 #include "libcli/composite/composite.h"
28 #include "librpc/gen_ndr/ndr_epmapper_c.h"
29 #include "librpc/gen_ndr/ndr_dcerpc.h"
30 #include "librpc/gen_ndr/ndr_misc.h"
31 #include "librpc/rpc/dcerpc_proto.h"
32 #include "auth/credentials/credentials.h"
33 #include "auth/gensec/gensec.h"
34 #include "param/param.h"
35 #include "librpc/rpc/rpc_common.h"
38 find a dcerpc call on an interface by name
40 const struct ndr_interface_call
*dcerpc_iface_find_call(const struct ndr_interface_table
*iface
,
44 for (i
=0;i
<iface
->num_calls
;i
++) {
45 if (strcmp(iface
->calls
[i
].name
, name
) == 0) {
46 return &iface
->calls
[i
];
53 push a ncacn_packet into a blob, potentially with auth info
55 NTSTATUS
ncacn_push_auth(DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
,
56 struct ncacn_packet
*pkt
,
57 struct dcerpc_auth
*auth_info
)
60 enum ndr_err_code ndr_err
;
62 ndr
= ndr_push_init_ctx(mem_ctx
);
64 return NT_STATUS_NO_MEMORY
;
67 if (!(pkt
->drep
[0] & DCERPC_DREP_LE
)) {
68 ndr
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
71 if (pkt
->pfc_flags
& DCERPC_PFC_FLAG_OBJECT_UUID
) {
72 ndr
->flags
|= LIBNDR_FLAG_OBJECT_PRESENT
;
76 pkt
->auth_length
= auth_info
->credentials
.length
;
81 ndr_err
= ndr_push_ncacn_packet(ndr
, NDR_SCALARS
|NDR_BUFFERS
, pkt
);
82 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
83 return ndr_map_error2ntstatus(ndr_err
);
88 /* the s3 rpc server doesn't handle auth padding in
89 bind requests. Use zero auth padding to keep us
90 working with old servers */
91 uint32_t offset
= ndr
->offset
;
92 ndr_err
= ndr_push_align(ndr
, 16);
93 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
94 return ndr_map_error2ntstatus(ndr_err
);
96 auth_info
->auth_pad_length
= ndr
->offset
- offset
;
98 auth_info
->auth_pad_length
= 0;
100 ndr_err
= ndr_push_dcerpc_auth(ndr
, NDR_SCALARS
|NDR_BUFFERS
, auth_info
);
101 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
102 return ndr_map_error2ntstatus(ndr_err
);
106 *blob
= ndr_push_blob(ndr
);
108 /* fill in the frag length */
109 dcerpc_set_frag_length(blob
, blob
->length
);
115 struct epm_map_binding_state
{
116 struct dcerpc_binding
*binding
;
117 const struct ndr_interface_table
*table
;
118 struct dcerpc_pipe
*pipe
;
119 struct policy_handle handle
;
121 struct epm_twr_t twr
;
122 struct epm_twr_t
*twr_r
;
128 static void continue_epm_recv_binding(struct composite_context
*ctx
);
129 static void continue_epm_map(struct tevent_req
*subreq
);
133 Stage 2 of epm_map_binding: Receive connected rpc pipe and send endpoint
136 static void continue_epm_recv_binding(struct composite_context
*ctx
)
138 struct composite_context
*c
= talloc_get_type(ctx
->async
.private_data
,
139 struct composite_context
);
140 struct epm_map_binding_state
*s
= talloc_get_type(c
->private_data
,
141 struct epm_map_binding_state
);
142 struct tevent_req
*subreq
;
144 /* receive result of rpc pipe connect request */
145 c
->status
= dcerpc_pipe_connect_b_recv(ctx
, c
, &s
->pipe
);
146 if (!composite_is_ok(c
)) return;
148 c
->status
= dcerpc_binding_build_tower(s
->pipe
, s
->binding
, &s
->twr
.tower
);
149 if (!composite_is_ok(c
)) return;
151 /* with some nice pretty paper around it of course */
152 s
->r
.in
.object
= &s
->object
;
153 s
->r
.in
.map_tower
= &s
->twr
;
154 s
->r
.in
.entry_handle
= &s
->handle
;
155 s
->r
.in
.max_towers
= 1;
156 s
->r
.out
.entry_handle
= &s
->handle
;
157 s
->r
.out
.num_towers
= &s
->num_towers
;
159 /* send request for an endpoint mapping - a rpc request on connected pipe */
160 subreq
= dcerpc_epm_Map_r_send(s
, c
->event_ctx
,
161 s
->pipe
->binding_handle
,
163 if (composite_nomem(subreq
, c
)) return;
165 tevent_req_set_callback(subreq
, continue_epm_map
, c
);
170 Stage 3 of epm_map_binding: Receive endpoint mapping and provide binding details
172 static void continue_epm_map(struct tevent_req
*subreq
)
174 struct composite_context
*c
= tevent_req_callback_data(subreq
,
175 struct composite_context
);
176 struct epm_map_binding_state
*s
= talloc_get_type(c
->private_data
,
177 struct epm_map_binding_state
);
178 const char *endpoint
;
180 /* receive result of a rpc request */
181 c
->status
= dcerpc_epm_Map_r_recv(subreq
, s
);
183 if (!composite_is_ok(c
)) return;
185 /* check the details */
186 if (s
->r
.out
.result
!= 0 || *s
->r
.out
.num_towers
!= 1) {
187 composite_error(c
, NT_STATUS_PORT_UNREACHABLE
);
191 s
->twr_r
= s
->r
.out
.towers
[0].twr
;
192 if (s
->twr_r
== NULL
) {
193 composite_error(c
, NT_STATUS_PORT_UNREACHABLE
);
197 if (s
->twr_r
->tower
.num_floors
!= s
->twr
.tower
.num_floors
||
198 s
->twr_r
->tower
.floors
[3].lhs
.protocol
!= s
->twr
.tower
.floors
[3].lhs
.protocol
) {
199 composite_error(c
, NT_STATUS_PORT_UNREACHABLE
);
203 /* get received endpoint */
204 endpoint
= dcerpc_floor_get_rhs_data(s
, &s
->twr_r
->tower
.floors
[3]);
205 if (composite_nomem(endpoint
, c
)) return;
207 c
->status
= dcerpc_binding_set_string_option(s
->binding
,
210 if (!composite_is_ok(c
)) {
219 Request for endpoint mapping of dcerpc binding - try to request for endpoint
220 unless there is default one.
222 struct composite_context
*dcerpc_epm_map_binding_send(TALLOC_CTX
*mem_ctx
,
223 struct dcerpc_binding
*binding
,
224 const struct ndr_interface_table
*table
,
225 struct cli_credentials
*creds
,
226 struct tevent_context
*ev
,
227 struct loadparm_context
*lp_ctx
)
229 struct composite_context
*c
;
230 struct epm_map_binding_state
*s
;
231 struct composite_context
*pipe_connect_req
;
233 struct dcerpc_binding
*epmapper_binding
;
240 /* composite context allocation and setup */
241 c
= composite_create(mem_ctx
, ev
);
246 s
= talloc_zero(c
, struct epm_map_binding_state
);
247 if (composite_nomem(s
, c
)) return c
;
250 s
->binding
= binding
;
251 s
->object
= dcerpc_binding_get_object(binding
);
254 c
->status
= dcerpc_binding_set_abstract_syntax(binding
,
256 if (!composite_is_ok(c
)) {
261 First, check if there is a default endpoint specified in the IDL
263 for (i
= 0; i
< table
->endpoints
->count
; i
++) {
264 struct dcerpc_binding
*default_binding
;
265 enum dcerpc_transport_t transport
;
266 enum dcerpc_transport_t dtransport
;
267 const char *dendpoint
= NULL
;
269 status
= dcerpc_parse_binding(s
,
270 table
->endpoints
->names
[i
],
272 if (!NT_STATUS_IS_OK(status
)) {
276 transport
= dcerpc_binding_get_transport(binding
);
277 dtransport
= dcerpc_binding_get_transport(default_binding
);
278 if (transport
== NCA_UNKNOWN
) {
279 c
->status
= dcerpc_binding_set_transport(binding
,
281 if (!composite_is_ok(c
)) {
284 transport
= dtransport
;
287 if (transport
!= dtransport
) {
288 TALLOC_FREE(default_binding
);
292 dendpoint
= dcerpc_binding_get_string_option(default_binding
,
294 if (dendpoint
== NULL
) {
295 TALLOC_FREE(default_binding
);
299 c
->status
= dcerpc_binding_set_string_option(binding
,
302 if (!composite_is_ok(c
)) {
306 TALLOC_FREE(default_binding
);
311 epmapper_binding
= dcerpc_binding_dup(s
, binding
);
312 if (composite_nomem(epmapper_binding
, c
)) return c
;
314 /* basic endpoint mapping data */
315 c
->status
= dcerpc_binding_set_string_option(epmapper_binding
,
317 if (!composite_is_ok(c
)) {
320 c
->status
= dcerpc_binding_set_flags(epmapper_binding
, 0, UINT32_MAX
);
321 if (!composite_is_ok(c
)) {
324 c
->status
= dcerpc_binding_set_assoc_group_id(epmapper_binding
, 0);
325 if (!composite_is_ok(c
)) {
328 c
->status
= dcerpc_binding_set_object(epmapper_binding
, GUID_zero());
329 if (!composite_is_ok(c
)) {
333 /* initiate rpc pipe connection */
334 pipe_connect_req
= dcerpc_pipe_connect_b_send(s
, epmapper_binding
,
338 if (composite_nomem(pipe_connect_req
, c
)) return c
;
340 composite_continue(c
, pipe_connect_req
, continue_epm_recv_binding
, c
);
346 Receive result of endpoint mapping request
348 NTSTATUS
dcerpc_epm_map_binding_recv(struct composite_context
*c
)
350 NTSTATUS status
= composite_wait(c
);
358 Get endpoint mapping for rpc connection
360 _PUBLIC_ NTSTATUS
dcerpc_epm_map_binding(TALLOC_CTX
*mem_ctx
, struct dcerpc_binding
*binding
,
361 const struct ndr_interface_table
*table
, struct tevent_context
*ev
,
362 struct loadparm_context
*lp_ctx
)
364 struct composite_context
*c
;
365 struct cli_credentials
*epm_creds
;
367 epm_creds
= cli_credentials_init_anon(mem_ctx
);
368 if (epm_creds
== NULL
) {
369 return NT_STATUS_NO_MEMORY
;
371 c
= dcerpc_epm_map_binding_send(mem_ctx
, binding
, table
, epm_creds
, ev
, lp_ctx
);
373 talloc_free(epm_creds
);
374 return NT_STATUS_NO_MEMORY
;
376 talloc_steal(c
, epm_creds
);
377 return dcerpc_epm_map_binding_recv(c
);
381 struct pipe_auth_state
{
382 struct dcerpc_pipe
*pipe
;
383 const struct dcerpc_binding
*binding
;
384 const struct ndr_interface_table
*table
;
385 struct loadparm_context
*lp_ctx
;
386 struct cli_credentials
*credentials
;
387 unsigned int logon_retries
;
391 static void continue_auth_schannel(struct composite_context
*ctx
);
392 static void continue_auth(struct composite_context
*ctx
);
393 static void continue_auth_none(struct composite_context
*ctx
);
394 static void continue_ntlmssp_connection(struct composite_context
*ctx
);
395 static void continue_spnego_after_wrong_pass(struct composite_context
*ctx
);
399 Stage 2 of pipe_auth: Receive result of schannel bind request
401 static void continue_auth_schannel(struct composite_context
*ctx
)
403 struct composite_context
*c
= talloc_get_type(ctx
->async
.private_data
,
404 struct composite_context
);
406 c
->status
= dcerpc_bind_auth_schannel_recv(ctx
);
407 if (!composite_is_ok(c
)) return;
414 Stage 2 of pipe_auth: Receive result of authenticated bind request
416 static void continue_auth(struct composite_context
*ctx
)
418 struct composite_context
*c
= talloc_get_type(ctx
->async
.private_data
,
419 struct composite_context
);
421 c
->status
= dcerpc_bind_auth_recv(ctx
);
422 if (!composite_is_ok(c
)) return;
427 Stage 2 of pipe_auth: Receive result of authenticated bind request, but handle fallbacks:
430 static void continue_auth_auto(struct composite_context
*ctx
)
432 struct composite_context
*c
= talloc_get_type(ctx
->async
.private_data
,
433 struct composite_context
);
434 struct pipe_auth_state
*s
= talloc_get_type(c
->private_data
, struct pipe_auth_state
);
435 struct composite_context
*sec_conn_req
;
437 c
->status
= dcerpc_bind_auth_recv(ctx
);
438 if (NT_STATUS_EQUAL(c
->status
, NT_STATUS_INVALID_PARAMETER
)) {
440 * Retry with NTLMSSP auth as fallback
441 * send a request for secondary rpc connection
443 sec_conn_req
= dcerpc_secondary_connection_send(s
->pipe
,
445 composite_continue(c
, sec_conn_req
, continue_ntlmssp_connection
, c
);
447 } else if (NT_STATUS_EQUAL(c
->status
, NT_STATUS_LOGON_FAILURE
) ||
448 NT_STATUS_EQUAL(c
->status
, NT_STATUS_UNSUCCESSFUL
)) {
450 try a second time on any error. We don't just do it
451 on LOGON_FAILURE as some servers will give a
452 NT_STATUS_UNSUCCESSFUL on a authentication error on RPC
454 const char *principal
;
455 const char *endpoint
;
457 principal
= gensec_get_target_principal(s
->pipe
->conn
->security_state
.generic_state
);
458 if (principal
== NULL
) {
459 const char *hostname
= gensec_get_target_hostname(s
->pipe
->conn
->security_state
.generic_state
);
460 const char *service
= gensec_get_target_service(s
->pipe
->conn
->security_state
.generic_state
);
461 if (hostname
!= NULL
&& service
!= NULL
) {
462 principal
= talloc_asprintf(c
, "%s/%s", service
, hostname
);
466 endpoint
= dcerpc_binding_get_string_option(s
->binding
, "endpoint");
468 if ((cli_credentials_failed_kerberos_login(s
->credentials
, principal
, &s
->logon_retries
) ||
469 cli_credentials_wrong_password(s
->credentials
)) &&
472 * Retry SPNEGO with a better password
473 * send a request for secondary rpc connection
475 sec_conn_req
= dcerpc_secondary_connection_send(s
->pipe
,
477 composite_continue(c
, sec_conn_req
, continue_spnego_after_wrong_pass
, c
);
482 if (!composite_is_ok(c
)) return;
488 Stage 3 of pipe_auth (fallback to NTLMSSP case): Receive secondary
489 rpc connection (the first one can't be used any more, due to the
490 bind nak) and perform authenticated bind request
492 static void continue_ntlmssp_connection(struct composite_context
*ctx
)
494 struct composite_context
*c
;
495 struct pipe_auth_state
*s
;
496 struct composite_context
*auth_req
;
497 struct dcerpc_pipe
*p2
;
500 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
501 s
= talloc_get_type(c
->private_data
, struct pipe_auth_state
);
503 /* receive secondary rpc connection */
504 c
->status
= dcerpc_secondary_connection_recv(ctx
, &p2
);
505 if (!composite_is_ok(c
)) return;
508 /* this is a rather strange situation. When
509 we come into the routine, s is a child of s->pipe, and
510 when we created p2 above, it also became a child of
513 Now we want p2 to be a parent of s->pipe, and we want s to
514 be a parent of both of them! If we don't do this very
515 carefully we end up creating a talloc loop
518 /* we need the new contexts to hang off the same context
519 that s->pipe is on, but the only way to get that is
520 via talloc_parent() */
521 pp
= talloc_parent(s
->pipe
);
523 /* promote s to be at the top */
526 /* and put p2 under s */
529 /* now put s->pipe under p2 */
530 talloc_steal(p2
, s
->pipe
);
534 /* initiate a authenticated bind */
535 auth_req
= dcerpc_bind_auth_send(c
, s
->pipe
, s
->table
,
537 lpcfg_gensec_settings(c
, s
->lp_ctx
),
538 DCERPC_AUTH_TYPE_NTLMSSP
,
539 dcerpc_auth_level(s
->pipe
->conn
),
540 s
->table
->authservices
->names
[0]);
541 composite_continue(c
, auth_req
, continue_auth
, c
);
545 Stage 3 of pipe_auth (retry on wrong password): Receive secondary
546 rpc connection (the first one can't be used any more, due to the
547 bind nak) and perform authenticated bind request
549 static void continue_spnego_after_wrong_pass(struct composite_context
*ctx
)
551 struct composite_context
*c
;
552 struct pipe_auth_state
*s
;
553 struct composite_context
*auth_req
;
554 struct dcerpc_pipe
*p2
;
556 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
557 s
= talloc_get_type(c
->private_data
, struct pipe_auth_state
);
559 /* receive secondary rpc connection */
560 c
->status
= dcerpc_secondary_connection_recv(ctx
, &p2
);
561 if (!composite_is_ok(c
)) return;
564 talloc_steal(p2
, s
->pipe
);
567 /* initiate a authenticated bind */
568 auth_req
= dcerpc_bind_auth_send(c
, s
->pipe
, s
->table
,
570 lpcfg_gensec_settings(c
, s
->lp_ctx
),
571 DCERPC_AUTH_TYPE_SPNEGO
,
572 dcerpc_auth_level(s
->pipe
->conn
),
573 s
->table
->authservices
->names
[0]);
574 composite_continue(c
, auth_req
, continue_auth
, c
);
579 Stage 2 of pipe_auth: Receive result of non-authenticated bind request
581 static void continue_auth_none(struct composite_context
*ctx
)
583 struct composite_context
*c
= talloc_get_type(ctx
->async
.private_data
,
584 struct composite_context
);
586 c
->status
= dcerpc_bind_auth_none_recv(ctx
);
587 if (!composite_is_ok(c
)) return;
594 Request to perform an authenticated bind if required. Authentication
595 is determined using credentials passed and binding flags.
597 struct composite_context
*dcerpc_pipe_auth_send(struct dcerpc_pipe
*p
,
598 const struct dcerpc_binding
*binding
,
599 const struct ndr_interface_table
*table
,
600 struct cli_credentials
*credentials
,
601 struct loadparm_context
*lp_ctx
)
603 struct composite_context
*c
;
604 struct pipe_auth_state
*s
;
605 struct composite_context
*auth_schannel_req
;
606 struct composite_context
*auth_req
;
607 struct composite_context
*auth_none_req
;
608 struct dcecli_connection
*conn
;
611 /* composite context allocation and setup */
612 c
= composite_create(p
, p
->conn
->event_ctx
);
613 if (c
== NULL
) return NULL
;
615 s
= talloc_zero(c
, struct pipe_auth_state
);
616 if (composite_nomem(s
, c
)) return c
;
619 /* store parameters in state structure */
620 s
->binding
= binding
;
622 s
->credentials
= credentials
;
626 conn
= s
->pipe
->conn
;
627 conn
->flags
= dcerpc_binding_get_flags(binding
);
630 conn
->flags
|= DCERPC_DEBUG_PRINT_BOTH
;
633 if (conn
->transport
.transport
== NCALRPC
) {
634 const char *v
= dcerpc_binding_get_string_option(binding
,
637 if (v
!= NULL
&& strcmp(v
, "ncalrpc_as_system") == 0) {
638 auth_req
= dcerpc_bind_auth_send(c
, s
->pipe
, s
->table
,
640 lpcfg_gensec_settings(c
, s
->lp_ctx
),
641 DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM
,
642 DCERPC_AUTH_LEVEL_CONNECT
,
643 s
->table
->authservices
->names
[0]);
644 composite_continue(c
, auth_req
, continue_auth
, c
);
649 if (cli_credentials_is_anonymous(s
->credentials
)) {
650 auth_none_req
= dcerpc_bind_auth_none_send(c
, s
->pipe
, s
->table
);
651 composite_continue(c
, auth_none_req
, continue_auth_none
, c
);
655 if ((conn
->flags
& DCERPC_SCHANNEL
) &&
656 !cli_credentials_get_netlogon_creds(s
->credentials
)) {
657 /* If we don't already have netlogon credentials for
658 * the schannel bind, then we have to get these
660 auth_schannel_req
= dcerpc_bind_auth_schannel_send(c
, s
->pipe
, s
->table
,
661 s
->credentials
, s
->lp_ctx
,
662 dcerpc_auth_level(conn
));
663 composite_continue(c
, auth_schannel_req
, continue_auth_schannel
, c
);
668 * we rely on the already authenticated CIFS connection
669 * if not doing sign or seal
671 if (conn
->transport
.transport
== NCACN_NP
&&
672 !(conn
->flags
& (DCERPC_SIGN
|DCERPC_SEAL
))) {
673 auth_none_req
= dcerpc_bind_auth_none_send(c
, s
->pipe
, s
->table
);
674 composite_continue(c
, auth_none_req
, continue_auth_none
, c
);
679 /* Perform an authenticated DCE-RPC bind
681 if (!(conn
->flags
& (DCERPC_SIGN
|DCERPC_SEAL
))) {
683 we are doing an authenticated connection,
684 but not using sign or seal. We must force
685 the CONNECT dcerpc auth type as a NONE auth
686 type doesn't allow authentication
687 information to be passed.
689 conn
->flags
|= DCERPC_CONNECT
;
692 if (conn
->flags
& DCERPC_AUTH_SPNEGO
) {
693 auth_type
= DCERPC_AUTH_TYPE_SPNEGO
;
695 } else if (conn
->flags
& DCERPC_AUTH_KRB5
) {
696 auth_type
= DCERPC_AUTH_TYPE_KRB5
;
698 } else if (conn
->flags
& DCERPC_SCHANNEL
) {
699 auth_type
= DCERPC_AUTH_TYPE_SCHANNEL
;
701 } else if (conn
->flags
& DCERPC_AUTH_NTLM
) {
702 auth_type
= DCERPC_AUTH_TYPE_NTLMSSP
;
705 /* try SPNEGO with fallback to NTLMSSP */
706 auth_req
= dcerpc_bind_auth_send(c
, s
->pipe
, s
->table
,
708 lpcfg_gensec_settings(c
, s
->lp_ctx
),
709 DCERPC_AUTH_TYPE_SPNEGO
,
710 dcerpc_auth_level(conn
),
711 s
->table
->authservices
->names
[0]);
712 composite_continue(c
, auth_req
, continue_auth_auto
, c
);
716 auth_req
= dcerpc_bind_auth_send(c
, s
->pipe
, s
->table
,
718 lpcfg_gensec_settings(c
, s
->lp_ctx
),
720 dcerpc_auth_level(conn
),
721 s
->table
->authservices
->names
[0]);
722 composite_continue(c
, auth_req
, continue_auth
, c
);
728 Receive result of authenticated bind request on dcerpc pipe
730 This returns *p, which may be different to the one originally
731 supllied, as it rebinds to a new pipe due to authentication fallback
734 NTSTATUS
dcerpc_pipe_auth_recv(struct composite_context
*c
, TALLOC_CTX
*mem_ctx
,
735 struct dcerpc_pipe
**p
)
739 struct pipe_auth_state
*s
= talloc_get_type(c
->private_data
,
740 struct pipe_auth_state
);
741 status
= composite_wait(c
);
742 if (!NT_STATUS_IS_OK(status
)) {
743 char *uuid_str
= GUID_string(s
->pipe
, &s
->table
->syntax_id
.uuid
);
744 DEBUG(0, ("Failed to bind to uuid %s for %s %s\n", uuid_str
,
745 dcerpc_binding_string(uuid_str
, s
->binding
), nt_errstr(status
)));
746 talloc_free(uuid_str
);
748 talloc_steal(mem_ctx
, s
->pipe
);
758 Perform an authenticated bind if needed - sync version
760 This may change *p, as it rebinds to a new pipe due to authentication fallback
762 _PUBLIC_ NTSTATUS
dcerpc_pipe_auth(TALLOC_CTX
*mem_ctx
,
763 struct dcerpc_pipe
**p
,
764 const struct dcerpc_binding
*binding
,
765 const struct ndr_interface_table
*table
,
766 struct cli_credentials
*credentials
,
767 struct loadparm_context
*lp_ctx
)
769 struct composite_context
*c
;
771 c
= dcerpc_pipe_auth_send(*p
, binding
, table
, credentials
, lp_ctx
);
772 return dcerpc_pipe_auth_recv(c
, mem_ctx
, p
);
776 NTSTATUS
dcerpc_generic_session_key(struct dcecli_connection
*c
,
777 DATA_BLOB
*session_key
)
779 /* this took quite a few CPU cycles to find ... */
780 session_key
->data
= discard_const_p(unsigned char, "SystemLibraryDTC");
781 session_key
->length
= 16;
786 fetch the user session key - may be default (above) or the SMB session key
788 The key is always truncated to 16 bytes
790 _PUBLIC_ NTSTATUS
dcerpc_fetch_session_key(struct dcerpc_pipe
*p
,
791 DATA_BLOB
*session_key
)
794 status
= p
->conn
->security_state
.session_key(p
->conn
, session_key
);
795 if (!NT_STATUS_IS_OK(status
)) {
799 session_key
->length
= MIN(session_key
->length
, 16);
806 log a rpc packet in a format suitable for ndrdump. This is especially useful
807 for sealed packets, where ethereal cannot easily see the contents
809 this triggers on a debug level of >= 10
811 _PUBLIC_
void dcerpc_log_packet(const char *lockdir
,
812 const struct ndr_interface_table
*ndr
,
813 uint32_t opnum
, uint32_t flags
,
814 const DATA_BLOB
*pkt
)
816 const int num_examples
= 20;
819 if (lockdir
== NULL
) return;
821 for (i
=0;i
<num_examples
;i
++) {
824 ret
= asprintf(&name
, "%s/rpclog/%s-%u.%d.%s",
825 lockdir
, ndr
->name
, opnum
, i
,
826 (flags
&NDR_IN
)?"in":"out");
830 if (!file_exist(name
)) {
831 if (file_save(name
, pkt
->data
, pkt
->length
)) {
832 DEBUG(10,("Logged rpc packet to %s\n", name
));
844 create a secondary context from a primary connection
846 this uses dcerpc_alter_context() to create a new dcerpc context_id
848 _PUBLIC_ NTSTATUS
dcerpc_secondary_context(struct dcerpc_pipe
*p
,
849 struct dcerpc_pipe
**pp2
,
850 const struct ndr_interface_table
*table
)
853 struct dcerpc_pipe
*p2
;
855 p2
= talloc_zero(p
, struct dcerpc_pipe
);
857 return NT_STATUS_NO_MEMORY
;
859 p2
->conn
= talloc_reference(p2
, p
->conn
);
860 p2
->request_timeout
= p
->request_timeout
;
862 p2
->context_id
= ++p
->conn
->next_context_id
;
864 p2
->syntax
= table
->syntax_id
;
866 p2
->transfer_syntax
= p
->transfer_syntax
;
868 p2
->binding
= dcerpc_binding_dup(p2
, p
->binding
);
869 if (p2
->binding
== NULL
) {
871 return NT_STATUS_NO_MEMORY
;
874 p2
->binding_handle
= dcerpc_pipe_binding_handle(p2
);
875 if (p2
->binding_handle
== NULL
) {
877 return NT_STATUS_NO_MEMORY
;
880 status
= dcerpc_alter_context(p2
, p2
, &p2
->syntax
, &p2
->transfer_syntax
);
881 if (!NT_STATUS_IS_OK(status
)) {