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 tevent_context
*ev
,
226 struct loadparm_context
*lp_ctx
)
228 struct composite_context
*c
;
229 struct epm_map_binding_state
*s
;
230 struct composite_context
*pipe_connect_req
;
231 struct cli_credentials
*anon_creds
;
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 /* anonymous credentials for rpc connection used to get endpoint mapping */
312 anon_creds
= cli_credentials_init_anon(s
);
313 if (composite_nomem(anon_creds
, c
)) return c
;
315 epmapper_binding
= dcerpc_binding_dup(s
, binding
);
316 if (composite_nomem(epmapper_binding
, c
)) return c
;
318 /* basic endpoint mapping data */
319 c
->status
= dcerpc_binding_set_string_option(epmapper_binding
,
321 if (!composite_is_ok(c
)) {
324 c
->status
= dcerpc_binding_set_flags(epmapper_binding
, 0, UINT32_MAX
);
325 if (!composite_is_ok(c
)) {
328 c
->status
= dcerpc_binding_set_assoc_group_id(epmapper_binding
, 0);
329 if (!composite_is_ok(c
)) {
332 c
->status
= dcerpc_binding_set_object(epmapper_binding
, GUID_zero());
333 if (!composite_is_ok(c
)) {
337 /* initiate rpc pipe connection */
338 pipe_connect_req
= dcerpc_pipe_connect_b_send(s
, epmapper_binding
,
340 anon_creds
, c
->event_ctx
,
342 if (composite_nomem(pipe_connect_req
, c
)) return c
;
344 composite_continue(c
, pipe_connect_req
, continue_epm_recv_binding
, c
);
350 Receive result of endpoint mapping request
352 NTSTATUS
dcerpc_epm_map_binding_recv(struct composite_context
*c
)
354 NTSTATUS status
= composite_wait(c
);
362 Get endpoint mapping for rpc connection
364 _PUBLIC_ NTSTATUS
dcerpc_epm_map_binding(TALLOC_CTX
*mem_ctx
, struct dcerpc_binding
*binding
,
365 const struct ndr_interface_table
*table
, struct tevent_context
*ev
,
366 struct loadparm_context
*lp_ctx
)
368 struct composite_context
*c
;
370 c
= dcerpc_epm_map_binding_send(mem_ctx
, binding
, table
, ev
, lp_ctx
);
371 return dcerpc_epm_map_binding_recv(c
);
375 struct pipe_auth_state
{
376 struct dcerpc_pipe
*pipe
;
377 const struct dcerpc_binding
*binding
;
378 const struct ndr_interface_table
*table
;
379 struct loadparm_context
*lp_ctx
;
380 struct cli_credentials
*credentials
;
381 unsigned int logon_retries
;
385 static void continue_auth_schannel(struct composite_context
*ctx
);
386 static void continue_auth(struct composite_context
*ctx
);
387 static void continue_auth_none(struct composite_context
*ctx
);
388 static void continue_ntlmssp_connection(struct composite_context
*ctx
);
389 static void continue_spnego_after_wrong_pass(struct composite_context
*ctx
);
393 Stage 2 of pipe_auth: Receive result of schannel bind request
395 static void continue_auth_schannel(struct composite_context
*ctx
)
397 struct composite_context
*c
= talloc_get_type(ctx
->async
.private_data
,
398 struct composite_context
);
400 c
->status
= dcerpc_bind_auth_schannel_recv(ctx
);
401 if (!composite_is_ok(c
)) return;
408 Stage 2 of pipe_auth: Receive result of authenticated bind request
410 static void continue_auth(struct composite_context
*ctx
)
412 struct composite_context
*c
= talloc_get_type(ctx
->async
.private_data
,
413 struct composite_context
);
415 c
->status
= dcerpc_bind_auth_recv(ctx
);
416 if (!composite_is_ok(c
)) return;
421 Stage 2 of pipe_auth: Receive result of authenticated bind request, but handle fallbacks:
424 static void continue_auth_auto(struct composite_context
*ctx
)
426 struct composite_context
*c
= talloc_get_type(ctx
->async
.private_data
,
427 struct composite_context
);
428 struct pipe_auth_state
*s
= talloc_get_type(c
->private_data
, struct pipe_auth_state
);
429 struct composite_context
*sec_conn_req
;
431 c
->status
= dcerpc_bind_auth_recv(ctx
);
432 if (NT_STATUS_EQUAL(c
->status
, NT_STATUS_INVALID_PARAMETER
)) {
434 * Retry with NTLMSSP auth as fallback
435 * send a request for secondary rpc connection
437 sec_conn_req
= dcerpc_secondary_connection_send(s
->pipe
,
439 composite_continue(c
, sec_conn_req
, continue_ntlmssp_connection
, c
);
441 } else if (NT_STATUS_EQUAL(c
->status
, NT_STATUS_LOGON_FAILURE
) ||
442 NT_STATUS_EQUAL(c
->status
, NT_STATUS_UNSUCCESSFUL
)) {
444 try a second time on any error. We don't just do it
445 on LOGON_FAILURE as some servers will give a
446 NT_STATUS_UNSUCCESSFUL on a authentication error on RPC
448 const char *principal
;
449 const char *endpoint
;
451 principal
= gensec_get_target_principal(s
->pipe
->conn
->security_state
.generic_state
);
452 if (principal
== NULL
) {
453 const char *hostname
= gensec_get_target_hostname(s
->pipe
->conn
->security_state
.generic_state
);
454 const char *service
= gensec_get_target_service(s
->pipe
->conn
->security_state
.generic_state
);
455 if (hostname
!= NULL
&& service
!= NULL
) {
456 principal
= talloc_asprintf(c
, "%s/%s", service
, hostname
);
460 endpoint
= dcerpc_binding_get_string_option(s
->binding
, "endpoint");
462 if ((cli_credentials_failed_kerberos_login(s
->credentials
, principal
, &s
->logon_retries
) ||
463 cli_credentials_wrong_password(s
->credentials
)) &&
466 * Retry SPNEGO with a better password
467 * send a request for secondary rpc connection
469 sec_conn_req
= dcerpc_secondary_connection_send(s
->pipe
,
471 composite_continue(c
, sec_conn_req
, continue_spnego_after_wrong_pass
, c
);
476 if (!composite_is_ok(c
)) return;
482 Stage 3 of pipe_auth (fallback to NTLMSSP case): Receive secondary
483 rpc connection (the first one can't be used any more, due to the
484 bind nak) and perform authenticated bind request
486 static void continue_ntlmssp_connection(struct composite_context
*ctx
)
488 struct composite_context
*c
;
489 struct pipe_auth_state
*s
;
490 struct composite_context
*auth_req
;
491 struct dcerpc_pipe
*p2
;
494 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
495 s
= talloc_get_type(c
->private_data
, struct pipe_auth_state
);
497 /* receive secondary rpc connection */
498 c
->status
= dcerpc_secondary_connection_recv(ctx
, &p2
);
499 if (!composite_is_ok(c
)) return;
502 /* this is a rather strange situation. When
503 we come into the routine, s is a child of s->pipe, and
504 when we created p2 above, it also became a child of
507 Now we want p2 to be a parent of s->pipe, and we want s to
508 be a parent of both of them! If we don't do this very
509 carefully we end up creating a talloc loop
512 /* we need the new contexts to hang off the same context
513 that s->pipe is on, but the only way to get that is
514 via talloc_parent() */
515 pp
= talloc_parent(s
->pipe
);
517 /* promote s to be at the top */
520 /* and put p2 under s */
523 /* now put s->pipe under p2 */
524 talloc_steal(p2
, s
->pipe
);
528 /* initiate a authenticated bind */
529 auth_req
= dcerpc_bind_auth_send(c
, s
->pipe
, s
->table
,
531 lpcfg_gensec_settings(c
, s
->lp_ctx
),
532 DCERPC_AUTH_TYPE_NTLMSSP
,
533 dcerpc_auth_level(s
->pipe
->conn
),
534 s
->table
->authservices
->names
[0]);
535 composite_continue(c
, auth_req
, continue_auth
, c
);
539 Stage 3 of pipe_auth (retry on wrong password): Receive secondary
540 rpc connection (the first one can't be used any more, due to the
541 bind nak) and perform authenticated bind request
543 static void continue_spnego_after_wrong_pass(struct composite_context
*ctx
)
545 struct composite_context
*c
;
546 struct pipe_auth_state
*s
;
547 struct composite_context
*auth_req
;
548 struct dcerpc_pipe
*p2
;
550 c
= talloc_get_type(ctx
->async
.private_data
, struct composite_context
);
551 s
= talloc_get_type(c
->private_data
, struct pipe_auth_state
);
553 /* receive secondary rpc connection */
554 c
->status
= dcerpc_secondary_connection_recv(ctx
, &p2
);
555 if (!composite_is_ok(c
)) return;
558 talloc_steal(p2
, s
->pipe
);
561 /* initiate a authenticated bind */
562 auth_req
= dcerpc_bind_auth_send(c
, s
->pipe
, s
->table
,
564 lpcfg_gensec_settings(c
, s
->lp_ctx
),
565 DCERPC_AUTH_TYPE_SPNEGO
,
566 dcerpc_auth_level(s
->pipe
->conn
),
567 s
->table
->authservices
->names
[0]);
568 composite_continue(c
, auth_req
, continue_auth
, c
);
573 Stage 2 of pipe_auth: Receive result of non-authenticated bind request
575 static void continue_auth_none(struct composite_context
*ctx
)
577 struct composite_context
*c
= talloc_get_type(ctx
->async
.private_data
,
578 struct composite_context
);
580 c
->status
= dcerpc_bind_auth_none_recv(ctx
);
581 if (!composite_is_ok(c
)) return;
588 Request to perform an authenticated bind if required. Authentication
589 is determined using credentials passed and binding flags.
591 struct composite_context
*dcerpc_pipe_auth_send(struct dcerpc_pipe
*p
,
592 const struct dcerpc_binding
*binding
,
593 const struct ndr_interface_table
*table
,
594 struct cli_credentials
*credentials
,
595 struct loadparm_context
*lp_ctx
)
597 struct composite_context
*c
;
598 struct pipe_auth_state
*s
;
599 struct composite_context
*auth_schannel_req
;
600 struct composite_context
*auth_req
;
601 struct composite_context
*auth_none_req
;
602 struct dcecli_connection
*conn
;
605 /* composite context allocation and setup */
606 c
= composite_create(p
, p
->conn
->event_ctx
);
607 if (c
== NULL
) return NULL
;
609 s
= talloc_zero(c
, struct pipe_auth_state
);
610 if (composite_nomem(s
, c
)) return c
;
613 /* store parameters in state structure */
614 s
->binding
= binding
;
616 s
->credentials
= credentials
;
620 conn
= s
->pipe
->conn
;
621 conn
->flags
= dcerpc_binding_get_flags(binding
);
624 conn
->flags
|= DCERPC_DEBUG_PRINT_BOTH
;
627 if (cli_credentials_is_anonymous(s
->credentials
)) {
628 auth_none_req
= dcerpc_bind_auth_none_send(c
, s
->pipe
, s
->table
);
629 composite_continue(c
, auth_none_req
, continue_auth_none
, c
);
633 if ((conn
->flags
& DCERPC_SCHANNEL
) &&
634 !cli_credentials_get_netlogon_creds(s
->credentials
)) {
635 /* If we don't already have netlogon credentials for
636 * the schannel bind, then we have to get these
638 auth_schannel_req
= dcerpc_bind_auth_schannel_send(c
, s
->pipe
, s
->table
,
639 s
->credentials
, s
->lp_ctx
,
640 dcerpc_auth_level(conn
));
641 composite_continue(c
, auth_schannel_req
, continue_auth_schannel
, c
);
646 * we rely on the already authenticated CIFS connection
647 * if not doing sign or seal
649 if (conn
->transport
.transport
== NCACN_NP
&&
650 !(conn
->flags
& (DCERPC_SIGN
|DCERPC_SEAL
))) {
651 auth_none_req
= dcerpc_bind_auth_none_send(c
, s
->pipe
, s
->table
);
652 composite_continue(c
, auth_none_req
, continue_auth_none
, c
);
657 /* Perform an authenticated DCE-RPC bind
659 if (!(conn
->flags
& (DCERPC_SIGN
|DCERPC_SEAL
))) {
661 we are doing an authenticated connection,
662 but not using sign or seal. We must force
663 the CONNECT dcerpc auth type as a NONE auth
664 type doesn't allow authentication
665 information to be passed.
667 conn
->flags
|= DCERPC_CONNECT
;
670 if (conn
->flags
& DCERPC_AUTH_SPNEGO
) {
671 auth_type
= DCERPC_AUTH_TYPE_SPNEGO
;
673 } else if (conn
->flags
& DCERPC_AUTH_KRB5
) {
674 auth_type
= DCERPC_AUTH_TYPE_KRB5
;
676 } else if (conn
->flags
& DCERPC_SCHANNEL
) {
677 auth_type
= DCERPC_AUTH_TYPE_SCHANNEL
;
679 } else if (conn
->flags
& DCERPC_AUTH_NTLM
) {
680 auth_type
= DCERPC_AUTH_TYPE_NTLMSSP
;
683 /* try SPNEGO with fallback to NTLMSSP */
684 auth_req
= dcerpc_bind_auth_send(c
, s
->pipe
, s
->table
,
686 lpcfg_gensec_settings(c
, s
->lp_ctx
),
687 DCERPC_AUTH_TYPE_SPNEGO
,
688 dcerpc_auth_level(conn
),
689 s
->table
->authservices
->names
[0]);
690 composite_continue(c
, auth_req
, continue_auth_auto
, c
);
694 auth_req
= dcerpc_bind_auth_send(c
, s
->pipe
, s
->table
,
696 lpcfg_gensec_settings(c
, s
->lp_ctx
),
698 dcerpc_auth_level(conn
),
699 s
->table
->authservices
->names
[0]);
700 composite_continue(c
, auth_req
, continue_auth
, c
);
706 Receive result of authenticated bind request on dcerpc pipe
708 This returns *p, which may be different to the one originally
709 supllied, as it rebinds to a new pipe due to authentication fallback
712 NTSTATUS
dcerpc_pipe_auth_recv(struct composite_context
*c
, TALLOC_CTX
*mem_ctx
,
713 struct dcerpc_pipe
**p
)
717 struct pipe_auth_state
*s
= talloc_get_type(c
->private_data
,
718 struct pipe_auth_state
);
719 status
= composite_wait(c
);
720 if (!NT_STATUS_IS_OK(status
)) {
721 char *uuid_str
= GUID_string(s
->pipe
, &s
->table
->syntax_id
.uuid
);
722 DEBUG(0, ("Failed to bind to uuid %s for %s %s\n", uuid_str
,
723 dcerpc_binding_string(uuid_str
, s
->binding
), nt_errstr(status
)));
724 talloc_free(uuid_str
);
726 talloc_steal(mem_ctx
, s
->pipe
);
736 Perform an authenticated bind if needed - sync version
738 This may change *p, as it rebinds to a new pipe due to authentication fallback
740 _PUBLIC_ NTSTATUS
dcerpc_pipe_auth(TALLOC_CTX
*mem_ctx
,
741 struct dcerpc_pipe
**p
,
742 const struct dcerpc_binding
*binding
,
743 const struct ndr_interface_table
*table
,
744 struct cli_credentials
*credentials
,
745 struct loadparm_context
*lp_ctx
)
747 struct composite_context
*c
;
749 c
= dcerpc_pipe_auth_send(*p
, binding
, table
, credentials
, lp_ctx
);
750 return dcerpc_pipe_auth_recv(c
, mem_ctx
, p
);
754 NTSTATUS
dcerpc_generic_session_key(struct dcecli_connection
*c
,
755 DATA_BLOB
*session_key
)
757 /* this took quite a few CPU cycles to find ... */
758 session_key
->data
= discard_const_p(unsigned char, "SystemLibraryDTC");
759 session_key
->length
= 16;
764 fetch the user session key - may be default (above) or the SMB session key
766 The key is always truncated to 16 bytes
768 _PUBLIC_ NTSTATUS
dcerpc_fetch_session_key(struct dcerpc_pipe
*p
,
769 DATA_BLOB
*session_key
)
772 status
= p
->conn
->security_state
.session_key(p
->conn
, session_key
);
773 if (!NT_STATUS_IS_OK(status
)) {
777 session_key
->length
= MIN(session_key
->length
, 16);
784 log a rpc packet in a format suitable for ndrdump. This is especially useful
785 for sealed packets, where ethereal cannot easily see the contents
787 this triggers on a debug level of >= 10
789 _PUBLIC_
void dcerpc_log_packet(const char *lockdir
,
790 const struct ndr_interface_table
*ndr
,
791 uint32_t opnum
, uint32_t flags
,
792 const DATA_BLOB
*pkt
)
794 const int num_examples
= 20;
797 if (lockdir
== NULL
) return;
799 for (i
=0;i
<num_examples
;i
++) {
801 asprintf(&name
, "%s/rpclog/%s-%u.%d.%s",
802 lockdir
, ndr
->name
, opnum
, i
,
803 (flags
&NDR_IN
)?"in":"out");
807 if (!file_exist(name
)) {
808 if (file_save(name
, pkt
->data
, pkt
->length
)) {
809 DEBUG(10,("Logged rpc packet to %s\n", name
));
821 create a secondary context from a primary connection
823 this uses dcerpc_alter_context() to create a new dcerpc context_id
825 _PUBLIC_ NTSTATUS
dcerpc_secondary_context(struct dcerpc_pipe
*p
,
826 struct dcerpc_pipe
**pp2
,
827 const struct ndr_interface_table
*table
)
830 struct dcerpc_pipe
*p2
;
832 p2
= talloc_zero(p
, struct dcerpc_pipe
);
834 return NT_STATUS_NO_MEMORY
;
836 p2
->conn
= talloc_reference(p2
, p
->conn
);
837 p2
->request_timeout
= p
->request_timeout
;
839 p2
->context_id
= ++p
->conn
->next_context_id
;
841 p2
->syntax
= table
->syntax_id
;
843 p2
->transfer_syntax
= p
->transfer_syntax
;
845 p2
->binding
= dcerpc_binding_dup(p2
, p
->binding
);
846 if (p2
->binding
== NULL
) {
848 return NT_STATUS_NO_MEMORY
;
851 p2
->binding_handle
= dcerpc_pipe_binding_handle(p2
);
852 if (p2
->binding_handle
== NULL
) {
854 return NT_STATUS_NO_MEMORY
;
857 status
= dcerpc_alter_context(p2
, p2
, &p2
->syntax
, &p2
->transfer_syntax
);
858 if (!NT_STATUS_IS_OK(status
)) {