2 Unix SMB/CIFS implementation.
4 server side dcerpc core code
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) Stefan (metze) Metzmacher 2004-2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "auth/auth.h"
25 #include "auth/gensec/gensec.h"
26 #include "../lib/util/dlinklist.h"
27 #include "rpc_server/dcerpc_server.h"
28 #include "rpc_server/dcerpc_server_proto.h"
29 #include "rpc_server/common/proto.h"
30 #include "librpc/rpc/dcerpc_proto.h"
31 #include "system/filesys.h"
32 #include "libcli/security/security.h"
33 #include "param/param.h"
34 #include "../lib/tsocket/tsocket.h"
35 #include "../libcli/named_pipe_auth/npa_tstream.h"
36 #include "smbd/service_stream.h"
37 #include "../lib/tsocket/tsocket.h"
38 #include "lib/socket/socket.h"
39 #include "smbd/process_model.h"
40 #include "lib/messaging/irpc.h"
41 #include "librpc/rpc/rpc_common.h"
42 #include "lib/util/samba_modules.h"
44 /* this is only used when the client asks for an unknown interface */
45 #define DUMMY_ASSOC_GROUP 0x0FFFFFFF
47 extern const struct dcesrv_interface dcesrv_mgmt_interface
;
51 find an association group given a assoc_group_id
53 static struct dcesrv_assoc_group
*dcesrv_assoc_group_find(struct dcesrv_context
*dce_ctx
,
58 id_ptr
= idr_find(dce_ctx
->assoc_groups_idr
, id
);
62 return talloc_get_type_abort(id_ptr
, struct dcesrv_assoc_group
);
66 take a reference to an existing association group
68 static struct dcesrv_assoc_group
*dcesrv_assoc_group_reference(TALLOC_CTX
*mem_ctx
,
69 struct dcesrv_context
*dce_ctx
,
72 struct dcesrv_assoc_group
*assoc_group
;
74 assoc_group
= dcesrv_assoc_group_find(dce_ctx
, id
);
75 if (assoc_group
== NULL
) {
76 DEBUG(0,(__location__
": Failed to find assoc_group 0x%08x\n", id
));
79 return talloc_reference(mem_ctx
, assoc_group
);
82 static int dcesrv_assoc_group_destructor(struct dcesrv_assoc_group
*assoc_group
)
85 ret
= idr_remove(assoc_group
->dce_ctx
->assoc_groups_idr
, assoc_group
->id
);
87 DEBUG(0,(__location__
": Failed to remove assoc_group 0x%08x\n",
94 allocate a new association group
96 static struct dcesrv_assoc_group
*dcesrv_assoc_group_new(TALLOC_CTX
*mem_ctx
,
97 struct dcesrv_context
*dce_ctx
)
99 struct dcesrv_assoc_group
*assoc_group
;
102 assoc_group
= talloc_zero(mem_ctx
, struct dcesrv_assoc_group
);
103 if (assoc_group
== NULL
) {
107 id
= idr_get_new_random(dce_ctx
->assoc_groups_idr
, assoc_group
, UINT16_MAX
);
109 talloc_free(assoc_group
);
110 DEBUG(0,(__location__
": Out of association groups!\n"));
114 assoc_group
->id
= id
;
115 assoc_group
->dce_ctx
= dce_ctx
;
117 talloc_set_destructor(assoc_group
, dcesrv_assoc_group_destructor
);
124 see if two endpoints match
126 static bool endpoints_match(const struct dcerpc_binding
*ep1
,
127 const struct dcerpc_binding
*ep2
)
129 if (ep1
->transport
!= ep2
->transport
) {
133 if (!ep1
->endpoint
|| !ep2
->endpoint
) {
134 return ep1
->endpoint
== ep2
->endpoint
;
137 if (strcasecmp(ep1
->endpoint
, ep2
->endpoint
) != 0)
144 find an endpoint in the dcesrv_context
146 static struct dcesrv_endpoint
*find_endpoint(struct dcesrv_context
*dce_ctx
,
147 const struct dcerpc_binding
*ep_description
)
149 struct dcesrv_endpoint
*ep
;
150 for (ep
=dce_ctx
->endpoint_list
; ep
; ep
=ep
->next
) {
151 if (endpoints_match(ep
->ep_description
, ep_description
)) {
159 find a registered context_id from a bind or alter_context
161 static struct dcesrv_connection_context
*dcesrv_find_context(struct dcesrv_connection
*conn
,
164 struct dcesrv_connection_context
*c
;
165 for (c
=conn
->contexts
;c
;c
=c
->next
) {
166 if (c
->context_id
== context_id
) return c
;
172 see if a uuid and if_version match to an interface
174 static bool interface_match(const struct dcesrv_interface
*if1
,
175 const struct dcesrv_interface
*if2
)
177 return (if1
->syntax_id
.if_version
== if2
->syntax_id
.if_version
&&
178 GUID_equal(&if1
->syntax_id
.uuid
, &if2
->syntax_id
.uuid
));
182 find the interface operations on an endpoint
184 static const struct dcesrv_interface
*find_interface(const struct dcesrv_endpoint
*endpoint
,
185 const struct dcesrv_interface
*iface
)
187 struct dcesrv_if_list
*ifl
;
188 for (ifl
=endpoint
->interface_list
; ifl
; ifl
=ifl
->next
) {
189 if (interface_match(&(ifl
->iface
), iface
)) {
190 return &(ifl
->iface
);
197 see if a uuid and if_version match to an interface
199 static bool interface_match_by_uuid(const struct dcesrv_interface
*iface
,
200 const struct GUID
*uuid
, uint32_t if_version
)
202 return (iface
->syntax_id
.if_version
== if_version
&&
203 GUID_equal(&iface
->syntax_id
.uuid
, uuid
));
207 find the interface operations on an endpoint by uuid
209 static const struct dcesrv_interface
*find_interface_by_uuid(const struct dcesrv_endpoint
*endpoint
,
210 const struct GUID
*uuid
, uint32_t if_version
)
212 struct dcesrv_if_list
*ifl
;
213 for (ifl
=endpoint
->interface_list
; ifl
; ifl
=ifl
->next
) {
214 if (interface_match_by_uuid(&(ifl
->iface
), uuid
, if_version
)) {
215 return &(ifl
->iface
);
222 find the earlier parts of a fragmented call awaiting reassembily
224 static struct dcesrv_call_state
*dcesrv_find_fragmented_call(struct dcesrv_connection
*dce_conn
, uint16_t call_id
)
226 struct dcesrv_call_state
*c
;
227 for (c
=dce_conn
->incoming_fragmented_call_list
;c
;c
=c
->next
) {
228 if (c
->pkt
.call_id
== call_id
) {
236 register an interface on an endpoint
238 _PUBLIC_ NTSTATUS
dcesrv_interface_register(struct dcesrv_context
*dce_ctx
,
240 const struct dcesrv_interface
*iface
,
241 const struct security_descriptor
*sd
)
243 struct dcesrv_endpoint
*ep
;
244 struct dcesrv_if_list
*ifl
;
245 struct dcerpc_binding
*binding
;
249 status
= dcerpc_parse_binding(dce_ctx
, ep_name
, &binding
);
251 if (NT_STATUS_IS_ERR(status
)) {
252 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name
));
256 /* check if this endpoint exists
258 if ((ep
=find_endpoint(dce_ctx
, binding
))==NULL
) {
259 ep
= talloc(dce_ctx
, struct dcesrv_endpoint
);
261 return NT_STATUS_NO_MEMORY
;
264 ep
->ep_description
= talloc_reference(ep
, binding
);
267 /* add mgmt interface */
268 ifl
= talloc(dce_ctx
, struct dcesrv_if_list
);
270 return NT_STATUS_NO_MEMORY
;
273 memcpy(&(ifl
->iface
), &dcesrv_mgmt_interface
,
274 sizeof(struct dcesrv_interface
));
276 DLIST_ADD(ep
->interface_list
, ifl
);
279 /* see if the interface is already registered on te endpoint */
280 if (find_interface(ep
, iface
)!=NULL
) {
281 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
282 iface
->name
, ep_name
));
283 return NT_STATUS_OBJECT_NAME_COLLISION
;
286 /* talloc a new interface list element */
287 ifl
= talloc(dce_ctx
, struct dcesrv_if_list
);
289 return NT_STATUS_NO_MEMORY
;
292 /* copy the given interface struct to the one on the endpoints interface list */
293 memcpy(&(ifl
->iface
),iface
, sizeof(struct dcesrv_interface
));
295 /* if we have a security descriptor given,
296 * we should see if we can set it up on the endpoint
299 /* if there's currently no security descriptor given on the endpoint
302 if (ep
->sd
== NULL
) {
303 ep
->sd
= security_descriptor_copy(dce_ctx
, sd
);
306 /* if now there's no security descriptor given on the endpoint
307 * something goes wrong, either we failed to copy the security descriptor
308 * or there was already one on the endpoint
310 if (ep
->sd
!= NULL
) {
311 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
312 " on endpoint '%s'\n",
313 iface
->name
, ep_name
));
314 if (add_ep
) free(ep
);
316 return NT_STATUS_OBJECT_NAME_COLLISION
;
320 /* finally add the interface on the endpoint */
321 DLIST_ADD(ep
->interface_list
, ifl
);
323 /* if it's a new endpoint add it to the dcesrv_context */
325 DLIST_ADD(dce_ctx
->endpoint_list
, ep
);
328 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
329 iface
->name
, ep_name
));
334 NTSTATUS
dcesrv_inherited_session_key(struct dcesrv_connection
*p
,
335 DATA_BLOB
*session_key
)
337 if (p
->auth_state
.session_info
->session_key
.length
) {
338 *session_key
= p
->auth_state
.session_info
->session_key
;
341 return NT_STATUS_NO_USER_SESSION_KEY
;
345 fetch the user session key - may be default (above) or the SMB session key
347 The key is always truncated to 16 bytes
349 _PUBLIC_ NTSTATUS
dcesrv_fetch_session_key(struct dcesrv_connection
*p
,
350 DATA_BLOB
*session_key
)
352 NTSTATUS status
= p
->auth_state
.session_key(p
, session_key
);
353 if (!NT_STATUS_IS_OK(status
)) {
357 session_key
->length
= MIN(session_key
->length
, 16);
363 connect to a dcerpc endpoint
365 _PUBLIC_ NTSTATUS
dcesrv_endpoint_connect(struct dcesrv_context
*dce_ctx
,
367 const struct dcesrv_endpoint
*ep
,
368 struct auth_session_info
*session_info
,
369 struct tevent_context
*event_ctx
,
370 struct imessaging_context
*msg_ctx
,
371 struct server_id server_id
,
372 uint32_t state_flags
,
373 struct dcesrv_connection
**_p
)
375 struct dcesrv_connection
*p
;
378 return NT_STATUS_ACCESS_DENIED
;
381 p
= talloc(mem_ctx
, struct dcesrv_connection
);
382 NT_STATUS_HAVE_NO_MEMORY(p
);
384 if (!talloc_reference(p
, session_info
)) {
386 return NT_STATUS_NO_MEMORY
;
391 p
->dce_ctx
= dce_ctx
;
395 p
->packet_log_dir
= lpcfg_lockdir(dce_ctx
->lp_ctx
);
396 p
->incoming_fragmented_call_list
= NULL
;
397 p
->pending_call_list
= NULL
;
398 p
->cli_max_recv_frag
= 0;
399 p
->partial_input
= data_blob(NULL
, 0);
400 p
->auth_state
.auth_info
= NULL
;
401 p
->auth_state
.gensec_security
= NULL
;
402 p
->auth_state
.session_info
= session_info
;
403 p
->auth_state
.session_key
= dcesrv_generic_session_key
;
404 p
->event_ctx
= event_ctx
;
405 p
->msg_ctx
= msg_ctx
;
406 p
->server_id
= server_id
;
408 p
->state_flags
= state_flags
;
409 ZERO_STRUCT(p
->transport
);
416 move a call from an existing linked list to the specified list. This
417 prevents bugs where we forget to remove the call from a previous
420 static void dcesrv_call_set_list(struct dcesrv_call_state
*call
,
421 enum dcesrv_call_list list
)
423 switch (call
->list
) {
424 case DCESRV_LIST_NONE
:
426 case DCESRV_LIST_CALL_LIST
:
427 DLIST_REMOVE(call
->conn
->call_list
, call
);
429 case DCESRV_LIST_FRAGMENTED_CALL_LIST
:
430 DLIST_REMOVE(call
->conn
->incoming_fragmented_call_list
, call
);
432 case DCESRV_LIST_PENDING_CALL_LIST
:
433 DLIST_REMOVE(call
->conn
->pending_call_list
, call
);
438 case DCESRV_LIST_NONE
:
440 case DCESRV_LIST_CALL_LIST
:
441 DLIST_ADD_END(call
->conn
->call_list
, call
, struct dcesrv_call_state
*);
443 case DCESRV_LIST_FRAGMENTED_CALL_LIST
:
444 DLIST_ADD_END(call
->conn
->incoming_fragmented_call_list
, call
, struct dcesrv_call_state
*);
446 case DCESRV_LIST_PENDING_CALL_LIST
:
447 DLIST_ADD_END(call
->conn
->pending_call_list
, call
, struct dcesrv_call_state
*);
454 return a dcerpc bind_nak
456 static NTSTATUS
dcesrv_bind_nak(struct dcesrv_call_state
*call
, uint32_t reason
)
458 struct ncacn_packet pkt
;
459 struct data_blob_list_item
*rep
;
462 /* setup a bind_nak */
463 dcesrv_init_hdr(&pkt
, lpcfg_rpc_big_endian(call
->conn
->dce_ctx
->lp_ctx
));
465 pkt
.call_id
= call
->pkt
.call_id
;
466 pkt
.ptype
= DCERPC_PKT_BIND_NAK
;
467 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
468 pkt
.u
.bind_nak
.reject_reason
= reason
;
469 if (pkt
.u
.bind_nak
.reject_reason
== DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED
) {
470 pkt
.u
.bind_nak
.versions
.v
.num_versions
= 0;
473 rep
= talloc(call
, struct data_blob_list_item
);
475 return NT_STATUS_NO_MEMORY
;
478 status
= ncacn_push_auth(&rep
->blob
, call
, &pkt
, NULL
);
479 if (!NT_STATUS_IS_OK(status
)) {
483 dcerpc_set_frag_length(&rep
->blob
, rep
->blob
.length
);
485 DLIST_ADD_END(call
->replies
, rep
, struct data_blob_list_item
*);
486 dcesrv_call_set_list(call
, DCESRV_LIST_CALL_LIST
);
488 if (call
->conn
->call_list
&& call
->conn
->call_list
->replies
) {
489 if (call
->conn
->transport
.report_output_data
) {
490 call
->conn
->transport
.report_output_data(call
->conn
);
497 static int dcesrv_connection_context_destructor(struct dcesrv_connection_context
*c
)
499 DLIST_REMOVE(c
->conn
->contexts
, c
);
501 if (c
->iface
&& c
->iface
->unbind
) {
502 c
->iface
->unbind(c
, c
->iface
);
509 handle a bind request
511 static NTSTATUS
dcesrv_bind(struct dcesrv_call_state
*call
)
513 uint32_t if_version
, transfer_syntax_version
;
514 struct GUID uuid
, *transfer_syntax_uuid
;
515 struct ncacn_packet pkt
;
516 struct data_blob_list_item
*rep
;
518 uint32_t result
=0, reason
=0;
520 const struct dcesrv_interface
*iface
;
521 uint32_t extra_flags
= 0;
524 if provided, check the assoc_group is valid
526 if (call
->pkt
.u
.bind
.assoc_group_id
!= 0 &&
527 lpcfg_parm_bool(call
->conn
->dce_ctx
->lp_ctx
, NULL
, "dcesrv","assoc group checking", true) &&
528 dcesrv_assoc_group_find(call
->conn
->dce_ctx
, call
->pkt
.u
.bind
.assoc_group_id
) == NULL
) {
529 return dcesrv_bind_nak(call
, 0);
532 if (call
->pkt
.u
.bind
.num_contexts
< 1 ||
533 call
->pkt
.u
.bind
.ctx_list
[0].num_transfer_syntaxes
< 1) {
534 return dcesrv_bind_nak(call
, 0);
537 context_id
= call
->pkt
.u
.bind
.ctx_list
[0].context_id
;
539 /* you can't bind twice on one context */
540 if (dcesrv_find_context(call
->conn
, context_id
) != NULL
) {
541 return dcesrv_bind_nak(call
, 0);
544 if_version
= call
->pkt
.u
.bind
.ctx_list
[0].abstract_syntax
.if_version
;
545 uuid
= call
->pkt
.u
.bind
.ctx_list
[0].abstract_syntax
.uuid
;
547 transfer_syntax_version
= call
->pkt
.u
.bind
.ctx_list
[0].transfer_syntaxes
[0].if_version
;
548 transfer_syntax_uuid
= &call
->pkt
.u
.bind
.ctx_list
[0].transfer_syntaxes
[0].uuid
;
549 if (!GUID_equal(&ndr_transfer_syntax_ndr
.uuid
, transfer_syntax_uuid
) != 0 ||
550 ndr_transfer_syntax_ndr
.if_version
!= transfer_syntax_version
) {
551 char *uuid_str
= GUID_string(call
, transfer_syntax_uuid
);
552 /* we only do NDR encoded dcerpc */
553 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str
));
554 talloc_free(uuid_str
);
555 return dcesrv_bind_nak(call
, 0);
558 iface
= find_interface_by_uuid(call
->conn
->endpoint
, &uuid
, if_version
);
560 char *uuid_str
= GUID_string(call
, &uuid
);
561 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str
, if_version
));
562 talloc_free(uuid_str
);
564 /* we don't know about that interface */
565 result
= DCERPC_BIND_PROVIDER_REJECT
;
566 reason
= DCERPC_BIND_REASON_ASYNTAX
;
570 /* add this context to the list of available context_ids */
571 struct dcesrv_connection_context
*context
= talloc(call
->conn
,
572 struct dcesrv_connection_context
);
573 if (context
== NULL
) {
574 return dcesrv_bind_nak(call
, 0);
576 context
->conn
= call
->conn
;
577 context
->iface
= iface
;
578 context
->context_id
= context_id
;
579 if (call
->pkt
.u
.bind
.assoc_group_id
!= 0) {
580 context
->assoc_group
= dcesrv_assoc_group_reference(context
,
582 call
->pkt
.u
.bind
.assoc_group_id
);
584 context
->assoc_group
= dcesrv_assoc_group_new(context
, call
->conn
->dce_ctx
);
586 if (context
->assoc_group
== NULL
) {
587 talloc_free(context
);
588 return dcesrv_bind_nak(call
, 0);
590 context
->private_data
= NULL
;
591 DLIST_ADD(call
->conn
->contexts
, context
);
592 call
->context
= context
;
593 talloc_set_destructor(context
, dcesrv_connection_context_destructor
);
595 status
= iface
->bind(call
, iface
, if_version
);
596 if (!NT_STATUS_IS_OK(status
)) {
597 char *uuid_str
= GUID_string(call
, &uuid
);
598 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
599 uuid_str
, if_version
, nt_errstr(status
)));
600 talloc_free(uuid_str
);
601 /* we don't want to trigger the iface->unbind() hook */
602 context
->iface
= NULL
;
603 talloc_free(call
->context
);
604 call
->context
= NULL
;
605 return dcesrv_bind_nak(call
, 0);
609 if (call
->conn
->cli_max_recv_frag
== 0) {
610 call
->conn
->cli_max_recv_frag
= MIN(0x2000, call
->pkt
.u
.bind
.max_recv_frag
);
613 if ((call
->pkt
.pfc_flags
& DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
) &&
614 lpcfg_parm_bool(call
->conn
->dce_ctx
->lp_ctx
, NULL
, "dcesrv","header signing", false)) {
615 call
->conn
->state_flags
|= DCESRV_CALL_STATE_FLAG_HEADER_SIGNING
;
616 extra_flags
|= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
;
619 /* handle any authentication that is being requested */
620 if (!dcesrv_auth_bind(call
)) {
621 talloc_free(call
->context
);
622 call
->context
= NULL
;
623 return dcesrv_bind_nak(call
, DCERPC_BIND_REASON_INVALID_AUTH_TYPE
);
626 /* setup a bind_ack */
627 dcesrv_init_hdr(&pkt
, lpcfg_rpc_big_endian(call
->conn
->dce_ctx
->lp_ctx
));
629 pkt
.call_id
= call
->pkt
.call_id
;
630 pkt
.ptype
= DCERPC_PKT_BIND_ACK
;
631 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
| extra_flags
;
632 pkt
.u
.bind_ack
.max_xmit_frag
= call
->conn
->cli_max_recv_frag
;
633 pkt
.u
.bind_ack
.max_recv_frag
= 0x2000;
636 make it possible for iface->bind() to specify the assoc_group_id
637 This helps the openchange mapiproxy plugin to work correctly.
642 pkt
.u
.bind_ack
.assoc_group_id
= call
->context
->assoc_group
->id
;
644 pkt
.u
.bind_ack
.assoc_group_id
= DUMMY_ASSOC_GROUP
;
648 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
649 pkt
.u
.bind_ack
.secondary_address
= talloc_asprintf(call
, "\\PIPE\\%s", iface
->name
);
651 pkt
.u
.bind_ack
.secondary_address
= "";
653 pkt
.u
.bind_ack
.num_results
= 1;
654 pkt
.u
.bind_ack
.ctx_list
= talloc(call
, struct dcerpc_ack_ctx
);
655 if (!pkt
.u
.bind_ack
.ctx_list
) {
656 talloc_free(call
->context
);
657 call
->context
= NULL
;
658 return NT_STATUS_NO_MEMORY
;
660 pkt
.u
.bind_ack
.ctx_list
[0].result
= result
;
661 pkt
.u
.bind_ack
.ctx_list
[0].reason
= reason
;
662 pkt
.u
.bind_ack
.ctx_list
[0].syntax
= ndr_transfer_syntax_ndr
;
663 pkt
.u
.bind_ack
.auth_info
= data_blob(NULL
, 0);
665 status
= dcesrv_auth_bind_ack(call
, &pkt
);
666 if (!NT_STATUS_IS_OK(status
)) {
667 talloc_free(call
->context
);
668 call
->context
= NULL
;
669 return dcesrv_bind_nak(call
, 0);
672 rep
= talloc(call
, struct data_blob_list_item
);
674 talloc_free(call
->context
);
675 call
->context
= NULL
;
676 return NT_STATUS_NO_MEMORY
;
679 status
= ncacn_push_auth(&rep
->blob
, call
, &pkt
,
680 call
->conn
->auth_state
.auth_info
);
681 if (!NT_STATUS_IS_OK(status
)) {
682 talloc_free(call
->context
);
683 call
->context
= NULL
;
687 dcerpc_set_frag_length(&rep
->blob
, rep
->blob
.length
);
689 DLIST_ADD_END(call
->replies
, rep
, struct data_blob_list_item
*);
690 dcesrv_call_set_list(call
, DCESRV_LIST_CALL_LIST
);
692 if (call
->conn
->call_list
&& call
->conn
->call_list
->replies
) {
693 if (call
->conn
->transport
.report_output_data
) {
694 call
->conn
->transport
.report_output_data(call
->conn
);
703 handle a auth3 request
705 static NTSTATUS
dcesrv_auth3(struct dcesrv_call_state
*call
)
707 /* handle the auth3 in the auth code */
708 if (!dcesrv_auth_auth3(call
)) {
709 return dcesrv_fault(call
, DCERPC_FAULT_OTHER
);
714 /* we don't send a reply to a auth3 request, except by a
721 handle a bind request
723 static NTSTATUS
dcesrv_alter_new_context(struct dcesrv_call_state
*call
, uint32_t context_id
)
725 uint32_t if_version
, transfer_syntax_version
;
726 struct dcesrv_connection_context
*context
;
727 const struct dcesrv_interface
*iface
;
728 struct GUID uuid
, *transfer_syntax_uuid
;
731 if_version
= call
->pkt
.u
.alter
.ctx_list
[0].abstract_syntax
.if_version
;
732 uuid
= call
->pkt
.u
.alter
.ctx_list
[0].abstract_syntax
.uuid
;
734 transfer_syntax_version
= call
->pkt
.u
.alter
.ctx_list
[0].transfer_syntaxes
[0].if_version
;
735 transfer_syntax_uuid
= &call
->pkt
.u
.alter
.ctx_list
[0].transfer_syntaxes
[0].uuid
;
736 if (!GUID_equal(transfer_syntax_uuid
, &ndr_transfer_syntax_ndr
.uuid
) ||
737 ndr_transfer_syntax_ndr
.if_version
!= transfer_syntax_version
) {
738 /* we only do NDR encoded dcerpc */
739 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED
;
742 iface
= find_interface_by_uuid(call
->conn
->endpoint
, &uuid
, if_version
);
744 char *uuid_str
= GUID_string(call
, &uuid
);
745 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str
, if_version
));
746 talloc_free(uuid_str
);
747 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED
;
750 /* add this context to the list of available context_ids */
751 context
= talloc(call
->conn
, struct dcesrv_connection_context
);
752 if (context
== NULL
) {
753 return NT_STATUS_NO_MEMORY
;
755 context
->conn
= call
->conn
;
756 context
->iface
= iface
;
757 context
->context_id
= context_id
;
758 if (call
->pkt
.u
.alter
.assoc_group_id
!= 0) {
759 context
->assoc_group
= dcesrv_assoc_group_reference(context
,
761 call
->pkt
.u
.alter
.assoc_group_id
);
763 context
->assoc_group
= dcesrv_assoc_group_new(context
, call
->conn
->dce_ctx
);
765 if (context
->assoc_group
== NULL
) {
766 talloc_free(context
);
767 call
->context
= NULL
;
768 return NT_STATUS_NO_MEMORY
;
770 context
->private_data
= NULL
;
771 DLIST_ADD(call
->conn
->contexts
, context
);
772 call
->context
= context
;
773 talloc_set_destructor(context
, dcesrv_connection_context_destructor
);
775 status
= iface
->bind(call
, iface
, if_version
);
776 if (!NT_STATUS_IS_OK(status
)) {
777 /* we don't want to trigger the iface->unbind() hook */
778 context
->iface
= NULL
;
779 talloc_free(context
);
780 call
->context
= NULL
;
789 handle a alter context request
791 static NTSTATUS
dcesrv_alter(struct dcesrv_call_state
*call
)
793 struct ncacn_packet pkt
;
794 struct data_blob_list_item
*rep
;
796 uint32_t result
=0, reason
=0;
799 /* handle any authentication that is being requested */
800 if (!dcesrv_auth_alter(call
)) {
801 /* TODO: work out the right reject code */
802 result
= DCERPC_BIND_PROVIDER_REJECT
;
803 reason
= DCERPC_BIND_REASON_ASYNTAX
;
806 context_id
= call
->pkt
.u
.alter
.ctx_list
[0].context_id
;
808 /* see if they are asking for a new interface */
810 call
->context
= dcesrv_find_context(call
->conn
, context_id
);
811 if (!call
->context
) {
812 status
= dcesrv_alter_new_context(call
, context_id
);
813 if (!NT_STATUS_IS_OK(status
)) {
814 result
= DCERPC_BIND_PROVIDER_REJECT
;
815 reason
= DCERPC_BIND_REASON_ASYNTAX
;
821 call
->pkt
.u
.alter
.assoc_group_id
!= 0 &&
822 lpcfg_parm_bool(call
->conn
->dce_ctx
->lp_ctx
, NULL
, "dcesrv","assoc group checking", true) &&
823 call
->pkt
.u
.alter
.assoc_group_id
!= call
->context
->assoc_group
->id
) {
824 DEBUG(0,(__location__
": Failed attempt to use new assoc_group in alter context (0x%08x 0x%08x)\n",
825 call
->context
->assoc_group
->id
, call
->pkt
.u
.alter
.assoc_group_id
));
826 /* TODO: can they ask for a new association group? */
827 result
= DCERPC_BIND_PROVIDER_REJECT
;
828 reason
= DCERPC_BIND_REASON_ASYNTAX
;
831 /* setup a alter_resp */
832 dcesrv_init_hdr(&pkt
, lpcfg_rpc_big_endian(call
->conn
->dce_ctx
->lp_ctx
));
834 pkt
.call_id
= call
->pkt
.call_id
;
835 pkt
.ptype
= DCERPC_PKT_ALTER_RESP
;
836 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
837 pkt
.u
.alter_resp
.max_xmit_frag
= 0x2000;
838 pkt
.u
.alter_resp
.max_recv_frag
= 0x2000;
840 pkt
.u
.alter_resp
.assoc_group_id
= call
->context
->assoc_group
->id
;
842 pkt
.u
.alter_resp
.assoc_group_id
= 0;
844 pkt
.u
.alter_resp
.num_results
= 1;
845 pkt
.u
.alter_resp
.ctx_list
= talloc_array(call
, struct dcerpc_ack_ctx
, 1);
846 if (!pkt
.u
.alter_resp
.ctx_list
) {
847 return NT_STATUS_NO_MEMORY
;
849 pkt
.u
.alter_resp
.ctx_list
[0].result
= result
;
850 pkt
.u
.alter_resp
.ctx_list
[0].reason
= reason
;
851 pkt
.u
.alter_resp
.ctx_list
[0].syntax
= ndr_transfer_syntax_ndr
;
852 pkt
.u
.alter_resp
.auth_info
= data_blob(NULL
, 0);
853 pkt
.u
.alter_resp
.secondary_address
= "";
855 status
= dcesrv_auth_alter_ack(call
, &pkt
);
856 if (!NT_STATUS_IS_OK(status
)) {
857 if (NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)
858 || NT_STATUS_EQUAL(status
, NT_STATUS_LOGON_FAILURE
)
859 || NT_STATUS_EQUAL(status
, NT_STATUS_NO_SUCH_USER
)
860 || NT_STATUS_EQUAL(status
, NT_STATUS_WRONG_PASSWORD
)) {
861 return dcesrv_fault(call
, DCERPC_FAULT_ACCESS_DENIED
);
863 return dcesrv_fault(call
, 0);
866 rep
= talloc(call
, struct data_blob_list_item
);
868 return NT_STATUS_NO_MEMORY
;
871 status
= ncacn_push_auth(&rep
->blob
, call
, &pkt
, call
->conn
->auth_state
.auth_info
);
872 if (!NT_STATUS_IS_OK(status
)) {
876 dcerpc_set_frag_length(&rep
->blob
, rep
->blob
.length
);
878 DLIST_ADD_END(call
->replies
, rep
, struct data_blob_list_item
*);
879 dcesrv_call_set_list(call
, DCESRV_LIST_CALL_LIST
);
881 if (call
->conn
->call_list
&& call
->conn
->call_list
->replies
) {
882 if (call
->conn
->transport
.report_output_data
) {
883 call
->conn
->transport
.report_output_data(call
->conn
);
891 possibly save the call for inspection with ndrdump
893 static void dcesrv_save_call(struct dcesrv_call_state
*call
, const char *why
)
897 const char *dump_dir
;
898 dump_dir
= lpcfg_parm_string(call
->conn
->dce_ctx
->lp_ctx
, NULL
, "dcesrv", "stubs directory");
902 fname
= talloc_asprintf(call
, "%s/RPC-%s-%u-%s.dat",
904 call
->context
->iface
->name
,
905 call
->pkt
.u
.request
.opnum
,
907 if (file_save(fname
, call
->pkt
.u
.request
.stub_and_verifier
.data
, call
->pkt
.u
.request
.stub_and_verifier
.length
)) {
908 DEBUG(0,("RPC SAVED %s\n", fname
));
915 handle a dcerpc request packet
917 static NTSTATUS
dcesrv_request(struct dcesrv_call_state
*call
)
919 struct ndr_pull
*pull
;
921 struct dcesrv_connection_context
*context
;
923 /* if authenticated, and the mech we use can't do async replies, don't use them... */
924 if (call
->conn
->auth_state
.gensec_security
&&
925 !gensec_have_feature(call
->conn
->auth_state
.gensec_security
, GENSEC_FEATURE_ASYNC_REPLIES
)) {
926 call
->state_flags
&= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC
;
929 context
= dcesrv_find_context(call
->conn
, call
->pkt
.u
.request
.context_id
);
930 if (context
== NULL
) {
931 return dcesrv_fault(call
, DCERPC_FAULT_UNK_IF
);
934 pull
= ndr_pull_init_blob(&call
->pkt
.u
.request
.stub_and_verifier
, call
);
935 NT_STATUS_HAVE_NO_MEMORY(pull
);
937 pull
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
939 call
->context
= context
;
940 call
->ndr_pull
= pull
;
942 if (!(call
->pkt
.drep
[0] & DCERPC_DREP_LE
)) {
943 pull
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
946 /* unravel the NDR for the packet */
947 status
= context
->iface
->ndr_pull(call
, call
, pull
, &call
->r
);
948 if (!NT_STATUS_IS_OK(status
)) {
949 if (call
->fault_code
== DCERPC_FAULT_OP_RNG_ERROR
) {
950 /* we got an unknown call */
951 DEBUG(3,(__location__
": Unknown RPC call %u on %s\n",
952 call
->pkt
.u
.request
.opnum
, context
->iface
->name
));
953 dcesrv_save_call(call
, "unknown");
955 dcesrv_save_call(call
, "pullfail");
957 return dcesrv_fault(call
, call
->fault_code
);
960 if (pull
->offset
!= pull
->data_size
) {
961 dcesrv_save_call(call
, "extrabytes");
962 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
963 pull
->data_size
- pull
->offset
));
966 /* call the dispatch function */
967 status
= context
->iface
->dispatch(call
, call
, call
->r
);
968 if (!NT_STATUS_IS_OK(status
)) {
969 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
970 context
->iface
->name
,
971 call
->pkt
.u
.request
.opnum
,
972 dcerpc_errstr(pull
, call
->fault_code
)));
973 return dcesrv_fault(call
, call
->fault_code
);
976 /* add the call to the pending list */
977 dcesrv_call_set_list(call
, DCESRV_LIST_PENDING_CALL_LIST
);
979 if (call
->state_flags
& DCESRV_CALL_STATE_FLAG_ASYNC
) {
983 return dcesrv_reply(call
);
988 remove the call from the right list when freed
990 static int dcesrv_call_dequeue(struct dcesrv_call_state
*call
)
992 dcesrv_call_set_list(call
, DCESRV_LIST_NONE
);
996 _PUBLIC_
const struct tsocket_address
*dcesrv_connection_get_local_address(struct dcesrv_connection
*conn
)
998 return conn
->local_address
;
1001 _PUBLIC_
const struct tsocket_address
*dcesrv_connection_get_remote_address(struct dcesrv_connection
*conn
)
1003 return conn
->remote_address
;
1007 process some input to a dcerpc endpoint server.
1009 NTSTATUS
dcesrv_process_ncacn_packet(struct dcesrv_connection
*dce_conn
,
1010 struct ncacn_packet
*pkt
,
1014 struct dcesrv_call_state
*call
;
1016 call
= talloc_zero(dce_conn
, struct dcesrv_call_state
);
1018 data_blob_free(&blob
);
1020 return NT_STATUS_NO_MEMORY
;
1022 call
->conn
= dce_conn
;
1023 call
->event_ctx
= dce_conn
->event_ctx
;
1024 call
->msg_ctx
= dce_conn
->msg_ctx
;
1025 call
->state_flags
= call
->conn
->state_flags
;
1026 call
->time
= timeval_current();
1027 call
->list
= DCESRV_LIST_NONE
;
1029 talloc_steal(call
, pkt
);
1030 talloc_steal(call
, blob
.data
);
1033 talloc_set_destructor(call
, dcesrv_call_dequeue
);
1035 /* we have to check the signing here, before combining the
1037 if (call
->pkt
.ptype
== DCERPC_PKT_REQUEST
&&
1038 !dcesrv_auth_request(call
, &blob
)) {
1039 return dcesrv_fault(call
, DCERPC_FAULT_ACCESS_DENIED
);
1042 /* see if this is a continued packet */
1043 if (call
->pkt
.ptype
== DCERPC_PKT_REQUEST
&&
1044 !(call
->pkt
.pfc_flags
& DCERPC_PFC_FLAG_FIRST
)) {
1045 struct dcesrv_call_state
*call2
= call
;
1046 uint32_t alloc_size
;
1048 /* we only allow fragmented requests, no other packet types */
1049 if (call
->pkt
.ptype
!= DCERPC_PKT_REQUEST
) {
1050 return dcesrv_fault(call2
, DCERPC_FAULT_OTHER
);
1053 /* this is a continuation of an existing call - find the call
1054 then tack it on the end */
1055 call
= dcesrv_find_fragmented_call(dce_conn
, call2
->pkt
.call_id
);
1057 return dcesrv_fault(call2
, DCERPC_FAULT_OTHER
);
1060 if (call
->pkt
.ptype
!= call2
->pkt
.ptype
) {
1061 /* trying to play silly buggers are we? */
1062 return dcesrv_fault(call2
, DCERPC_FAULT_OTHER
);
1065 alloc_size
= call
->pkt
.u
.request
.stub_and_verifier
.length
+
1066 call2
->pkt
.u
.request
.stub_and_verifier
.length
;
1067 if (call
->pkt
.u
.request
.alloc_hint
> alloc_size
) {
1068 alloc_size
= call
->pkt
.u
.request
.alloc_hint
;
1071 call
->pkt
.u
.request
.stub_and_verifier
.data
=
1072 talloc_realloc(call
,
1073 call
->pkt
.u
.request
.stub_and_verifier
.data
,
1074 uint8_t, alloc_size
);
1075 if (!call
->pkt
.u
.request
.stub_and_verifier
.data
) {
1076 return dcesrv_fault(call2
, DCERPC_FAULT_OTHER
);
1078 memcpy(call
->pkt
.u
.request
.stub_and_verifier
.data
+
1079 call
->pkt
.u
.request
.stub_and_verifier
.length
,
1080 call2
->pkt
.u
.request
.stub_and_verifier
.data
,
1081 call2
->pkt
.u
.request
.stub_and_verifier
.length
);
1082 call
->pkt
.u
.request
.stub_and_verifier
.length
+=
1083 call2
->pkt
.u
.request
.stub_and_verifier
.length
;
1085 call
->pkt
.pfc_flags
|= (call2
->pkt
.pfc_flags
& DCERPC_PFC_FLAG_LAST
);
1090 /* this may not be the last pdu in the chain - if its isn't then
1091 just put it on the incoming_fragmented_call_list and wait for the rest */
1092 if (call
->pkt
.ptype
== DCERPC_PKT_REQUEST
&&
1093 !(call
->pkt
.pfc_flags
& DCERPC_PFC_FLAG_LAST
)) {
1094 dcesrv_call_set_list(call
, DCESRV_LIST_FRAGMENTED_CALL_LIST
);
1095 return NT_STATUS_OK
;
1098 /* This removes any fragments we may have had stashed away */
1099 dcesrv_call_set_list(call
, DCESRV_LIST_NONE
);
1101 switch (call
->pkt
.ptype
) {
1102 case DCERPC_PKT_BIND
:
1103 status
= dcesrv_bind(call
);
1105 case DCERPC_PKT_AUTH3
:
1106 status
= dcesrv_auth3(call
);
1108 case DCERPC_PKT_ALTER
:
1109 status
= dcesrv_alter(call
);
1111 case DCERPC_PKT_REQUEST
:
1112 status
= dcesrv_request(call
);
1115 status
= NT_STATUS_INVALID_PARAMETER
;
1119 /* if we are going to be sending a reply then add
1120 it to the list of pending calls. We add it to the end to keep the call
1121 list in the order we will answer */
1122 if (!NT_STATUS_IS_OK(status
)) {
1129 _PUBLIC_ NTSTATUS
dcesrv_init_context(TALLOC_CTX
*mem_ctx
,
1130 struct loadparm_context
*lp_ctx
,
1131 const char **endpoint_servers
, struct dcesrv_context
**_dce_ctx
)
1134 struct dcesrv_context
*dce_ctx
;
1137 if (!endpoint_servers
) {
1138 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1139 return NT_STATUS_INTERNAL_ERROR
;
1142 dce_ctx
= talloc(mem_ctx
, struct dcesrv_context
);
1143 NT_STATUS_HAVE_NO_MEMORY(dce_ctx
);
1144 dce_ctx
->endpoint_list
= NULL
;
1145 dce_ctx
->lp_ctx
= lp_ctx
;
1146 dce_ctx
->assoc_groups_idr
= idr_init(dce_ctx
);
1147 NT_STATUS_HAVE_NO_MEMORY(dce_ctx
->assoc_groups_idr
);
1148 dce_ctx
->broken_connections
= NULL
;
1150 for (i
=0;endpoint_servers
[i
];i
++) {
1151 const struct dcesrv_endpoint_server
*ep_server
;
1153 ep_server
= dcesrv_ep_server_byname(endpoint_servers
[i
]);
1155 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers
[i
]));
1156 return NT_STATUS_INTERNAL_ERROR
;
1159 status
= ep_server
->init_server(dce_ctx
, ep_server
);
1160 if (!NT_STATUS_IS_OK(status
)) {
1161 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers
[i
],
1162 nt_errstr(status
)));
1167 *_dce_ctx
= dce_ctx
;
1168 return NT_STATUS_OK
;
1171 /* the list of currently registered DCERPC endpoint servers.
1173 static struct ep_server
{
1174 struct dcesrv_endpoint_server
*ep_server
;
1175 } *ep_servers
= NULL
;
1176 static int num_ep_servers
;
1179 register a DCERPC endpoint server.
1181 The 'name' can be later used by other backends to find the operations
1182 structure for this backend.
1184 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1186 _PUBLIC_ NTSTATUS
dcerpc_register_ep_server(const void *_ep_server
)
1188 const struct dcesrv_endpoint_server
*ep_server
= _ep_server
;
1190 if (dcesrv_ep_server_byname(ep_server
->name
) != NULL
) {
1191 /* its already registered! */
1192 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1194 return NT_STATUS_OBJECT_NAME_COLLISION
;
1197 ep_servers
= realloc_p(ep_servers
, struct ep_server
, num_ep_servers
+1);
1199 smb_panic("out of memory in dcerpc_register");
1202 ep_servers
[num_ep_servers
].ep_server
= smb_xmemdup(ep_server
, sizeof(*ep_server
));
1203 ep_servers
[num_ep_servers
].ep_server
->name
= smb_xstrdup(ep_server
->name
);
1207 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1210 return NT_STATUS_OK
;
1214 return the operations structure for a named backend of the specified type
1216 const struct dcesrv_endpoint_server
*dcesrv_ep_server_byname(const char *name
)
1220 for (i
=0;i
<num_ep_servers
;i
++) {
1221 if (strcmp(ep_servers
[i
].ep_server
->name
, name
) == 0) {
1222 return ep_servers
[i
].ep_server
;
1229 void dcerpc_server_init(struct loadparm_context
*lp_ctx
)
1231 static bool initialized
;
1232 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
1233 STATIC_dcerpc_server_MODULES_PROTO
;
1234 init_module_fn static_init
[] = { STATIC_dcerpc_server_MODULES
};
1235 init_module_fn
*shared_init
;
1242 shared_init
= load_samba_modules(NULL
, "dcerpc_server");
1244 run_init_functions(static_init
);
1245 run_init_functions(shared_init
);
1247 talloc_free(shared_init
);
1251 return the DCERPC module version, and the size of some critical types
1252 This can be used by endpoint server modules to either detect compilation errors, or provide
1253 multiple implementations for different smbd compilation options in one module
1255 const struct dcesrv_critical_sizes
*dcerpc_module_version(void)
1257 static const struct dcesrv_critical_sizes critical_sizes
= {
1258 DCERPC_MODULE_VERSION
,
1259 sizeof(struct dcesrv_context
),
1260 sizeof(struct dcesrv_endpoint
),
1261 sizeof(struct dcesrv_endpoint_server
),
1262 sizeof(struct dcesrv_interface
),
1263 sizeof(struct dcesrv_if_list
),
1264 sizeof(struct dcesrv_connection
),
1265 sizeof(struct dcesrv_call_state
),
1266 sizeof(struct dcesrv_auth
),
1267 sizeof(struct dcesrv_handle
)
1270 return &critical_sizes
;
1273 static void dcesrv_terminate_connection(struct dcesrv_connection
*dce_conn
, const char *reason
)
1275 struct dcesrv_context
*dce_ctx
= dce_conn
->dce_ctx
;
1276 struct stream_connection
*srv_conn
;
1277 srv_conn
= talloc_get_type(dce_conn
->transport
.private_data
,
1278 struct stream_connection
);
1280 if (dce_conn
->pending_call_list
== NULL
) {
1281 char *full_reason
= talloc_asprintf(dce_conn
, "dcesrv: %s", reason
);
1283 DLIST_REMOVE(dce_ctx
->broken_connections
, dce_conn
);
1284 stream_terminate_connection(srv_conn
, full_reason
? full_reason
: reason
);
1288 if (dce_conn
->terminate
!= NULL
) {
1292 DEBUG(3,("dcesrv: terminating connection due to '%s' defered due to pending calls\n",
1294 dce_conn
->terminate
= talloc_strdup(dce_conn
, reason
);
1295 if (dce_conn
->terminate
== NULL
) {
1296 dce_conn
->terminate
= "dcesrv: defered terminating connection - no memory";
1298 DLIST_ADD_END(dce_ctx
->broken_connections
, dce_conn
, NULL
);
1301 static void dcesrv_cleanup_broken_connections(struct dcesrv_context
*dce_ctx
)
1303 struct dcesrv_connection
*cur
, *next
;
1305 next
= dce_ctx
->broken_connections
;
1306 while (next
!= NULL
) {
1310 dcesrv_terminate_connection(cur
, cur
->terminate
);
1314 /* We need this include to be able to compile on some plateforms
1315 * (ie. freebsd 7.2) as it seems that <sys/uio.h> is not included
1317 * It has to be that deep because otherwise we have a conflict on
1318 * const struct dcesrv_interface declaration.
1319 * This is mostly due to socket_wrapper defining #define bind swrap_bind
1320 * which conflict with the bind used before.
1322 #include "system/network.h"
1324 struct dcesrv_sock_reply_state
{
1325 struct dcesrv_connection
*dce_conn
;
1326 struct dcesrv_call_state
*call
;
1330 static void dcesrv_sock_reply_done(struct tevent_req
*subreq
);
1332 static void dcesrv_sock_report_output_data(struct dcesrv_connection
*dce_conn
)
1334 struct dcesrv_call_state
*call
;
1336 call
= dce_conn
->call_list
;
1337 if (!call
|| !call
->replies
) {
1341 while (call
->replies
) {
1342 struct data_blob_list_item
*rep
= call
->replies
;
1343 struct dcesrv_sock_reply_state
*substate
;
1344 struct tevent_req
*subreq
;
1346 substate
= talloc(call
, struct dcesrv_sock_reply_state
);
1348 dcesrv_terminate_connection(dce_conn
, "no memory");
1352 substate
->dce_conn
= dce_conn
;
1353 substate
->call
= NULL
;
1355 DLIST_REMOVE(call
->replies
, rep
);
1357 if (call
->replies
== NULL
) {
1358 substate
->call
= call
;
1361 substate
->iov
.iov_base
= (void *) rep
->blob
.data
;
1362 substate
->iov
.iov_len
= rep
->blob
.length
;
1364 subreq
= tstream_writev_queue_send(substate
,
1365 dce_conn
->event_ctx
,
1367 dce_conn
->send_queue
,
1370 dcesrv_terminate_connection(dce_conn
, "no memory");
1373 tevent_req_set_callback(subreq
, dcesrv_sock_reply_done
,
1377 DLIST_REMOVE(call
->conn
->call_list
, call
);
1378 call
->list
= DCESRV_LIST_NONE
;
1381 static void dcesrv_sock_reply_done(struct tevent_req
*subreq
)
1383 struct dcesrv_sock_reply_state
*substate
= tevent_req_callback_data(subreq
,
1384 struct dcesrv_sock_reply_state
);
1388 struct dcesrv_call_state
*call
= substate
->call
;
1390 ret
= tstream_writev_queue_recv(subreq
, &sys_errno
);
1391 TALLOC_FREE(subreq
);
1393 status
= map_nt_error_from_unix_common(sys_errno
);
1394 dcesrv_terminate_connection(substate
->dce_conn
, nt_errstr(status
));
1398 talloc_free(substate
);
1407 struct dcesrv_socket_context
{
1408 const struct dcesrv_endpoint
*endpoint
;
1409 struct dcesrv_context
*dcesrv_ctx
;
1413 static void dcesrv_read_fragment_done(struct tevent_req
*subreq
);
1415 static void dcesrv_sock_accept(struct stream_connection
*srv_conn
)
1418 struct dcesrv_socket_context
*dcesrv_sock
=
1419 talloc_get_type(srv_conn
->private_data
, struct dcesrv_socket_context
);
1420 struct dcesrv_connection
*dcesrv_conn
= NULL
;
1422 struct tevent_req
*subreq
;
1423 struct loadparm_context
*lp_ctx
= dcesrv_sock
->dcesrv_ctx
->lp_ctx
;
1425 dcesrv_cleanup_broken_connections(dcesrv_sock
->dcesrv_ctx
);
1427 if (!srv_conn
->session_info
) {
1428 status
= auth_anonymous_session_info(srv_conn
,
1430 &srv_conn
->session_info
);
1431 if (!NT_STATUS_IS_OK(status
)) {
1432 DEBUG(0,("dcesrv_sock_accept: auth_anonymous_session_info failed: %s\n",
1433 nt_errstr(status
)));
1434 stream_terminate_connection(srv_conn
, nt_errstr(status
));
1439 status
= dcesrv_endpoint_connect(dcesrv_sock
->dcesrv_ctx
,
1441 dcesrv_sock
->endpoint
,
1442 srv_conn
->session_info
,
1443 srv_conn
->event
.ctx
,
1445 srv_conn
->server_id
,
1446 DCESRV_CALL_STATE_FLAG_MAY_ASYNC
,
1448 if (!NT_STATUS_IS_OK(status
)) {
1449 DEBUG(0,("dcesrv_sock_accept: dcesrv_endpoint_connect failed: %s\n",
1450 nt_errstr(status
)));
1451 stream_terminate_connection(srv_conn
, nt_errstr(status
));
1455 dcesrv_conn
->transport
.private_data
= srv_conn
;
1456 dcesrv_conn
->transport
.report_output_data
= dcesrv_sock_report_output_data
;
1458 TALLOC_FREE(srv_conn
->event
.fde
);
1460 dcesrv_conn
->send_queue
= tevent_queue_create(dcesrv_conn
, "dcesrv send queue");
1461 if (!dcesrv_conn
->send_queue
) {
1462 status
= NT_STATUS_NO_MEMORY
;
1463 DEBUG(0,("dcesrv_sock_accept: tevent_queue_create(%s)\n",
1464 nt_errstr(status
)));
1465 stream_terminate_connection(srv_conn
, nt_errstr(status
));
1469 if (dcesrv_sock
->endpoint
->ep_description
->transport
== NCACN_NP
) {
1470 dcesrv_conn
->auth_state
.session_key
= dcesrv_inherited_session_key
;
1471 dcesrv_conn
->stream
= talloc_move(dcesrv_conn
,
1472 &srv_conn
->tstream
);
1474 ret
= tstream_bsd_existing_socket(dcesrv_conn
,
1475 socket_get_fd(srv_conn
->socket
),
1476 &dcesrv_conn
->stream
);
1478 status
= map_nt_error_from_unix_common(errno
);
1479 DEBUG(0, ("dcesrv_sock_accept: "
1480 "failed to setup tstream: %s\n",
1481 nt_errstr(status
)));
1482 stream_terminate_connection(srv_conn
, nt_errstr(status
));
1485 socket_set_flags(srv_conn
->socket
, SOCKET_FLAG_NOCLOSE
);
1488 dcesrv_conn
->local_address
= srv_conn
->local_address
;
1489 dcesrv_conn
->remote_address
= srv_conn
->remote_address
;
1491 srv_conn
->private_data
= dcesrv_conn
;
1493 irpc_add_name(srv_conn
->msg_ctx
, "rpc_server");
1495 subreq
= dcerpc_read_ncacn_packet_send(dcesrv_conn
,
1496 dcesrv_conn
->event_ctx
,
1497 dcesrv_conn
->stream
);
1499 status
= NT_STATUS_NO_MEMORY
;
1500 DEBUG(0,("dcesrv_sock_accept: dcerpc_read_fragment_buffer_send(%s)\n",
1501 nt_errstr(status
)));
1502 stream_terminate_connection(srv_conn
, nt_errstr(status
));
1505 tevent_req_set_callback(subreq
, dcesrv_read_fragment_done
, dcesrv_conn
);
1510 static void dcesrv_read_fragment_done(struct tevent_req
*subreq
)
1512 struct dcesrv_connection
*dce_conn
= tevent_req_callback_data(subreq
,
1513 struct dcesrv_connection
);
1514 struct dcesrv_context
*dce_ctx
= dce_conn
->dce_ctx
;
1515 struct ncacn_packet
*pkt
;
1519 if (dce_conn
->terminate
) {
1521 * if the current connection is broken
1522 * we need to clean it up before any other connection
1524 dcesrv_terminate_connection(dce_conn
, dce_conn
->terminate
);
1525 dcesrv_cleanup_broken_connections(dce_ctx
);
1529 dcesrv_cleanup_broken_connections(dce_ctx
);
1531 status
= dcerpc_read_ncacn_packet_recv(subreq
, dce_conn
,
1533 TALLOC_FREE(subreq
);
1534 if (!NT_STATUS_IS_OK(status
)) {
1535 dcesrv_terminate_connection(dce_conn
, nt_errstr(status
));
1539 status
= dcesrv_process_ncacn_packet(dce_conn
, pkt
, buffer
);
1540 if (!NT_STATUS_IS_OK(status
)) {
1541 dcesrv_terminate_connection(dce_conn
, nt_errstr(status
));
1545 subreq
= dcerpc_read_ncacn_packet_send(dce_conn
,
1546 dce_conn
->event_ctx
,
1549 status
= NT_STATUS_NO_MEMORY
;
1550 dcesrv_terminate_connection(dce_conn
, nt_errstr(status
));
1553 tevent_req_set_callback(subreq
, dcesrv_read_fragment_done
, dce_conn
);
1556 static void dcesrv_sock_recv(struct stream_connection
*conn
, uint16_t flags
)
1558 struct dcesrv_connection
*dce_conn
= talloc_get_type(conn
->private_data
,
1559 struct dcesrv_connection
);
1560 dcesrv_terminate_connection(dce_conn
, "dcesrv_sock_recv triggered");
1563 static void dcesrv_sock_send(struct stream_connection
*conn
, uint16_t flags
)
1565 struct dcesrv_connection
*dce_conn
= talloc_get_type(conn
->private_data
,
1566 struct dcesrv_connection
);
1567 dcesrv_terminate_connection(dce_conn
, "dcesrv_sock_send triggered");
1571 static const struct stream_server_ops dcesrv_stream_ops
= {
1573 .accept_connection
= dcesrv_sock_accept
,
1574 .recv_handler
= dcesrv_sock_recv
,
1575 .send_handler
= dcesrv_sock_send
,
1578 static NTSTATUS
dcesrv_add_ep_unix(struct dcesrv_context
*dce_ctx
,
1579 struct loadparm_context
*lp_ctx
,
1580 struct dcesrv_endpoint
*e
,
1581 struct tevent_context
*event_ctx
, const struct model_ops
*model_ops
)
1583 struct dcesrv_socket_context
*dcesrv_sock
;
1587 dcesrv_sock
= talloc(event_ctx
, struct dcesrv_socket_context
);
1588 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock
);
1590 /* remember the endpoint of this socket */
1591 dcesrv_sock
->endpoint
= e
;
1592 dcesrv_sock
->dcesrv_ctx
= talloc_reference(dcesrv_sock
, dce_ctx
);
1594 status
= stream_setup_socket(dcesrv_sock
, event_ctx
, lp_ctx
,
1595 model_ops
, &dcesrv_stream_ops
,
1596 "unix", e
->ep_description
->endpoint
, &port
,
1597 lpcfg_socket_options(lp_ctx
),
1599 if (!NT_STATUS_IS_OK(status
)) {
1600 DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n",
1601 e
->ep_description
->endpoint
, nt_errstr(status
)));
1607 static NTSTATUS
dcesrv_add_ep_ncalrpc(struct dcesrv_context
*dce_ctx
,
1608 struct loadparm_context
*lp_ctx
,
1609 struct dcesrv_endpoint
*e
,
1610 struct tevent_context
*event_ctx
, const struct model_ops
*model_ops
)
1612 struct dcesrv_socket_context
*dcesrv_sock
;
1617 if (!e
->ep_description
->endpoint
) {
1618 /* No identifier specified: use DEFAULT.
1619 * DO NOT hardcode this value anywhere else. Rather, specify
1620 * no endpoint and let the epmapper worry about it. */
1621 e
->ep_description
->endpoint
= talloc_strdup(dce_ctx
, "DEFAULT");
1624 full_path
= talloc_asprintf(dce_ctx
, "%s/%s", lpcfg_ncalrpc_dir(lp_ctx
),
1625 e
->ep_description
->endpoint
);
1627 dcesrv_sock
= talloc(event_ctx
, struct dcesrv_socket_context
);
1628 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock
);
1630 /* remember the endpoint of this socket */
1631 dcesrv_sock
->endpoint
= e
;
1632 dcesrv_sock
->dcesrv_ctx
= talloc_reference(dcesrv_sock
, dce_ctx
);
1634 status
= stream_setup_socket(dcesrv_sock
, event_ctx
, lp_ctx
,
1635 model_ops
, &dcesrv_stream_ops
,
1636 "unix", full_path
, &port
,
1637 lpcfg_socket_options(lp_ctx
),
1639 if (!NT_STATUS_IS_OK(status
)) {
1640 DEBUG(0,("service_setup_stream_socket(identifier=%s,path=%s) failed - %s\n",
1641 e
->ep_description
->endpoint
, full_path
, nt_errstr(status
)));
1646 static NTSTATUS
dcesrv_add_ep_np(struct dcesrv_context
*dce_ctx
,
1647 struct loadparm_context
*lp_ctx
,
1648 struct dcesrv_endpoint
*e
,
1649 struct tevent_context
*event_ctx
, const struct model_ops
*model_ops
)
1651 struct dcesrv_socket_context
*dcesrv_sock
;
1654 if (e
->ep_description
->endpoint
== NULL
) {
1655 DEBUG(0, ("Endpoint mandatory for named pipes\n"));
1656 return NT_STATUS_INVALID_PARAMETER
;
1659 dcesrv_sock
= talloc(event_ctx
, struct dcesrv_socket_context
);
1660 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock
);
1662 /* remember the endpoint of this socket */
1663 dcesrv_sock
->endpoint
= e
;
1664 dcesrv_sock
->dcesrv_ctx
= talloc_reference(dcesrv_sock
, dce_ctx
);
1666 status
= tstream_setup_named_pipe(dce_ctx
, event_ctx
, lp_ctx
,
1667 model_ops
, &dcesrv_stream_ops
,
1668 e
->ep_description
->endpoint
,
1670 if (!NT_STATUS_IS_OK(status
)) {
1671 DEBUG(0,("stream_setup_named_pipe(pipe=%s) failed - %s\n",
1672 e
->ep_description
->endpoint
, nt_errstr(status
)));
1676 return NT_STATUS_OK
;
1680 add a socket address to the list of events, one event per dcerpc endpoint
1682 static NTSTATUS
add_socket_rpc_tcp_iface(struct dcesrv_context
*dce_ctx
, struct dcesrv_endpoint
*e
,
1683 struct tevent_context
*event_ctx
, const struct model_ops
*model_ops
,
1684 const char *address
)
1686 struct dcesrv_socket_context
*dcesrv_sock
;
1690 if (e
->ep_description
->endpoint
) {
1691 port
= atoi(e
->ep_description
->endpoint
);
1694 dcesrv_sock
= talloc(event_ctx
, struct dcesrv_socket_context
);
1695 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock
);
1697 /* remember the endpoint of this socket */
1698 dcesrv_sock
->endpoint
= e
;
1699 dcesrv_sock
->dcesrv_ctx
= talloc_reference(dcesrv_sock
, dce_ctx
);
1701 status
= stream_setup_socket(dcesrv_sock
, event_ctx
, dce_ctx
->lp_ctx
,
1702 model_ops
, &dcesrv_stream_ops
,
1703 "ip", address
, &port
,
1704 lpcfg_socket_options(dce_ctx
->lp_ctx
),
1706 if (!NT_STATUS_IS_OK(status
)) {
1707 DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) failed - %s\n",
1708 address
, port
, nt_errstr(status
)));
1711 if (e
->ep_description
->endpoint
== NULL
) {
1712 e
->ep_description
->endpoint
= talloc_asprintf(dce_ctx
, "%d", port
);
1718 #include "lib/socket/netif.h" /* Included here to work around the fact that socket_wrapper redefines bind() */
1720 static NTSTATUS
dcesrv_add_ep_tcp(struct dcesrv_context
*dce_ctx
,
1721 struct loadparm_context
*lp_ctx
,
1722 struct dcesrv_endpoint
*e
,
1723 struct tevent_context
*event_ctx
, const struct model_ops
*model_ops
)
1727 /* Add TCP/IP sockets */
1728 if (lpcfg_interfaces(lp_ctx
) && lpcfg_bind_interfaces_only(lp_ctx
)) {
1731 struct interface
*ifaces
;
1733 load_interface_list(dce_ctx
, lp_ctx
, &ifaces
);
1735 num_interfaces
= iface_list_count(ifaces
);
1736 for(i
= 0; i
< num_interfaces
; i
++) {
1737 const char *address
= iface_list_n_ip(ifaces
, i
);
1738 status
= add_socket_rpc_tcp_iface(dce_ctx
, e
, event_ctx
, model_ops
, address
);
1739 NT_STATUS_NOT_OK_RETURN(status
);
1744 wcard
= iface_list_wildcard(dce_ctx
, lp_ctx
);
1745 NT_STATUS_HAVE_NO_MEMORY(wcard
);
1746 for (i
=0; wcard
[i
]; i
++) {
1747 status
= add_socket_rpc_tcp_iface(dce_ctx
, e
, event_ctx
, model_ops
, wcard
[i
]);
1748 NT_STATUS_NOT_OK_RETURN(status
);
1753 return NT_STATUS_OK
;
1756 NTSTATUS
dcesrv_add_ep(struct dcesrv_context
*dce_ctx
,
1757 struct loadparm_context
*lp_ctx
,
1758 struct dcesrv_endpoint
*e
,
1759 struct tevent_context
*event_ctx
,
1760 const struct model_ops
*model_ops
)
1762 switch (e
->ep_description
->transport
) {
1763 case NCACN_UNIX_STREAM
:
1764 return dcesrv_add_ep_unix(dce_ctx
, lp_ctx
, e
, event_ctx
, model_ops
);
1767 return dcesrv_add_ep_ncalrpc(dce_ctx
, lp_ctx
, e
, event_ctx
, model_ops
);
1770 return dcesrv_add_ep_tcp(dce_ctx
, lp_ctx
, e
, event_ctx
, model_ops
);
1773 return dcesrv_add_ep_np(dce_ctx
, lp_ctx
, e
, event_ctx
, model_ops
);
1776 return NT_STATUS_NOT_SUPPORTED
;
1782 * retrieve credentials from a dce_call
1784 _PUBLIC_
struct cli_credentials
*dcesrv_call_credentials(struct dcesrv_call_state
*dce_call
)
1786 return dce_call
->conn
->auth_state
.session_info
->credentials
;
1790 * returns true if this is an authenticated call
1792 _PUBLIC_
bool dcesrv_call_authenticated(struct dcesrv_call_state
*dce_call
)
1794 enum security_user_level level
;
1795 level
= security_session_user_level(dce_call
->conn
->auth_state
.session_info
, NULL
);
1796 return level
>= SECURITY_USER
;
1800 * retrieve account_name for a dce_call
1802 _PUBLIC_
const char *dcesrv_call_account_name(struct dcesrv_call_state
*dce_call
)
1804 return dce_call
->context
->conn
->auth_state
.session_info
->info
->account_name
;