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"
43 #include "librpc/gen_ndr/ndr_dcerpc.h"
45 /* this is only used when the client asks for an unknown interface */
46 #define DUMMY_ASSOC_GROUP 0x0FFFFFFF
48 extern const struct dcesrv_interface dcesrv_mgmt_interface
;
52 find an association group given a assoc_group_id
54 static struct dcesrv_assoc_group
*dcesrv_assoc_group_find(struct dcesrv_context
*dce_ctx
,
59 id_ptr
= idr_find(dce_ctx
->assoc_groups_idr
, id
);
63 return talloc_get_type_abort(id_ptr
, struct dcesrv_assoc_group
);
67 take a reference to an existing association group
69 static struct dcesrv_assoc_group
*dcesrv_assoc_group_reference(TALLOC_CTX
*mem_ctx
,
70 struct dcesrv_context
*dce_ctx
,
73 struct dcesrv_assoc_group
*assoc_group
;
75 assoc_group
= dcesrv_assoc_group_find(dce_ctx
, id
);
76 if (assoc_group
== NULL
) {
77 DEBUG(0,(__location__
": Failed to find assoc_group 0x%08x\n", id
));
80 return talloc_reference(mem_ctx
, assoc_group
);
83 static int dcesrv_assoc_group_destructor(struct dcesrv_assoc_group
*assoc_group
)
86 ret
= idr_remove(assoc_group
->dce_ctx
->assoc_groups_idr
, assoc_group
->id
);
88 DEBUG(0,(__location__
": Failed to remove assoc_group 0x%08x\n",
95 allocate a new association group
97 static struct dcesrv_assoc_group
*dcesrv_assoc_group_new(TALLOC_CTX
*mem_ctx
,
98 struct dcesrv_context
*dce_ctx
)
100 struct dcesrv_assoc_group
*assoc_group
;
103 assoc_group
= talloc_zero(mem_ctx
, struct dcesrv_assoc_group
);
104 if (assoc_group
== NULL
) {
108 id
= idr_get_new_random(dce_ctx
->assoc_groups_idr
, assoc_group
, UINT16_MAX
);
110 talloc_free(assoc_group
);
111 DEBUG(0,(__location__
": Out of association groups!\n"));
115 assoc_group
->id
= id
;
116 assoc_group
->dce_ctx
= dce_ctx
;
118 talloc_set_destructor(assoc_group
, dcesrv_assoc_group_destructor
);
125 see if two endpoints match
127 static bool endpoints_match(const struct dcerpc_binding
*ep1
,
128 const struct dcerpc_binding
*ep2
)
130 enum dcerpc_transport_t t1
;
131 enum dcerpc_transport_t t2
;
135 t1
= dcerpc_binding_get_transport(ep1
);
136 t2
= dcerpc_binding_get_transport(ep2
);
138 e1
= dcerpc_binding_get_string_option(ep1
, "endpoint");
139 e2
= dcerpc_binding_get_string_option(ep2
, "endpoint");
149 if (strcasecmp(e1
, e2
) != 0) {
157 find an endpoint in the dcesrv_context
159 static struct dcesrv_endpoint
*find_endpoint(struct dcesrv_context
*dce_ctx
,
160 const struct dcerpc_binding
*ep_description
)
162 struct dcesrv_endpoint
*ep
;
163 for (ep
=dce_ctx
->endpoint_list
; ep
; ep
=ep
->next
) {
164 if (endpoints_match(ep
->ep_description
, ep_description
)) {
172 find a registered context_id from a bind or alter_context
174 static struct dcesrv_connection_context
*dcesrv_find_context(struct dcesrv_connection
*conn
,
177 struct dcesrv_connection_context
*c
;
178 for (c
=conn
->contexts
;c
;c
=c
->next
) {
179 if (c
->context_id
== context_id
) return c
;
185 see if a uuid and if_version match to an interface
187 static bool interface_match(const struct dcesrv_interface
*if1
,
188 const struct dcesrv_interface
*if2
)
190 return (if1
->syntax_id
.if_version
== if2
->syntax_id
.if_version
&&
191 GUID_equal(&if1
->syntax_id
.uuid
, &if2
->syntax_id
.uuid
));
195 find the interface operations on an endpoint
197 static const struct dcesrv_interface
*find_interface(const struct dcesrv_endpoint
*endpoint
,
198 const struct dcesrv_interface
*iface
)
200 struct dcesrv_if_list
*ifl
;
201 for (ifl
=endpoint
->interface_list
; ifl
; ifl
=ifl
->next
) {
202 if (interface_match(&(ifl
->iface
), iface
)) {
203 return &(ifl
->iface
);
210 see if a uuid and if_version match to an interface
212 static bool interface_match_by_uuid(const struct dcesrv_interface
*iface
,
213 const struct GUID
*uuid
, uint32_t if_version
)
215 return (iface
->syntax_id
.if_version
== if_version
&&
216 GUID_equal(&iface
->syntax_id
.uuid
, uuid
));
220 find the interface operations on an endpoint by uuid
222 static const struct dcesrv_interface
*find_interface_by_uuid(const struct dcesrv_endpoint
*endpoint
,
223 const struct GUID
*uuid
, uint32_t if_version
)
225 struct dcesrv_if_list
*ifl
;
226 for (ifl
=endpoint
->interface_list
; ifl
; ifl
=ifl
->next
) {
227 if (interface_match_by_uuid(&(ifl
->iface
), uuid
, if_version
)) {
228 return &(ifl
->iface
);
235 find the earlier parts of a fragmented call awaiting reassembily
237 static struct dcesrv_call_state
*dcesrv_find_fragmented_call(struct dcesrv_connection
*dce_conn
, uint16_t call_id
)
239 struct dcesrv_call_state
*c
;
240 for (c
=dce_conn
->incoming_fragmented_call_list
;c
;c
=c
->next
) {
241 if (c
->pkt
.call_id
== call_id
) {
249 register an interface on an endpoint
251 _PUBLIC_ NTSTATUS
dcesrv_interface_register(struct dcesrv_context
*dce_ctx
,
253 const struct dcesrv_interface
*iface
,
254 const struct security_descriptor
*sd
)
256 struct dcesrv_endpoint
*ep
;
257 struct dcesrv_if_list
*ifl
;
258 struct dcerpc_binding
*binding
;
262 status
= dcerpc_parse_binding(dce_ctx
, ep_name
, &binding
);
264 if (NT_STATUS_IS_ERR(status
)) {
265 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name
));
269 /* check if this endpoint exists
271 if ((ep
=find_endpoint(dce_ctx
, binding
))==NULL
) {
272 ep
= talloc(dce_ctx
, struct dcesrv_endpoint
);
274 return NT_STATUS_NO_MEMORY
;
277 ep
->ep_description
= talloc_move(ep
, &binding
);
280 /* add mgmt interface */
281 ifl
= talloc(ep
, struct dcesrv_if_list
);
283 return NT_STATUS_NO_MEMORY
;
286 memcpy(&(ifl
->iface
), &dcesrv_mgmt_interface
,
287 sizeof(struct dcesrv_interface
));
289 DLIST_ADD(ep
->interface_list
, ifl
);
292 /* see if the interface is already registered on te endpoint */
293 if (find_interface(ep
, iface
)!=NULL
) {
294 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
295 iface
->name
, ep_name
));
296 return NT_STATUS_OBJECT_NAME_COLLISION
;
299 /* talloc a new interface list element */
300 ifl
= talloc(ep
, struct dcesrv_if_list
);
302 return NT_STATUS_NO_MEMORY
;
305 /* copy the given interface struct to the one on the endpoints interface list */
306 memcpy(&(ifl
->iface
),iface
, sizeof(struct dcesrv_interface
));
308 /* if we have a security descriptor given,
309 * we should see if we can set it up on the endpoint
312 /* if there's currently no security descriptor given on the endpoint
315 if (ep
->sd
== NULL
) {
316 ep
->sd
= security_descriptor_copy(ep
, sd
);
319 /* if now there's no security descriptor given on the endpoint
320 * something goes wrong, either we failed to copy the security descriptor
321 * or there was already one on the endpoint
323 if (ep
->sd
!= NULL
) {
324 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
325 " on endpoint '%s'\n",
326 iface
->name
, ep_name
));
327 if (add_ep
) free(ep
);
329 return NT_STATUS_OBJECT_NAME_COLLISION
;
333 /* finally add the interface on the endpoint */
334 DLIST_ADD(ep
->interface_list
, ifl
);
336 /* if it's a new endpoint add it to the dcesrv_context */
338 DLIST_ADD(dce_ctx
->endpoint_list
, ep
);
341 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
342 iface
->name
, ep_name
));
347 NTSTATUS
dcesrv_inherited_session_key(struct dcesrv_connection
*p
,
348 DATA_BLOB
*session_key
)
350 if (p
->auth_state
.session_info
->session_key
.length
) {
351 *session_key
= p
->auth_state
.session_info
->session_key
;
354 return NT_STATUS_NO_USER_SESSION_KEY
;
358 fetch the user session key - may be default (above) or the SMB session key
360 The key is always truncated to 16 bytes
362 _PUBLIC_ NTSTATUS
dcesrv_fetch_session_key(struct dcesrv_connection
*p
,
363 DATA_BLOB
*session_key
)
365 NTSTATUS status
= p
->auth_state
.session_key(p
, session_key
);
366 if (!NT_STATUS_IS_OK(status
)) {
370 session_key
->length
= MIN(session_key
->length
, 16);
376 connect to a dcerpc endpoint
378 _PUBLIC_ NTSTATUS
dcesrv_endpoint_connect(struct dcesrv_context
*dce_ctx
,
380 const struct dcesrv_endpoint
*ep
,
381 struct auth_session_info
*session_info
,
382 struct tevent_context
*event_ctx
,
383 struct imessaging_context
*msg_ctx
,
384 struct server_id server_id
,
385 uint32_t state_flags
,
386 struct dcesrv_connection
**_p
)
388 struct dcesrv_connection
*p
;
391 return NT_STATUS_ACCESS_DENIED
;
394 p
= talloc_zero(mem_ctx
, struct dcesrv_connection
);
395 NT_STATUS_HAVE_NO_MEMORY(p
);
397 if (!talloc_reference(p
, session_info
)) {
399 return NT_STATUS_NO_MEMORY
;
402 p
->dce_ctx
= dce_ctx
;
404 p
->packet_log_dir
= lpcfg_lock_directory(dce_ctx
->lp_ctx
);
405 p
->auth_state
.session_info
= session_info
;
406 p
->auth_state
.session_key
= dcesrv_generic_session_key
;
407 p
->event_ctx
= event_ctx
;
408 p
->msg_ctx
= msg_ctx
;
409 p
->server_id
= server_id
;
410 p
->state_flags
= state_flags
;
417 move a call from an existing linked list to the specified list. This
418 prevents bugs where we forget to remove the call from a previous
421 static void dcesrv_call_set_list(struct dcesrv_call_state
*call
,
422 enum dcesrv_call_list list
)
424 switch (call
->list
) {
425 case DCESRV_LIST_NONE
:
427 case DCESRV_LIST_CALL_LIST
:
428 DLIST_REMOVE(call
->conn
->call_list
, call
);
430 case DCESRV_LIST_FRAGMENTED_CALL_LIST
:
431 DLIST_REMOVE(call
->conn
->incoming_fragmented_call_list
, call
);
433 case DCESRV_LIST_PENDING_CALL_LIST
:
434 DLIST_REMOVE(call
->conn
->pending_call_list
, call
);
439 case DCESRV_LIST_NONE
:
441 case DCESRV_LIST_CALL_LIST
:
442 DLIST_ADD_END(call
->conn
->call_list
, call
, struct dcesrv_call_state
*);
444 case DCESRV_LIST_FRAGMENTED_CALL_LIST
:
445 DLIST_ADD_END(call
->conn
->incoming_fragmented_call_list
, call
, struct dcesrv_call_state
*);
447 case DCESRV_LIST_PENDING_CALL_LIST
:
448 DLIST_ADD_END(call
->conn
->pending_call_list
, call
, struct dcesrv_call_state
*);
455 return a dcerpc bind_nak
457 static NTSTATUS
dcesrv_bind_nak(struct dcesrv_call_state
*call
, uint32_t reason
)
459 struct ncacn_packet pkt
;
460 struct data_blob_list_item
*rep
;
463 /* setup a bind_nak */
464 dcesrv_init_hdr(&pkt
, lpcfg_rpc_big_endian(call
->conn
->dce_ctx
->lp_ctx
));
466 pkt
.call_id
= call
->pkt
.call_id
;
467 pkt
.ptype
= DCERPC_PKT_BIND_NAK
;
468 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
469 pkt
.u
.bind_nak
.reject_reason
= reason
;
470 if (pkt
.u
.bind_nak
.reject_reason
== DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED
) {
471 pkt
.u
.bind_nak
.versions
.v
.num_versions
= 0;
474 rep
= talloc(call
, struct data_blob_list_item
);
476 return NT_STATUS_NO_MEMORY
;
479 status
= ncacn_push_auth(&rep
->blob
, call
, &pkt
, NULL
);
480 if (!NT_STATUS_IS_OK(status
)) {
484 dcerpc_set_frag_length(&rep
->blob
, rep
->blob
.length
);
486 DLIST_ADD_END(call
->replies
, rep
, struct data_blob_list_item
*);
487 dcesrv_call_set_list(call
, DCESRV_LIST_CALL_LIST
);
489 if (call
->conn
->call_list
&& call
->conn
->call_list
->replies
) {
490 if (call
->conn
->transport
.report_output_data
) {
491 call
->conn
->transport
.report_output_data(call
->conn
);
498 static int dcesrv_connection_context_destructor(struct dcesrv_connection_context
*c
)
500 DLIST_REMOVE(c
->conn
->contexts
, c
);
502 if (c
->iface
&& c
->iface
->unbind
) {
503 c
->iface
->unbind(c
, c
->iface
);
510 handle a bind request
512 static NTSTATUS
dcesrv_bind(struct dcesrv_call_state
*call
)
514 uint32_t if_version
, transfer_syntax_version
;
515 struct GUID uuid
, *transfer_syntax_uuid
;
516 struct ncacn_packet pkt
;
517 struct data_blob_list_item
*rep
;
519 uint32_t result
=0, reason
=0;
521 const struct dcesrv_interface
*iface
;
522 uint32_t extra_flags
= 0;
525 if provided, check the assoc_group is valid
527 if (call
->pkt
.u
.bind
.assoc_group_id
!= 0 &&
528 lpcfg_parm_bool(call
->conn
->dce_ctx
->lp_ctx
, NULL
, "dcesrv","assoc group checking", true) &&
529 dcesrv_assoc_group_find(call
->conn
->dce_ctx
, call
->pkt
.u
.bind
.assoc_group_id
) == NULL
) {
530 return dcesrv_bind_nak(call
, 0);
533 if (call
->pkt
.u
.bind
.num_contexts
< 1 ||
534 call
->pkt
.u
.bind
.ctx_list
[0].num_transfer_syntaxes
< 1) {
535 return dcesrv_bind_nak(call
, 0);
538 context_id
= call
->pkt
.u
.bind
.ctx_list
[0].context_id
;
540 /* you can't bind twice on one context */
541 if (dcesrv_find_context(call
->conn
, context_id
) != NULL
) {
542 return dcesrv_bind_nak(call
, 0);
545 if_version
= call
->pkt
.u
.bind
.ctx_list
[0].abstract_syntax
.if_version
;
546 uuid
= call
->pkt
.u
.bind
.ctx_list
[0].abstract_syntax
.uuid
;
548 transfer_syntax_version
= call
->pkt
.u
.bind
.ctx_list
[0].transfer_syntaxes
[0].if_version
;
549 transfer_syntax_uuid
= &call
->pkt
.u
.bind
.ctx_list
[0].transfer_syntaxes
[0].uuid
;
550 if (!GUID_equal(&ndr_transfer_syntax_ndr
.uuid
, transfer_syntax_uuid
) != 0 ||
551 ndr_transfer_syntax_ndr
.if_version
!= transfer_syntax_version
) {
552 char *uuid_str
= GUID_string(call
, transfer_syntax_uuid
);
553 /* we only do NDR encoded dcerpc */
554 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str
));
555 talloc_free(uuid_str
);
556 return dcesrv_bind_nak(call
, 0);
559 iface
= find_interface_by_uuid(call
->conn
->endpoint
, &uuid
, if_version
);
561 char *uuid_str
= GUID_string(call
, &uuid
);
562 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str
, if_version
));
563 talloc_free(uuid_str
);
565 /* we don't know about that interface */
566 result
= DCERPC_BIND_PROVIDER_REJECT
;
567 reason
= DCERPC_BIND_REASON_ASYNTAX
;
571 /* add this context to the list of available context_ids */
572 struct dcesrv_connection_context
*context
= talloc(call
->conn
,
573 struct dcesrv_connection_context
);
574 if (context
== NULL
) {
575 return dcesrv_bind_nak(call
, 0);
577 context
->conn
= call
->conn
;
578 context
->iface
= iface
;
579 context
->context_id
= context_id
;
580 if (call
->pkt
.u
.bind
.assoc_group_id
!= 0) {
581 context
->assoc_group
= dcesrv_assoc_group_reference(context
,
583 call
->pkt
.u
.bind
.assoc_group_id
);
585 context
->assoc_group
= dcesrv_assoc_group_new(context
, call
->conn
->dce_ctx
);
587 if (context
->assoc_group
== NULL
) {
588 talloc_free(context
);
589 return dcesrv_bind_nak(call
, 0);
591 context
->private_data
= NULL
;
592 DLIST_ADD(call
->conn
->contexts
, context
);
593 call
->context
= context
;
594 talloc_set_destructor(context
, dcesrv_connection_context_destructor
);
596 status
= iface
->bind(call
, iface
, if_version
);
597 if (!NT_STATUS_IS_OK(status
)) {
598 char *uuid_str
= GUID_string(call
, &uuid
);
599 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
600 uuid_str
, if_version
, nt_errstr(status
)));
601 talloc_free(uuid_str
);
602 /* we don't want to trigger the iface->unbind() hook */
603 context
->iface
= NULL
;
604 talloc_free(call
->context
);
605 call
->context
= NULL
;
606 return dcesrv_bind_nak(call
, 0);
610 if (call
->conn
->cli_max_recv_frag
== 0) {
611 call
->conn
->cli_max_recv_frag
= MIN(0x2000, call
->pkt
.u
.bind
.max_recv_frag
);
614 /* handle any authentication that is being requested */
615 if (!dcesrv_auth_bind(call
)) {
616 talloc_free(call
->context
);
617 call
->context
= NULL
;
618 return dcesrv_bind_nak(call
, DCERPC_BIND_REASON_INVALID_AUTH_TYPE
);
621 /* setup a bind_ack */
622 dcesrv_init_hdr(&pkt
, lpcfg_rpc_big_endian(call
->conn
->dce_ctx
->lp_ctx
));
624 pkt
.call_id
= call
->pkt
.call_id
;
625 pkt
.ptype
= DCERPC_PKT_BIND_ACK
;
626 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
| extra_flags
;
627 pkt
.u
.bind_ack
.max_xmit_frag
= call
->conn
->cli_max_recv_frag
;
628 pkt
.u
.bind_ack
.max_recv_frag
= 0x2000;
631 make it possible for iface->bind() to specify the assoc_group_id
632 This helps the openchange mapiproxy plugin to work correctly.
637 pkt
.u
.bind_ack
.assoc_group_id
= call
->context
->assoc_group
->id
;
639 pkt
.u
.bind_ack
.assoc_group_id
= DUMMY_ASSOC_GROUP
;
643 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
644 pkt
.u
.bind_ack
.secondary_address
= talloc_asprintf(call
, "\\PIPE\\%s", iface
->name
);
646 pkt
.u
.bind_ack
.secondary_address
= "";
648 pkt
.u
.bind_ack
.num_results
= 1;
649 pkt
.u
.bind_ack
.ctx_list
= talloc(call
, struct dcerpc_ack_ctx
);
650 if (!pkt
.u
.bind_ack
.ctx_list
) {
651 talloc_free(call
->context
);
652 call
->context
= NULL
;
653 return NT_STATUS_NO_MEMORY
;
655 pkt
.u
.bind_ack
.ctx_list
[0].result
= result
;
656 pkt
.u
.bind_ack
.ctx_list
[0].reason
.value
= reason
;
657 pkt
.u
.bind_ack
.ctx_list
[0].syntax
= ndr_transfer_syntax_ndr
;
658 pkt
.u
.bind_ack
.auth_info
= data_blob(NULL
, 0);
660 status
= dcesrv_auth_bind_ack(call
, &pkt
);
661 if (!NT_STATUS_IS_OK(status
)) {
662 talloc_free(call
->context
);
663 call
->context
= NULL
;
664 return dcesrv_bind_nak(call
, 0);
667 rep
= talloc(call
, struct data_blob_list_item
);
669 talloc_free(call
->context
);
670 call
->context
= NULL
;
671 return NT_STATUS_NO_MEMORY
;
674 status
= ncacn_push_auth(&rep
->blob
, call
, &pkt
,
675 call
->conn
->auth_state
.auth_info
);
676 if (!NT_STATUS_IS_OK(status
)) {
677 talloc_free(call
->context
);
678 call
->context
= NULL
;
682 dcerpc_set_frag_length(&rep
->blob
, rep
->blob
.length
);
684 DLIST_ADD_END(call
->replies
, rep
, struct data_blob_list_item
*);
685 dcesrv_call_set_list(call
, DCESRV_LIST_CALL_LIST
);
687 if (call
->conn
->call_list
&& call
->conn
->call_list
->replies
) {
688 if (call
->conn
->transport
.report_output_data
) {
689 call
->conn
->transport
.report_output_data(call
->conn
);
698 handle a auth3 request
700 static NTSTATUS
dcesrv_auth3(struct dcesrv_call_state
*call
)
702 /* handle the auth3 in the auth code */
703 if (!dcesrv_auth_auth3(call
)) {
704 return dcesrv_fault(call
, DCERPC_FAULT_OTHER
);
709 /* we don't send a reply to a auth3 request, except by a
716 handle a bind request
718 static NTSTATUS
dcesrv_alter_new_context(struct dcesrv_call_state
*call
, uint32_t context_id
)
720 uint32_t if_version
, transfer_syntax_version
;
721 struct dcesrv_connection_context
*context
;
722 const struct dcesrv_interface
*iface
;
723 struct GUID uuid
, *transfer_syntax_uuid
;
726 if_version
= call
->pkt
.u
.alter
.ctx_list
[0].abstract_syntax
.if_version
;
727 uuid
= call
->pkt
.u
.alter
.ctx_list
[0].abstract_syntax
.uuid
;
729 transfer_syntax_version
= call
->pkt
.u
.alter
.ctx_list
[0].transfer_syntaxes
[0].if_version
;
730 transfer_syntax_uuid
= &call
->pkt
.u
.alter
.ctx_list
[0].transfer_syntaxes
[0].uuid
;
731 if (!GUID_equal(transfer_syntax_uuid
, &ndr_transfer_syntax_ndr
.uuid
) ||
732 ndr_transfer_syntax_ndr
.if_version
!= transfer_syntax_version
) {
733 /* we only do NDR encoded dcerpc */
734 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED
;
737 iface
= find_interface_by_uuid(call
->conn
->endpoint
, &uuid
, if_version
);
739 char *uuid_str
= GUID_string(call
, &uuid
);
740 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str
, if_version
));
741 talloc_free(uuid_str
);
742 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED
;
745 /* add this context to the list of available context_ids */
746 context
= talloc(call
->conn
, struct dcesrv_connection_context
);
747 if (context
== NULL
) {
748 return NT_STATUS_NO_MEMORY
;
750 context
->conn
= call
->conn
;
751 context
->iface
= iface
;
752 context
->context_id
= context_id
;
753 if (call
->pkt
.u
.alter
.assoc_group_id
!= 0) {
754 context
->assoc_group
= dcesrv_assoc_group_reference(context
,
756 call
->pkt
.u
.alter
.assoc_group_id
);
758 context
->assoc_group
= dcesrv_assoc_group_new(context
, call
->conn
->dce_ctx
);
760 if (context
->assoc_group
== NULL
) {
761 talloc_free(context
);
762 call
->context
= NULL
;
763 return NT_STATUS_NO_MEMORY
;
765 context
->private_data
= NULL
;
766 DLIST_ADD(call
->conn
->contexts
, context
);
767 call
->context
= context
;
768 talloc_set_destructor(context
, dcesrv_connection_context_destructor
);
770 status
= iface
->bind(call
, iface
, if_version
);
771 if (!NT_STATUS_IS_OK(status
)) {
772 /* we don't want to trigger the iface->unbind() hook */
773 context
->iface
= NULL
;
774 talloc_free(context
);
775 call
->context
= NULL
;
784 handle a alter context request
786 static NTSTATUS
dcesrv_alter(struct dcesrv_call_state
*call
)
788 struct ncacn_packet pkt
;
789 struct data_blob_list_item
*rep
;
791 uint32_t result
=0, reason
=0;
794 /* handle any authentication that is being requested */
795 if (!dcesrv_auth_alter(call
)) {
796 /* TODO: work out the right reject code */
797 result
= DCERPC_BIND_PROVIDER_REJECT
;
798 reason
= DCERPC_BIND_REASON_ASYNTAX
;
801 context_id
= call
->pkt
.u
.alter
.ctx_list
[0].context_id
;
803 /* see if they are asking for a new interface */
805 call
->context
= dcesrv_find_context(call
->conn
, context_id
);
806 if (!call
->context
) {
807 status
= dcesrv_alter_new_context(call
, context_id
);
808 if (!NT_STATUS_IS_OK(status
)) {
809 result
= DCERPC_BIND_PROVIDER_REJECT
;
810 reason
= DCERPC_BIND_REASON_ASYNTAX
;
816 call
->pkt
.u
.alter
.assoc_group_id
!= 0 &&
817 lpcfg_parm_bool(call
->conn
->dce_ctx
->lp_ctx
, NULL
, "dcesrv","assoc group checking", true) &&
818 call
->pkt
.u
.alter
.assoc_group_id
!= call
->context
->assoc_group
->id
) {
819 DEBUG(0,(__location__
": Failed attempt to use new assoc_group in alter context (0x%08x 0x%08x)\n",
820 call
->context
->assoc_group
->id
, call
->pkt
.u
.alter
.assoc_group_id
));
821 /* TODO: can they ask for a new association group? */
822 result
= DCERPC_BIND_PROVIDER_REJECT
;
823 reason
= DCERPC_BIND_REASON_ASYNTAX
;
826 /* setup a alter_resp */
827 dcesrv_init_hdr(&pkt
, lpcfg_rpc_big_endian(call
->conn
->dce_ctx
->lp_ctx
));
829 pkt
.call_id
= call
->pkt
.call_id
;
830 pkt
.ptype
= DCERPC_PKT_ALTER_RESP
;
831 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
832 pkt
.u
.alter_resp
.max_xmit_frag
= 0x2000;
833 pkt
.u
.alter_resp
.max_recv_frag
= 0x2000;
835 pkt
.u
.alter_resp
.assoc_group_id
= call
->context
->assoc_group
->id
;
837 pkt
.u
.alter_resp
.assoc_group_id
= 0;
839 pkt
.u
.alter_resp
.num_results
= 1;
840 pkt
.u
.alter_resp
.ctx_list
= talloc_array(call
, struct dcerpc_ack_ctx
, 1);
841 if (!pkt
.u
.alter_resp
.ctx_list
) {
842 return NT_STATUS_NO_MEMORY
;
844 pkt
.u
.alter_resp
.ctx_list
[0].result
= result
;
845 pkt
.u
.alter_resp
.ctx_list
[0].reason
.value
= reason
;
846 pkt
.u
.alter_resp
.ctx_list
[0].syntax
= ndr_transfer_syntax_ndr
;
847 pkt
.u
.alter_resp
.auth_info
= data_blob(NULL
, 0);
848 pkt
.u
.alter_resp
.secondary_address
= "";
850 status
= dcesrv_auth_alter_ack(call
, &pkt
);
851 if (!NT_STATUS_IS_OK(status
)) {
852 if (NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)
853 || NT_STATUS_EQUAL(status
, NT_STATUS_LOGON_FAILURE
)
854 || NT_STATUS_EQUAL(status
, NT_STATUS_NO_SUCH_USER
)
855 || NT_STATUS_EQUAL(status
, NT_STATUS_WRONG_PASSWORD
)) {
856 return dcesrv_fault(call
, DCERPC_FAULT_ACCESS_DENIED
);
858 return dcesrv_fault(call
, 0);
861 rep
= talloc(call
, struct data_blob_list_item
);
863 return NT_STATUS_NO_MEMORY
;
866 status
= ncacn_push_auth(&rep
->blob
, call
, &pkt
, call
->conn
->auth_state
.auth_info
);
867 if (!NT_STATUS_IS_OK(status
)) {
871 dcerpc_set_frag_length(&rep
->blob
, rep
->blob
.length
);
873 DLIST_ADD_END(call
->replies
, rep
, struct data_blob_list_item
*);
874 dcesrv_call_set_list(call
, DCESRV_LIST_CALL_LIST
);
876 if (call
->conn
->call_list
&& call
->conn
->call_list
->replies
) {
877 if (call
->conn
->transport
.report_output_data
) {
878 call
->conn
->transport
.report_output_data(call
->conn
);
886 possibly save the call for inspection with ndrdump
888 static void dcesrv_save_call(struct dcesrv_call_state
*call
, const char *why
)
892 const char *dump_dir
;
893 dump_dir
= lpcfg_parm_string(call
->conn
->dce_ctx
->lp_ctx
, NULL
, "dcesrv", "stubs directory");
897 fname
= talloc_asprintf(call
, "%s/RPC-%s-%u-%s.dat",
899 call
->context
->iface
->name
,
900 call
->pkt
.u
.request
.opnum
,
902 if (file_save(fname
, call
->pkt
.u
.request
.stub_and_verifier
.data
, call
->pkt
.u
.request
.stub_and_verifier
.length
)) {
903 DEBUG(0,("RPC SAVED %s\n", fname
));
909 static NTSTATUS
dcesrv_check_verification_trailer(struct dcesrv_call_state
*call
)
911 TALLOC_CTX
*frame
= talloc_stackframe();
912 const uint32_t bitmask1
= call
->conn
->auth_state
.client_hdr_signing
?
913 DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING
: 0;
914 const struct dcerpc_sec_vt_pcontext pcontext
= {
915 .abstract_syntax
= call
->context
->iface
->syntax_id
,
916 .transfer_syntax
= ndr_transfer_syntax_ndr
,
918 const struct dcerpc_sec_vt_header2 header2
=
919 dcerpc_sec_vt_header2_from_ncacn_packet(&call
->pkt
);
920 enum ndr_err_code ndr_err
;
921 struct dcerpc_sec_verification_trailer
*vt
= NULL
;
922 NTSTATUS status
= NT_STATUS_OK
;
925 SMB_ASSERT(call
->pkt
.ptype
== DCERPC_PKT_REQUEST
);
927 ndr_err
= ndr_pop_dcerpc_sec_verification_trailer(call
->ndr_pull
,
929 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
930 status
= ndr_map_error2ntstatus(ndr_err
);
934 ok
= dcerpc_sec_verification_trailer_check(vt
, &bitmask1
,
935 &pcontext
, &header2
);
937 status
= NT_STATUS_ACCESS_DENIED
;
946 handle a dcerpc request packet
948 static NTSTATUS
dcesrv_request(struct dcesrv_call_state
*call
)
950 struct ndr_pull
*pull
;
952 struct dcesrv_connection_context
*context
;
954 /* if authenticated, and the mech we use can't do async replies, don't use them... */
955 if (call
->conn
->auth_state
.gensec_security
&&
956 !gensec_have_feature(call
->conn
->auth_state
.gensec_security
, GENSEC_FEATURE_ASYNC_REPLIES
)) {
957 call
->state_flags
&= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC
;
960 context
= dcesrv_find_context(call
->conn
, call
->pkt
.u
.request
.context_id
);
961 if (context
== NULL
) {
962 return dcesrv_fault(call
, DCERPC_FAULT_UNK_IF
);
965 pull
= ndr_pull_init_blob(&call
->pkt
.u
.request
.stub_and_verifier
, call
);
966 NT_STATUS_HAVE_NO_MEMORY(pull
);
968 pull
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
970 call
->context
= context
;
971 call
->ndr_pull
= pull
;
973 if (!(call
->pkt
.drep
[0] & DCERPC_DREP_LE
)) {
974 pull
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
977 status
= dcesrv_check_verification_trailer(call
);
978 if (!NT_STATUS_IS_OK(status
)) {
979 uint32_t faultcode
= DCERPC_FAULT_OTHER
;
980 if (NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
981 faultcode
= DCERPC_FAULT_ACCESS_DENIED
;
983 DEBUG(10, ("dcesrv_check_verification_trailer failed: %s\n",
985 return dcesrv_fault(call
, faultcode
);
988 /* unravel the NDR for the packet */
989 status
= context
->iface
->ndr_pull(call
, call
, pull
, &call
->r
);
990 if (!NT_STATUS_IS_OK(status
)) {
991 if (call
->fault_code
== DCERPC_FAULT_OP_RNG_ERROR
) {
992 /* we got an unknown call */
993 DEBUG(3,(__location__
": Unknown RPC call %u on %s\n",
994 call
->pkt
.u
.request
.opnum
, context
->iface
->name
));
995 dcesrv_save_call(call
, "unknown");
997 dcesrv_save_call(call
, "pullfail");
999 return dcesrv_fault(call
, call
->fault_code
);
1002 if (pull
->offset
!= pull
->data_size
) {
1003 dcesrv_save_call(call
, "extrabytes");
1004 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
1005 pull
->data_size
- pull
->offset
));
1008 /* call the dispatch function */
1009 status
= context
->iface
->dispatch(call
, call
, call
->r
);
1010 if (!NT_STATUS_IS_OK(status
)) {
1011 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
1012 context
->iface
->name
,
1013 call
->pkt
.u
.request
.opnum
,
1014 dcerpc_errstr(pull
, call
->fault_code
)));
1015 return dcesrv_fault(call
, call
->fault_code
);
1018 /* add the call to the pending list */
1019 dcesrv_call_set_list(call
, DCESRV_LIST_PENDING_CALL_LIST
);
1021 if (call
->state_flags
& DCESRV_CALL_STATE_FLAG_ASYNC
) {
1022 return NT_STATUS_OK
;
1025 return dcesrv_reply(call
);
1030 remove the call from the right list when freed
1032 static int dcesrv_call_dequeue(struct dcesrv_call_state
*call
)
1034 dcesrv_call_set_list(call
, DCESRV_LIST_NONE
);
1038 _PUBLIC_
const struct tsocket_address
*dcesrv_connection_get_local_address(struct dcesrv_connection
*conn
)
1040 return conn
->local_address
;
1043 _PUBLIC_
const struct tsocket_address
*dcesrv_connection_get_remote_address(struct dcesrv_connection
*conn
)
1045 return conn
->remote_address
;
1049 process some input to a dcerpc endpoint server.
1051 NTSTATUS
dcesrv_process_ncacn_packet(struct dcesrv_connection
*dce_conn
,
1052 struct ncacn_packet
*pkt
,
1056 struct dcesrv_call_state
*call
;
1058 call
= talloc_zero(dce_conn
, struct dcesrv_call_state
);
1060 data_blob_free(&blob
);
1062 return NT_STATUS_NO_MEMORY
;
1064 call
->conn
= dce_conn
;
1065 call
->event_ctx
= dce_conn
->event_ctx
;
1066 call
->msg_ctx
= dce_conn
->msg_ctx
;
1067 call
->state_flags
= call
->conn
->state_flags
;
1068 call
->time
= timeval_current();
1069 call
->list
= DCESRV_LIST_NONE
;
1071 talloc_steal(call
, pkt
);
1072 talloc_steal(call
, blob
.data
);
1075 talloc_set_destructor(call
, dcesrv_call_dequeue
);
1077 /* we have to check the signing here, before combining the
1079 if (call
->pkt
.ptype
== DCERPC_PKT_REQUEST
&&
1080 !dcesrv_auth_request(call
, &blob
)) {
1081 return dcesrv_fault(call
, DCERPC_FAULT_ACCESS_DENIED
);
1084 /* see if this is a continued packet */
1085 if (call
->pkt
.ptype
== DCERPC_PKT_REQUEST
&&
1086 !(call
->pkt
.pfc_flags
& DCERPC_PFC_FLAG_FIRST
)) {
1087 struct dcesrv_call_state
*call2
= call
;
1088 uint32_t alloc_size
;
1090 /* we only allow fragmented requests, no other packet types */
1091 if (call
->pkt
.ptype
!= DCERPC_PKT_REQUEST
) {
1092 return dcesrv_fault(call2
, DCERPC_FAULT_OTHER
);
1095 /* this is a continuation of an existing call - find the call
1096 then tack it on the end */
1097 call
= dcesrv_find_fragmented_call(dce_conn
, call2
->pkt
.call_id
);
1099 return dcesrv_fault(call2
, DCERPC_FAULT_OTHER
);
1102 if (call
->pkt
.ptype
!= call2
->pkt
.ptype
) {
1103 /* trying to play silly buggers are we? */
1104 return dcesrv_fault(call2
, DCERPC_NCA_S_PROTO_ERROR
);
1106 if (memcmp(call
->pkt
.drep
, call2
->pkt
.drep
, sizeof(pkt
->drep
)) != 0) {
1107 return dcesrv_fault(call2
, DCERPC_NCA_S_PROTO_ERROR
);
1109 if (call
->pkt
.call_id
!= call2
->pkt
.call_id
) {
1110 return dcesrv_fault(call2
, DCERPC_NCA_S_PROTO_ERROR
);
1112 if (call
->pkt
.u
.request
.context_id
!= call2
->pkt
.u
.request
.context_id
) {
1113 return dcesrv_fault(call2
, DCERPC_NCA_S_PROTO_ERROR
);
1115 if (call
->pkt
.u
.request
.opnum
!= call2
->pkt
.u
.request
.opnum
) {
1116 return dcesrv_fault(call2
, DCERPC_NCA_S_PROTO_ERROR
);
1119 alloc_size
= call
->pkt
.u
.request
.stub_and_verifier
.length
+
1120 call2
->pkt
.u
.request
.stub_and_verifier
.length
;
1121 if (call
->pkt
.u
.request
.alloc_hint
> alloc_size
) {
1122 alloc_size
= call
->pkt
.u
.request
.alloc_hint
;
1125 call
->pkt
.u
.request
.stub_and_verifier
.data
=
1126 talloc_realloc(call
,
1127 call
->pkt
.u
.request
.stub_and_verifier
.data
,
1128 uint8_t, alloc_size
);
1129 if (!call
->pkt
.u
.request
.stub_and_verifier
.data
) {
1130 return dcesrv_fault(call2
, DCERPC_FAULT_OTHER
);
1132 memcpy(call
->pkt
.u
.request
.stub_and_verifier
.data
+
1133 call
->pkt
.u
.request
.stub_and_verifier
.length
,
1134 call2
->pkt
.u
.request
.stub_and_verifier
.data
,
1135 call2
->pkt
.u
.request
.stub_and_verifier
.length
);
1136 call
->pkt
.u
.request
.stub_and_verifier
.length
+=
1137 call2
->pkt
.u
.request
.stub_and_verifier
.length
;
1139 call
->pkt
.pfc_flags
|= (call2
->pkt
.pfc_flags
& DCERPC_PFC_FLAG_LAST
);
1144 /* this may not be the last pdu in the chain - if its isn't then
1145 just put it on the incoming_fragmented_call_list and wait for the rest */
1146 if (call
->pkt
.ptype
== DCERPC_PKT_REQUEST
&&
1147 !(call
->pkt
.pfc_flags
& DCERPC_PFC_FLAG_LAST
)) {
1148 dcesrv_call_set_list(call
, DCESRV_LIST_FRAGMENTED_CALL_LIST
);
1149 return NT_STATUS_OK
;
1152 /* This removes any fragments we may have had stashed away */
1153 dcesrv_call_set_list(call
, DCESRV_LIST_NONE
);
1155 switch (call
->pkt
.ptype
) {
1156 case DCERPC_PKT_BIND
:
1157 status
= dcesrv_bind(call
);
1159 case DCERPC_PKT_AUTH3
:
1160 status
= dcesrv_auth3(call
);
1162 case DCERPC_PKT_ALTER
:
1163 status
= dcesrv_alter(call
);
1165 case DCERPC_PKT_REQUEST
:
1166 status
= dcesrv_request(call
);
1169 status
= NT_STATUS_INVALID_PARAMETER
;
1173 /* if we are going to be sending a reply then add
1174 it to the list of pending calls. We add it to the end to keep the call
1175 list in the order we will answer */
1176 if (!NT_STATUS_IS_OK(status
)) {
1183 _PUBLIC_ NTSTATUS
dcesrv_init_context(TALLOC_CTX
*mem_ctx
,
1184 struct loadparm_context
*lp_ctx
,
1185 const char **endpoint_servers
, struct dcesrv_context
**_dce_ctx
)
1188 struct dcesrv_context
*dce_ctx
;
1191 if (!endpoint_servers
) {
1192 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1193 return NT_STATUS_INTERNAL_ERROR
;
1196 dce_ctx
= talloc(mem_ctx
, struct dcesrv_context
);
1197 NT_STATUS_HAVE_NO_MEMORY(dce_ctx
);
1198 dce_ctx
->endpoint_list
= NULL
;
1199 dce_ctx
->lp_ctx
= lp_ctx
;
1200 dce_ctx
->assoc_groups_idr
= idr_init(dce_ctx
);
1201 NT_STATUS_HAVE_NO_MEMORY(dce_ctx
->assoc_groups_idr
);
1202 dce_ctx
->broken_connections
= NULL
;
1204 for (i
=0;endpoint_servers
[i
];i
++) {
1205 const struct dcesrv_endpoint_server
*ep_server
;
1207 ep_server
= dcesrv_ep_server_byname(endpoint_servers
[i
]);
1209 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers
[i
]));
1210 return NT_STATUS_INTERNAL_ERROR
;
1213 status
= ep_server
->init_server(dce_ctx
, ep_server
);
1214 if (!NT_STATUS_IS_OK(status
)) {
1215 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers
[i
],
1216 nt_errstr(status
)));
1221 *_dce_ctx
= dce_ctx
;
1222 return NT_STATUS_OK
;
1225 /* the list of currently registered DCERPC endpoint servers.
1227 static struct ep_server
{
1228 struct dcesrv_endpoint_server
*ep_server
;
1229 } *ep_servers
= NULL
;
1230 static int num_ep_servers
;
1233 register a DCERPC endpoint server.
1235 The 'name' can be later used by other backends to find the operations
1236 structure for this backend.
1238 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1240 _PUBLIC_ NTSTATUS
dcerpc_register_ep_server(const void *_ep_server
)
1242 const struct dcesrv_endpoint_server
*ep_server
= _ep_server
;
1244 if (dcesrv_ep_server_byname(ep_server
->name
) != NULL
) {
1245 /* its already registered! */
1246 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1248 return NT_STATUS_OBJECT_NAME_COLLISION
;
1251 ep_servers
= realloc_p(ep_servers
, struct ep_server
, num_ep_servers
+1);
1253 smb_panic("out of memory in dcerpc_register");
1256 ep_servers
[num_ep_servers
].ep_server
= smb_xmemdup(ep_server
, sizeof(*ep_server
));
1257 ep_servers
[num_ep_servers
].ep_server
->name
= smb_xstrdup(ep_server
->name
);
1261 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1264 return NT_STATUS_OK
;
1268 return the operations structure for a named backend of the specified type
1270 const struct dcesrv_endpoint_server
*dcesrv_ep_server_byname(const char *name
)
1274 for (i
=0;i
<num_ep_servers
;i
++) {
1275 if (strcmp(ep_servers
[i
].ep_server
->name
, name
) == 0) {
1276 return ep_servers
[i
].ep_server
;
1283 void dcerpc_server_init(struct loadparm_context
*lp_ctx
)
1285 static bool initialized
;
1286 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
1287 STATIC_dcerpc_server_MODULES_PROTO
;
1288 init_module_fn static_init
[] = { STATIC_dcerpc_server_MODULES
};
1289 init_module_fn
*shared_init
;
1296 shared_init
= load_samba_modules(NULL
, "dcerpc_server");
1298 run_init_functions(static_init
);
1299 run_init_functions(shared_init
);
1301 talloc_free(shared_init
);
1305 return the DCERPC module version, and the size of some critical types
1306 This can be used by endpoint server modules to either detect compilation errors, or provide
1307 multiple implementations for different smbd compilation options in one module
1309 const struct dcesrv_critical_sizes
*dcerpc_module_version(void)
1311 static const struct dcesrv_critical_sizes critical_sizes
= {
1312 DCERPC_MODULE_VERSION
,
1313 sizeof(struct dcesrv_context
),
1314 sizeof(struct dcesrv_endpoint
),
1315 sizeof(struct dcesrv_endpoint_server
),
1316 sizeof(struct dcesrv_interface
),
1317 sizeof(struct dcesrv_if_list
),
1318 sizeof(struct dcesrv_connection
),
1319 sizeof(struct dcesrv_call_state
),
1320 sizeof(struct dcesrv_auth
),
1321 sizeof(struct dcesrv_handle
)
1324 return &critical_sizes
;
1327 static void dcesrv_terminate_connection(struct dcesrv_connection
*dce_conn
, const char *reason
)
1329 struct dcesrv_context
*dce_ctx
= dce_conn
->dce_ctx
;
1330 struct stream_connection
*srv_conn
;
1331 srv_conn
= talloc_get_type(dce_conn
->transport
.private_data
,
1332 struct stream_connection
);
1334 if (dce_conn
->pending_call_list
== NULL
) {
1335 char *full_reason
= talloc_asprintf(dce_conn
, "dcesrv: %s", reason
);
1337 DLIST_REMOVE(dce_ctx
->broken_connections
, dce_conn
);
1338 stream_terminate_connection(srv_conn
, full_reason
? full_reason
: reason
);
1342 if (dce_conn
->terminate
!= NULL
) {
1346 DEBUG(3,("dcesrv: terminating connection due to '%s' defered due to pending calls\n",
1348 dce_conn
->terminate
= talloc_strdup(dce_conn
, reason
);
1349 if (dce_conn
->terminate
== NULL
) {
1350 dce_conn
->terminate
= "dcesrv: defered terminating connection - no memory";
1352 DLIST_ADD_END(dce_ctx
->broken_connections
, dce_conn
, NULL
);
1355 static void dcesrv_cleanup_broken_connections(struct dcesrv_context
*dce_ctx
)
1357 struct dcesrv_connection
*cur
, *next
;
1359 next
= dce_ctx
->broken_connections
;
1360 while (next
!= NULL
) {
1364 dcesrv_terminate_connection(cur
, cur
->terminate
);
1368 /* We need this include to be able to compile on some plateforms
1369 * (ie. freebsd 7.2) as it seems that <sys/uio.h> is not included
1371 * It has to be that deep because otherwise we have a conflict on
1372 * const struct dcesrv_interface declaration.
1373 * This is mostly due to socket_wrapper defining #define bind swrap_bind
1374 * which conflict with the bind used before.
1376 #include "system/network.h"
1378 struct dcesrv_sock_reply_state
{
1379 struct dcesrv_connection
*dce_conn
;
1380 struct dcesrv_call_state
*call
;
1384 static void dcesrv_sock_reply_done(struct tevent_req
*subreq
);
1386 static void dcesrv_sock_report_output_data(struct dcesrv_connection
*dce_conn
)
1388 struct dcesrv_call_state
*call
;
1390 call
= dce_conn
->call_list
;
1391 if (!call
|| !call
->replies
) {
1395 while (call
->replies
) {
1396 struct data_blob_list_item
*rep
= call
->replies
;
1397 struct dcesrv_sock_reply_state
*substate
;
1398 struct tevent_req
*subreq
;
1400 substate
= talloc(call
, struct dcesrv_sock_reply_state
);
1402 dcesrv_terminate_connection(dce_conn
, "no memory");
1406 substate
->dce_conn
= dce_conn
;
1407 substate
->call
= NULL
;
1409 DLIST_REMOVE(call
->replies
, rep
);
1411 if (call
->replies
== NULL
) {
1412 substate
->call
= call
;
1415 substate
->iov
.iov_base
= (void *) rep
->blob
.data
;
1416 substate
->iov
.iov_len
= rep
->blob
.length
;
1418 subreq
= tstream_writev_queue_send(substate
,
1419 dce_conn
->event_ctx
,
1421 dce_conn
->send_queue
,
1424 dcesrv_terminate_connection(dce_conn
, "no memory");
1427 tevent_req_set_callback(subreq
, dcesrv_sock_reply_done
,
1431 DLIST_REMOVE(call
->conn
->call_list
, call
);
1432 call
->list
= DCESRV_LIST_NONE
;
1435 static void dcesrv_sock_reply_done(struct tevent_req
*subreq
)
1437 struct dcesrv_sock_reply_state
*substate
= tevent_req_callback_data(subreq
,
1438 struct dcesrv_sock_reply_state
);
1442 struct dcesrv_call_state
*call
= substate
->call
;
1444 ret
= tstream_writev_queue_recv(subreq
, &sys_errno
);
1445 TALLOC_FREE(subreq
);
1447 status
= map_nt_error_from_unix_common(sys_errno
);
1448 dcesrv_terminate_connection(substate
->dce_conn
, nt_errstr(status
));
1452 talloc_free(substate
);
1461 struct dcesrv_socket_context
{
1462 const struct dcesrv_endpoint
*endpoint
;
1463 struct dcesrv_context
*dcesrv_ctx
;
1467 static void dcesrv_read_fragment_done(struct tevent_req
*subreq
);
1469 static void dcesrv_sock_accept(struct stream_connection
*srv_conn
)
1472 struct dcesrv_socket_context
*dcesrv_sock
=
1473 talloc_get_type(srv_conn
->private_data
, struct dcesrv_socket_context
);
1474 enum dcerpc_transport_t transport
=
1475 dcerpc_binding_get_transport(dcesrv_sock
->endpoint
->ep_description
);
1476 struct dcesrv_connection
*dcesrv_conn
= NULL
;
1478 struct tevent_req
*subreq
;
1479 struct loadparm_context
*lp_ctx
= dcesrv_sock
->dcesrv_ctx
->lp_ctx
;
1481 dcesrv_cleanup_broken_connections(dcesrv_sock
->dcesrv_ctx
);
1483 if (!srv_conn
->session_info
) {
1484 status
= auth_anonymous_session_info(srv_conn
,
1486 &srv_conn
->session_info
);
1487 if (!NT_STATUS_IS_OK(status
)) {
1488 DEBUG(0,("dcesrv_sock_accept: auth_anonymous_session_info failed: %s\n",
1489 nt_errstr(status
)));
1490 stream_terminate_connection(srv_conn
, nt_errstr(status
));
1495 status
= dcesrv_endpoint_connect(dcesrv_sock
->dcesrv_ctx
,
1497 dcesrv_sock
->endpoint
,
1498 srv_conn
->session_info
,
1499 srv_conn
->event
.ctx
,
1501 srv_conn
->server_id
,
1502 DCESRV_CALL_STATE_FLAG_MAY_ASYNC
,
1504 if (!NT_STATUS_IS_OK(status
)) {
1505 DEBUG(0,("dcesrv_sock_accept: dcesrv_endpoint_connect failed: %s\n",
1506 nt_errstr(status
)));
1507 stream_terminate_connection(srv_conn
, nt_errstr(status
));
1511 dcesrv_conn
->transport
.private_data
= srv_conn
;
1512 dcesrv_conn
->transport
.report_output_data
= dcesrv_sock_report_output_data
;
1514 TALLOC_FREE(srv_conn
->event
.fde
);
1516 dcesrv_conn
->send_queue
= tevent_queue_create(dcesrv_conn
, "dcesrv send queue");
1517 if (!dcesrv_conn
->send_queue
) {
1518 status
= NT_STATUS_NO_MEMORY
;
1519 DEBUG(0,("dcesrv_sock_accept: tevent_queue_create(%s)\n",
1520 nt_errstr(status
)));
1521 stream_terminate_connection(srv_conn
, nt_errstr(status
));
1525 if (transport
== NCACN_NP
) {
1526 dcesrv_conn
->auth_state
.session_key
= dcesrv_inherited_session_key
;
1527 dcesrv_conn
->stream
= talloc_move(dcesrv_conn
,
1528 &srv_conn
->tstream
);
1530 ret
= tstream_bsd_existing_socket(dcesrv_conn
,
1531 socket_get_fd(srv_conn
->socket
),
1532 &dcesrv_conn
->stream
);
1534 status
= map_nt_error_from_unix_common(errno
);
1535 DEBUG(0, ("dcesrv_sock_accept: "
1536 "failed to setup tstream: %s\n",
1537 nt_errstr(status
)));
1538 stream_terminate_connection(srv_conn
, nt_errstr(status
));
1541 socket_set_flags(srv_conn
->socket
, SOCKET_FLAG_NOCLOSE
);
1544 dcesrv_conn
->local_address
= srv_conn
->local_address
;
1545 dcesrv_conn
->remote_address
= srv_conn
->remote_address
;
1547 srv_conn
->private_data
= dcesrv_conn
;
1549 irpc_add_name(srv_conn
->msg_ctx
, "rpc_server");
1551 subreq
= dcerpc_read_ncacn_packet_send(dcesrv_conn
,
1552 dcesrv_conn
->event_ctx
,
1553 dcesrv_conn
->stream
);
1555 status
= NT_STATUS_NO_MEMORY
;
1556 DEBUG(0,("dcesrv_sock_accept: dcerpc_read_fragment_buffer_send(%s)\n",
1557 nt_errstr(status
)));
1558 stream_terminate_connection(srv_conn
, nt_errstr(status
));
1561 tevent_req_set_callback(subreq
, dcesrv_read_fragment_done
, dcesrv_conn
);
1566 static void dcesrv_read_fragment_done(struct tevent_req
*subreq
)
1568 struct dcesrv_connection
*dce_conn
= tevent_req_callback_data(subreq
,
1569 struct dcesrv_connection
);
1570 struct dcesrv_context
*dce_ctx
= dce_conn
->dce_ctx
;
1571 struct ncacn_packet
*pkt
;
1575 if (dce_conn
->terminate
) {
1577 * if the current connection is broken
1578 * we need to clean it up before any other connection
1580 dcesrv_terminate_connection(dce_conn
, dce_conn
->terminate
);
1581 dcesrv_cleanup_broken_connections(dce_ctx
);
1585 dcesrv_cleanup_broken_connections(dce_ctx
);
1587 status
= dcerpc_read_ncacn_packet_recv(subreq
, dce_conn
,
1589 TALLOC_FREE(subreq
);
1590 if (!NT_STATUS_IS_OK(status
)) {
1591 dcesrv_terminate_connection(dce_conn
, nt_errstr(status
));
1595 status
= dcesrv_process_ncacn_packet(dce_conn
, pkt
, buffer
);
1596 if (!NT_STATUS_IS_OK(status
)) {
1597 dcesrv_terminate_connection(dce_conn
, nt_errstr(status
));
1601 subreq
= dcerpc_read_ncacn_packet_send(dce_conn
,
1602 dce_conn
->event_ctx
,
1605 status
= NT_STATUS_NO_MEMORY
;
1606 dcesrv_terminate_connection(dce_conn
, nt_errstr(status
));
1609 tevent_req_set_callback(subreq
, dcesrv_read_fragment_done
, dce_conn
);
1612 static void dcesrv_sock_recv(struct stream_connection
*conn
, uint16_t flags
)
1614 struct dcesrv_connection
*dce_conn
= talloc_get_type(conn
->private_data
,
1615 struct dcesrv_connection
);
1616 dcesrv_terminate_connection(dce_conn
, "dcesrv_sock_recv triggered");
1619 static void dcesrv_sock_send(struct stream_connection
*conn
, uint16_t flags
)
1621 struct dcesrv_connection
*dce_conn
= talloc_get_type(conn
->private_data
,
1622 struct dcesrv_connection
);
1623 dcesrv_terminate_connection(dce_conn
, "dcesrv_sock_send triggered");
1627 static const struct stream_server_ops dcesrv_stream_ops
= {
1629 .accept_connection
= dcesrv_sock_accept
,
1630 .recv_handler
= dcesrv_sock_recv
,
1631 .send_handler
= dcesrv_sock_send
,
1634 static NTSTATUS
dcesrv_add_ep_unix(struct dcesrv_context
*dce_ctx
,
1635 struct loadparm_context
*lp_ctx
,
1636 struct dcesrv_endpoint
*e
,
1637 struct tevent_context
*event_ctx
, const struct model_ops
*model_ops
)
1639 struct dcesrv_socket_context
*dcesrv_sock
;
1642 const char *endpoint
;
1644 dcesrv_sock
= talloc(event_ctx
, struct dcesrv_socket_context
);
1645 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock
);
1647 /* remember the endpoint of this socket */
1648 dcesrv_sock
->endpoint
= e
;
1649 dcesrv_sock
->dcesrv_ctx
= talloc_reference(dcesrv_sock
, dce_ctx
);
1651 endpoint
= dcerpc_binding_get_string_option(e
->ep_description
, "endpoint");
1653 status
= stream_setup_socket(dcesrv_sock
, event_ctx
, lp_ctx
,
1654 model_ops
, &dcesrv_stream_ops
,
1655 "unix", endpoint
, &port
,
1656 lpcfg_socket_options(lp_ctx
),
1658 if (!NT_STATUS_IS_OK(status
)) {
1659 DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n",
1660 endpoint
, nt_errstr(status
)));
1666 static NTSTATUS
dcesrv_add_ep_ncalrpc(struct dcesrv_context
*dce_ctx
,
1667 struct loadparm_context
*lp_ctx
,
1668 struct dcesrv_endpoint
*e
,
1669 struct tevent_context
*event_ctx
, const struct model_ops
*model_ops
)
1671 struct dcesrv_socket_context
*dcesrv_sock
;
1675 const char *endpoint
;
1677 endpoint
= dcerpc_binding_get_string_option(e
->ep_description
, "endpoint");
1679 if (endpoint
== NULL
) {
1681 * No identifier specified: use DEFAULT.
1683 * TODO: DO NOT hardcode this value anywhere else. Rather, specify
1684 * no endpoint and let the epmapper worry about it.
1686 endpoint
= "DEFAULT";
1687 status
= dcerpc_binding_set_string_option(e
->ep_description
,
1690 if (!NT_STATUS_IS_OK(status
)) {
1691 DEBUG(0,("dcerpc_binding_set_string_option() failed - %s\n",
1692 nt_errstr(status
)));
1697 full_path
= talloc_asprintf(dce_ctx
, "%s/%s", lpcfg_ncalrpc_dir(lp_ctx
),
1700 dcesrv_sock
= talloc(event_ctx
, struct dcesrv_socket_context
);
1701 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock
);
1703 /* remember the endpoint of this socket */
1704 dcesrv_sock
->endpoint
= e
;
1705 dcesrv_sock
->dcesrv_ctx
= talloc_reference(dcesrv_sock
, dce_ctx
);
1707 status
= stream_setup_socket(dcesrv_sock
, event_ctx
, lp_ctx
,
1708 model_ops
, &dcesrv_stream_ops
,
1709 "unix", full_path
, &port
,
1710 lpcfg_socket_options(lp_ctx
),
1712 if (!NT_STATUS_IS_OK(status
)) {
1713 DEBUG(0,("service_setup_stream_socket(identifier=%s,path=%s) failed - %s\n",
1714 endpoint
, full_path
, nt_errstr(status
)));
1719 static NTSTATUS
dcesrv_add_ep_np(struct dcesrv_context
*dce_ctx
,
1720 struct loadparm_context
*lp_ctx
,
1721 struct dcesrv_endpoint
*e
,
1722 struct tevent_context
*event_ctx
, const struct model_ops
*model_ops
)
1724 struct dcesrv_socket_context
*dcesrv_sock
;
1726 const char *endpoint
;
1728 endpoint
= dcerpc_binding_get_string_option(e
->ep_description
, "endpoint");
1729 if (endpoint
== NULL
) {
1730 DEBUG(0, ("Endpoint mandatory for named pipes\n"));
1731 return NT_STATUS_INVALID_PARAMETER
;
1734 dcesrv_sock
= talloc(event_ctx
, struct dcesrv_socket_context
);
1735 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock
);
1737 /* remember the endpoint of this socket */
1738 dcesrv_sock
->endpoint
= e
;
1739 dcesrv_sock
->dcesrv_ctx
= talloc_reference(dcesrv_sock
, dce_ctx
);
1741 status
= tstream_setup_named_pipe(dce_ctx
, event_ctx
, lp_ctx
,
1742 model_ops
, &dcesrv_stream_ops
,
1745 if (!NT_STATUS_IS_OK(status
)) {
1746 DEBUG(0,("stream_setup_named_pipe(pipe=%s) failed - %s\n",
1747 endpoint
, nt_errstr(status
)));
1751 return NT_STATUS_OK
;
1755 add a socket address to the list of events, one event per dcerpc endpoint
1757 static NTSTATUS
add_socket_rpc_tcp_iface(struct dcesrv_context
*dce_ctx
, struct dcesrv_endpoint
*e
,
1758 struct tevent_context
*event_ctx
, const struct model_ops
*model_ops
,
1759 const char *address
)
1761 struct dcesrv_socket_context
*dcesrv_sock
;
1764 const char *endpoint
;
1767 endpoint
= dcerpc_binding_get_string_option(e
->ep_description
, "endpoint");
1768 if (endpoint
!= NULL
) {
1769 port
= atoi(endpoint
);
1772 dcesrv_sock
= talloc(event_ctx
, struct dcesrv_socket_context
);
1773 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock
);
1775 /* remember the endpoint of this socket */
1776 dcesrv_sock
->endpoint
= e
;
1777 dcesrv_sock
->dcesrv_ctx
= talloc_reference(dcesrv_sock
, dce_ctx
);
1779 status
= stream_setup_socket(dcesrv_sock
, event_ctx
, dce_ctx
->lp_ctx
,
1780 model_ops
, &dcesrv_stream_ops
,
1781 "ip", address
, &port
,
1782 lpcfg_socket_options(dce_ctx
->lp_ctx
),
1784 if (!NT_STATUS_IS_OK(status
)) {
1785 DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) failed - %s\n",
1786 address
, port
, nt_errstr(status
)));
1790 snprintf(port_str
, sizeof(port_str
), "%u", port
);
1792 status
= dcerpc_binding_set_string_option(e
->ep_description
,
1793 "endpoint", port_str
);
1794 if (!NT_STATUS_IS_OK(status
)) {
1795 DEBUG(0,("dcerpc_binding_set_string_option(endpoint, %s) failed - %s\n",
1796 port_str
, nt_errstr(status
)));
1800 return NT_STATUS_OK
;
1803 #include "lib/socket/netif.h" /* Included here to work around the fact that socket_wrapper redefines bind() */
1805 static NTSTATUS
dcesrv_add_ep_tcp(struct dcesrv_context
*dce_ctx
,
1806 struct loadparm_context
*lp_ctx
,
1807 struct dcesrv_endpoint
*e
,
1808 struct tevent_context
*event_ctx
, const struct model_ops
*model_ops
)
1812 /* Add TCP/IP sockets */
1813 if (lpcfg_interfaces(lp_ctx
) && lpcfg_bind_interfaces_only(lp_ctx
)) {
1816 struct interface
*ifaces
;
1818 load_interface_list(dce_ctx
, lp_ctx
, &ifaces
);
1820 num_interfaces
= iface_list_count(ifaces
);
1821 for(i
= 0; i
< num_interfaces
; i
++) {
1822 const char *address
= iface_list_n_ip(ifaces
, i
);
1823 status
= add_socket_rpc_tcp_iface(dce_ctx
, e
, event_ctx
, model_ops
, address
);
1824 NT_STATUS_NOT_OK_RETURN(status
);
1829 wcard
= iface_list_wildcard(dce_ctx
);
1830 NT_STATUS_HAVE_NO_MEMORY(wcard
);
1831 for (i
=0; wcard
[i
]; i
++) {
1832 status
= add_socket_rpc_tcp_iface(dce_ctx
, e
, event_ctx
, model_ops
, wcard
[i
]);
1833 NT_STATUS_NOT_OK_RETURN(status
);
1838 return NT_STATUS_OK
;
1841 NTSTATUS
dcesrv_add_ep(struct dcesrv_context
*dce_ctx
,
1842 struct loadparm_context
*lp_ctx
,
1843 struct dcesrv_endpoint
*e
,
1844 struct tevent_context
*event_ctx
,
1845 const struct model_ops
*model_ops
)
1847 enum dcerpc_transport_t transport
=
1848 dcerpc_binding_get_transport(e
->ep_description
);
1850 switch (transport
) {
1851 case NCACN_UNIX_STREAM
:
1852 return dcesrv_add_ep_unix(dce_ctx
, lp_ctx
, e
, event_ctx
, model_ops
);
1855 return dcesrv_add_ep_ncalrpc(dce_ctx
, lp_ctx
, e
, event_ctx
, model_ops
);
1858 return dcesrv_add_ep_tcp(dce_ctx
, lp_ctx
, e
, event_ctx
, model_ops
);
1861 return dcesrv_add_ep_np(dce_ctx
, lp_ctx
, e
, event_ctx
, model_ops
);
1864 return NT_STATUS_NOT_SUPPORTED
;
1870 * retrieve credentials from a dce_call
1872 _PUBLIC_
struct cli_credentials
*dcesrv_call_credentials(struct dcesrv_call_state
*dce_call
)
1874 return dce_call
->conn
->auth_state
.session_info
->credentials
;
1878 * returns true if this is an authenticated call
1880 _PUBLIC_
bool dcesrv_call_authenticated(struct dcesrv_call_state
*dce_call
)
1882 enum security_user_level level
;
1883 level
= security_session_user_level(dce_call
->conn
->auth_state
.session_info
, NULL
);
1884 return level
>= SECURITY_USER
;
1888 * retrieve account_name for a dce_call
1890 _PUBLIC_
const char *dcesrv_call_account_name(struct dcesrv_call_state
*dce_call
)
1892 return dce_call
->context
->conn
->auth_state
.session_info
->info
->account_name
;