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 "librpc/rpc/dcerpc_proto.h"
30 #include "system/filesys.h"
31 #include "libcli/security/security.h"
32 #include "param/param.h"
33 #include "../lib/tsocket/tsocket.h"
34 #include "../libcli/named_pipe_auth/npa_tstream.h"
35 #include "smbd/service_stream.h"
36 #include "../lib/tsocket/tsocket.h"
37 #include "lib/socket/socket.h"
38 #include "smbd/process_model.h"
39 #include "lib/messaging/irpc.h"
41 /* this is only used when the client asks for an unknown interface */
42 #define DUMMY_ASSOC_GROUP 0x0FFFFFFF
44 extern const struct dcesrv_interface dcesrv_mgmt_interface;
48 find an association group given a assoc_group_id
50 static struct dcesrv_assoc_group *dcesrv_assoc_group_find(struct dcesrv_context *dce_ctx,
55 id_ptr = idr_find(dce_ctx->assoc_groups_idr, id);
59 return talloc_get_type_abort(id_ptr, struct dcesrv_assoc_group);
63 take a reference to an existing association group
65 static struct dcesrv_assoc_group *dcesrv_assoc_group_reference(TALLOC_CTX *mem_ctx,
66 struct dcesrv_context *dce_ctx,
69 struct dcesrv_assoc_group *assoc_group;
71 assoc_group = dcesrv_assoc_group_find(dce_ctx, id);
72 if (assoc_group == NULL) {
73 DEBUG(0,(__location__ ": Failed to find assoc_group 0x%08x\n", id));
76 return talloc_reference(mem_ctx, assoc_group);
79 static int dcesrv_assoc_group_destructor(struct dcesrv_assoc_group *assoc_group)
82 ret = idr_remove(assoc_group->dce_ctx->assoc_groups_idr, assoc_group->id);
84 DEBUG(0,(__location__ ": Failed to remove assoc_group 0x%08x\n",
91 allocate a new association group
93 static struct dcesrv_assoc_group *dcesrv_assoc_group_new(TALLOC_CTX *mem_ctx,
94 struct dcesrv_context *dce_ctx)
96 struct dcesrv_assoc_group *assoc_group;
99 assoc_group = talloc_zero(mem_ctx, struct dcesrv_assoc_group);
100 if (assoc_group == NULL) {
104 id = idr_get_new_random(dce_ctx->assoc_groups_idr, assoc_group, UINT16_MAX);
106 talloc_free(assoc_group);
107 DEBUG(0,(__location__ ": Out of association groups!\n"));
111 assoc_group->id = id;
112 assoc_group->dce_ctx = dce_ctx;
114 talloc_set_destructor(assoc_group, dcesrv_assoc_group_destructor);
121 see if two endpoints match
123 static bool endpoints_match(const struct dcerpc_binding *ep1,
124 const struct dcerpc_binding *ep2)
126 if (ep1->transport != ep2->transport) {
130 if (!ep1->endpoint || !ep2->endpoint) {
131 return ep1->endpoint == ep2->endpoint;
134 if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
141 find an endpoint in the dcesrv_context
143 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
144 const struct dcerpc_binding *ep_description)
146 struct dcesrv_endpoint *ep;
147 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
148 if (endpoints_match(ep->ep_description, ep_description)) {
156 find a registered context_id from a bind or alter_context
158 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn,
161 struct dcesrv_connection_context *c;
162 for (c=conn->contexts;c;c=c->next) {
163 if (c->context_id == context_id) return c;
169 see if a uuid and if_version match to an interface
171 static bool interface_match(const struct dcesrv_interface *if1,
172 const struct dcesrv_interface *if2)
174 return (if1->syntax_id.if_version == if2->syntax_id.if_version &&
175 GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
179 find the interface operations on an endpoint
181 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
182 const struct dcesrv_interface *iface)
184 struct dcesrv_if_list *ifl;
185 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
186 if (interface_match(&(ifl->iface), iface)) {
187 return &(ifl->iface);
194 see if a uuid and if_version match to an interface
196 static bool interface_match_by_uuid(const struct dcesrv_interface *iface,
197 const struct GUID *uuid, uint32_t if_version)
199 return (iface->syntax_id.if_version == if_version &&
200 GUID_equal(&iface->syntax_id.uuid, uuid));
204 find the interface operations on an endpoint by uuid
206 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
207 const struct GUID *uuid, uint32_t if_version)
209 struct dcesrv_if_list *ifl;
210 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
211 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
212 return &(ifl->iface);
219 find the earlier parts of a fragmented call awaiting reassembily
221 static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
223 struct dcesrv_call_state *c;
224 for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
225 if (c->pkt.call_id == call_id) {
233 register an interface on an endpoint
235 _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
237 const struct dcesrv_interface *iface,
238 const struct security_descriptor *sd)
240 struct dcesrv_endpoint *ep;
241 struct dcesrv_if_list *ifl;
242 struct dcerpc_binding *binding;
246 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
248 if (NT_STATUS_IS_ERR(status)) {
249 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
253 /* check if this endpoint exists
255 if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
256 ep = talloc(dce_ctx, struct dcesrv_endpoint);
258 return NT_STATUS_NO_MEMORY;
261 ep->ep_description = talloc_reference(ep, binding);
264 /* add mgmt interface */
265 ifl = talloc(dce_ctx, struct dcesrv_if_list);
267 return NT_STATUS_NO_MEMORY;
270 memcpy(&(ifl->iface), &dcesrv_mgmt_interface,
271 sizeof(struct dcesrv_interface));
273 DLIST_ADD(ep->interface_list, ifl);
276 /* see if the interface is already registered on te endpoint */
277 if (find_interface(ep, iface)!=NULL) {
278 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
279 iface->name, ep_name));
280 return NT_STATUS_OBJECT_NAME_COLLISION;
283 /* talloc a new interface list element */
284 ifl = talloc(dce_ctx, struct dcesrv_if_list);
286 return NT_STATUS_NO_MEMORY;
289 /* copy the given interface struct to the one on the endpoints interface list */
290 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
292 /* if we have a security descriptor given,
293 * we should see if we can set it up on the endpoint
296 /* if there's currently no security descriptor given on the endpoint
299 if (ep->sd == NULL) {
300 ep->sd = security_descriptor_copy(dce_ctx, sd);
303 /* if now there's no security descriptor given on the endpoint
304 * something goes wrong, either we failed to copy the security descriptor
305 * or there was already one on the endpoint
307 if (ep->sd != NULL) {
308 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
309 " on endpoint '%s'\n",
310 iface->name, ep_name));
311 if (add_ep) free(ep);
313 return NT_STATUS_OBJECT_NAME_COLLISION;
317 /* finally add the interface on the endpoint */
318 DLIST_ADD(ep->interface_list, ifl);
320 /* if it's a new endpoint add it to the dcesrv_context */
322 DLIST_ADD(dce_ctx->endpoint_list, ep);
325 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
326 iface->name, ep_name));
331 NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
332 DATA_BLOB *session_key)
334 if (p->auth_state.session_info->session_key.length) {
335 *session_key = p->auth_state.session_info->session_key;
338 return NT_STATUS_NO_USER_SESSION_KEY;
341 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *c,
342 DATA_BLOB *session_key)
344 return dcerpc_generic_session_key(NULL, session_key);
348 fetch the user session key - may be default (above) or the SMB session key
350 The key is always truncated to 16 bytes
352 _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
353 DATA_BLOB *session_key)
355 NTSTATUS status = p->auth_state.session_key(p, session_key);
356 if (!NT_STATUS_IS_OK(status)) {
360 session_key->length = MIN(session_key->length, 16);
366 connect to a dcerpc endpoint
368 _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
370 const struct dcesrv_endpoint *ep,
371 struct auth_session_info *session_info,
372 struct tevent_context *event_ctx,
373 struct messaging_context *msg_ctx,
374 struct server_id server_id,
375 uint32_t state_flags,
376 struct dcesrv_connection **_p)
378 struct dcesrv_connection *p;
381 return NT_STATUS_ACCESS_DENIED;
384 p = talloc(mem_ctx, struct dcesrv_connection);
385 NT_STATUS_HAVE_NO_MEMORY(p);
387 if (!talloc_reference(p, session_info)) {
389 return NT_STATUS_NO_MEMORY;
392 p->dce_ctx = dce_ctx;
396 p->packet_log_dir = lpcfg_lockdir(dce_ctx->lp_ctx);
397 p->incoming_fragmented_call_list = NULL;
398 p->pending_call_list = NULL;
399 p->cli_max_recv_frag = 0;
400 p->partial_input = data_blob(NULL, 0);
401 p->auth_state.auth_info = NULL;
402 p->auth_state.gensec_security = NULL;
403 p->auth_state.session_info = session_info;
404 p->auth_state.session_key = dcesrv_generic_session_key;
405 p->event_ctx = event_ctx;
406 p->msg_ctx = msg_ctx;
407 p->server_id = server_id;
408 p->processing = false;
409 p->state_flags = state_flags;
410 ZERO_STRUCT(p->transport);
416 static void dcesrv_init_hdr(struct ncacn_packet *pkt, bool bigendian)
419 pkt->rpc_vers_minor = 0;
423 pkt->drep[0] = DCERPC_DREP_LE;
431 move a call from an existing linked list to the specified list. This
432 prevents bugs where we forget to remove the call from a previous
435 static void dcesrv_call_set_list(struct dcesrv_call_state *call,
436 enum dcesrv_call_list list)
438 switch (call->list) {
439 case DCESRV_LIST_NONE:
441 case DCESRV_LIST_CALL_LIST:
442 DLIST_REMOVE(call->conn->call_list, call);
444 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
445 DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
447 case DCESRV_LIST_PENDING_CALL_LIST:
448 DLIST_REMOVE(call->conn->pending_call_list, call);
453 case DCESRV_LIST_NONE:
455 case DCESRV_LIST_CALL_LIST:
456 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
458 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
459 DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
461 case DCESRV_LIST_PENDING_CALL_LIST:
462 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
468 return a dcerpc fault
470 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
472 struct ncacn_packet pkt;
473 struct data_blob_list_item *rep;
477 /* setup a bind_ack */
478 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
480 pkt.call_id = call->pkt.call_id;
481 pkt.ptype = DCERPC_PKT_FAULT;
482 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
483 pkt.u.fault.alloc_hint = 0;
484 pkt.u.fault.context_id = 0;
485 pkt.u.fault.cancel_count = 0;
486 pkt.u.fault.status = fault_code;
489 pkt.u.fault._pad = data_blob_const(zeros, sizeof(zeros));
491 rep = talloc(call, struct data_blob_list_item);
493 return NT_STATUS_NO_MEMORY;
496 status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
497 if (!NT_STATUS_IS_OK(status)) {
501 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
503 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
504 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
506 if (call->conn->call_list && call->conn->call_list->replies) {
507 if (call->conn->transport.report_output_data) {
508 call->conn->transport.report_output_data(call->conn);
517 return a dcerpc bind_nak
519 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
521 struct ncacn_packet pkt;
522 struct data_blob_list_item *rep;
525 /* setup a bind_nak */
526 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
528 pkt.call_id = call->pkt.call_id;
529 pkt.ptype = DCERPC_PKT_BIND_NAK;
530 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
531 pkt.u.bind_nak.reject_reason = reason;
532 if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
533 pkt.u.bind_nak.versions.v.num_versions = 0;
536 rep = talloc(call, struct data_blob_list_item);
538 return NT_STATUS_NO_MEMORY;
541 status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
542 if (!NT_STATUS_IS_OK(status)) {
546 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
548 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
549 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
551 if (call->conn->call_list && call->conn->call_list->replies) {
552 if (call->conn->transport.report_output_data) {
553 call->conn->transport.report_output_data(call->conn);
560 static int dcesrv_connection_context_destructor(struct dcesrv_connection_context *c)
562 DLIST_REMOVE(c->conn->contexts, c);
564 if (c->iface && c->iface->unbind) {
565 c->iface->unbind(c, c->iface);
572 handle a bind request
574 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
576 uint32_t if_version, transfer_syntax_version;
577 struct GUID uuid, *transfer_syntax_uuid;
578 struct ncacn_packet pkt;
579 struct data_blob_list_item *rep;
581 uint32_t result=0, reason=0;
583 const struct dcesrv_interface *iface;
584 uint32_t extra_flags = 0;
587 if provided, check the assoc_group is valid
589 if (call->pkt.u.bind.assoc_group_id != 0 &&
590 lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
591 dcesrv_assoc_group_find(call->conn->dce_ctx, call->pkt.u.bind.assoc_group_id) == NULL) {
592 return dcesrv_bind_nak(call, 0);
595 if (call->pkt.u.bind.num_contexts < 1 ||
596 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
597 return dcesrv_bind_nak(call, 0);
600 context_id = call->pkt.u.bind.ctx_list[0].context_id;
602 /* you can't bind twice on one context */
603 if (dcesrv_find_context(call->conn, context_id) != NULL) {
604 return dcesrv_bind_nak(call, 0);
607 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
608 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
610 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
611 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
612 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
613 ndr_transfer_syntax.if_version != transfer_syntax_version) {
614 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
615 /* we only do NDR encoded dcerpc */
616 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
617 talloc_free(uuid_str);
618 return dcesrv_bind_nak(call, 0);
621 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
623 char *uuid_str = GUID_string(call, &uuid);
624 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
625 talloc_free(uuid_str);
627 /* we don't know about that interface */
628 result = DCERPC_BIND_PROVIDER_REJECT;
629 reason = DCERPC_BIND_REASON_ASYNTAX;
633 /* add this context to the list of available context_ids */
634 struct dcesrv_connection_context *context = talloc(call->conn,
635 struct dcesrv_connection_context);
636 if (context == NULL) {
637 return dcesrv_bind_nak(call, 0);
639 context->conn = call->conn;
640 context->iface = iface;
641 context->context_id = context_id;
642 if (call->pkt.u.bind.assoc_group_id != 0) {
643 context->assoc_group = dcesrv_assoc_group_reference(context,
645 call->pkt.u.bind.assoc_group_id);
647 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
649 if (context->assoc_group == NULL) {
650 talloc_free(context);
651 return dcesrv_bind_nak(call, 0);
653 context->private_data = NULL;
654 DLIST_ADD(call->conn->contexts, context);
655 call->context = context;
656 talloc_set_destructor(context, dcesrv_connection_context_destructor);
658 status = iface->bind(call, iface, if_version);
659 if (!NT_STATUS_IS_OK(status)) {
660 char *uuid_str = GUID_string(call, &uuid);
661 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
662 uuid_str, if_version, nt_errstr(status)));
663 talloc_free(uuid_str);
664 /* we don't want to trigger the iface->unbind() hook */
665 context->iface = NULL;
666 talloc_free(call->context);
667 call->context = NULL;
668 return dcesrv_bind_nak(call, 0);
672 if (call->conn->cli_max_recv_frag == 0) {
673 call->conn->cli_max_recv_frag = MIN(0x2000, call->pkt.u.bind.max_recv_frag);
676 if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) &&
677 lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","header signing", false)) {
678 call->conn->state_flags |= DCESRV_CALL_STATE_FLAG_HEADER_SIGNING;
679 extra_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
682 /* handle any authentication that is being requested */
683 if (!dcesrv_auth_bind(call)) {
684 talloc_free(call->context);
685 call->context = NULL;
686 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
689 /* setup a bind_ack */
690 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
692 pkt.call_id = call->pkt.call_id;
693 pkt.ptype = DCERPC_PKT_BIND_ACK;
694 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
695 pkt.u.bind_ack.max_xmit_frag = call->conn->cli_max_recv_frag;
696 pkt.u.bind_ack.max_recv_frag = 0x2000;
699 make it possible for iface->bind() to specify the assoc_group_id
700 This helps the openchange mapiproxy plugin to work correctly.
705 pkt.u.bind_ack.assoc_group_id = call->context->assoc_group->id;
707 pkt.u.bind_ack.assoc_group_id = DUMMY_ASSOC_GROUP;
711 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
712 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
714 pkt.u.bind_ack.secondary_address = "";
716 pkt.u.bind_ack.num_results = 1;
717 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
718 if (!pkt.u.bind_ack.ctx_list) {
719 talloc_free(call->context);
720 call->context = NULL;
721 return NT_STATUS_NO_MEMORY;
723 pkt.u.bind_ack.ctx_list[0].result = result;
724 pkt.u.bind_ack.ctx_list[0].reason = reason;
725 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
726 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
728 status = dcesrv_auth_bind_ack(call, &pkt);
729 if (!NT_STATUS_IS_OK(status)) {
730 talloc_free(call->context);
731 call->context = NULL;
732 return dcesrv_bind_nak(call, 0);
735 rep = talloc(call, struct data_blob_list_item);
737 talloc_free(call->context);
738 call->context = NULL;
739 return NT_STATUS_NO_MEMORY;
742 status = ncacn_push_auth(&rep->blob, call, &pkt,
743 call->conn->auth_state.auth_info);
744 if (!NT_STATUS_IS_OK(status)) {
745 talloc_free(call->context);
746 call->context = NULL;
750 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
752 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
753 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
755 if (call->conn->call_list && call->conn->call_list->replies) {
756 if (call->conn->transport.report_output_data) {
757 call->conn->transport.report_output_data(call->conn);
766 handle a auth3 request
768 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
770 /* handle the auth3 in the auth code */
771 if (!dcesrv_auth_auth3(call)) {
772 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
777 /* we don't send a reply to a auth3 request, except by a
784 handle a bind request
786 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
788 uint32_t if_version, transfer_syntax_version;
789 struct dcesrv_connection_context *context;
790 const struct dcesrv_interface *iface;
791 struct GUID uuid, *transfer_syntax_uuid;
794 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
795 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
797 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
798 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
799 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
800 ndr_transfer_syntax.if_version != transfer_syntax_version) {
801 /* we only do NDR encoded dcerpc */
802 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
805 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
807 char *uuid_str = GUID_string(call, &uuid);
808 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
809 talloc_free(uuid_str);
810 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
813 /* add this context to the list of available context_ids */
814 context = talloc(call->conn, struct dcesrv_connection_context);
815 if (context == NULL) {
816 return NT_STATUS_NO_MEMORY;
818 context->conn = call->conn;
819 context->iface = iface;
820 context->context_id = context_id;
821 if (call->pkt.u.alter.assoc_group_id != 0) {
822 context->assoc_group = dcesrv_assoc_group_reference(context,
824 call->pkt.u.alter.assoc_group_id);
826 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
828 if (context->assoc_group == NULL) {
829 talloc_free(context);
830 call->context = NULL;
831 return NT_STATUS_NO_MEMORY;
833 context->private_data = NULL;
834 DLIST_ADD(call->conn->contexts, context);
835 call->context = context;
836 talloc_set_destructor(context, dcesrv_connection_context_destructor);
838 status = iface->bind(call, iface, if_version);
839 if (!NT_STATUS_IS_OK(status)) {
840 /* we don't want to trigger the iface->unbind() hook */
841 context->iface = NULL;
842 talloc_free(context);
843 call->context = NULL;
852 handle a alter context request
854 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
856 struct ncacn_packet pkt;
857 struct data_blob_list_item *rep;
859 uint32_t result=0, reason=0;
862 /* handle any authentication that is being requested */
863 if (!dcesrv_auth_alter(call)) {
864 /* TODO: work out the right reject code */
865 result = DCERPC_BIND_PROVIDER_REJECT;
866 reason = DCERPC_BIND_REASON_ASYNTAX;
869 context_id = call->pkt.u.alter.ctx_list[0].context_id;
871 /* see if they are asking for a new interface */
873 call->context = dcesrv_find_context(call->conn, context_id);
874 if (!call->context) {
875 status = dcesrv_alter_new_context(call, context_id);
876 if (!NT_STATUS_IS_OK(status)) {
877 result = DCERPC_BIND_PROVIDER_REJECT;
878 reason = DCERPC_BIND_REASON_ASYNTAX;
884 call->pkt.u.alter.assoc_group_id != 0 &&
885 lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
886 call->pkt.u.alter.assoc_group_id != call->context->assoc_group->id) {
887 DEBUG(0,(__location__ ": Failed attempt to use new assoc_group in alter context (0x%08x 0x%08x)\n",
888 call->context->assoc_group->id, call->pkt.u.alter.assoc_group_id));
889 /* TODO: can they ask for a new association group? */
890 result = DCERPC_BIND_PROVIDER_REJECT;
891 reason = DCERPC_BIND_REASON_ASYNTAX;
894 /* setup a alter_resp */
895 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
897 pkt.call_id = call->pkt.call_id;
898 pkt.ptype = DCERPC_PKT_ALTER_RESP;
899 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
900 pkt.u.alter_resp.max_xmit_frag = 0x2000;
901 pkt.u.alter_resp.max_recv_frag = 0x2000;
903 pkt.u.alter_resp.assoc_group_id = call->context->assoc_group->id;
905 pkt.u.alter_resp.assoc_group_id = 0;
907 pkt.u.alter_resp.num_results = 1;
908 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
909 if (!pkt.u.alter_resp.ctx_list) {
910 return NT_STATUS_NO_MEMORY;
912 pkt.u.alter_resp.ctx_list[0].result = result;
913 pkt.u.alter_resp.ctx_list[0].reason = reason;
914 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
915 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
916 pkt.u.alter_resp.secondary_address = "";
918 status = dcesrv_auth_alter_ack(call, &pkt);
919 if (!NT_STATUS_IS_OK(status)) {
920 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
921 || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
922 || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
923 || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
924 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
926 return dcesrv_fault(call, 0);
929 rep = talloc(call, struct data_blob_list_item);
931 return NT_STATUS_NO_MEMORY;
934 status = ncacn_push_auth(&rep->blob, call, &pkt, call->conn->auth_state.auth_info);
935 if (!NT_STATUS_IS_OK(status)) {
939 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
941 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
942 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
944 if (call->conn->call_list && call->conn->call_list->replies) {
945 if (call->conn->transport.report_output_data) {
946 call->conn->transport.report_output_data(call->conn);
954 possibly save the call for inspection with ndrdump
956 static void dcesrv_save_call(struct dcesrv_call_state *call, const char *why)
960 const char *dump_dir;
961 dump_dir = lpcfg_parm_string(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv", "stubs directory");
965 fname = talloc_asprintf(call, "%s/RPC-%s-%u-%s.dat",
967 call->context->iface->name,
968 call->pkt.u.request.opnum,
970 if (file_save(fname, call->pkt.u.request.stub_and_verifier.data, call->pkt.u.request.stub_and_verifier.length)) {
971 DEBUG(0,("RPC SAVED %s\n", fname));
978 handle a dcerpc request packet
980 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
982 struct ndr_pull *pull;
984 struct dcesrv_connection_context *context;
986 /* if authenticated, and the mech we use can't do async replies, don't use them... */
987 if (call->conn->auth_state.gensec_security &&
988 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
989 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
992 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
993 if (context == NULL) {
994 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
997 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
998 NT_STATUS_HAVE_NO_MEMORY(pull);
1000 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1002 call->context = context;
1003 call->ndr_pull = pull;
1005 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
1006 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1009 /* unravel the NDR for the packet */
1010 status = context->iface->ndr_pull(call, call, pull, &call->r);
1011 if (!NT_STATUS_IS_OK(status)) {
1012 if (call->fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
1013 /* we got an unknown call */
1014 DEBUG(3,(__location__ ": Unknown RPC call %u on %s\n",
1015 call->pkt.u.request.opnum, context->iface->name));
1016 dcesrv_save_call(call, "unknown");
1018 dcesrv_save_call(call, "pullfail");
1020 return dcesrv_fault(call, call->fault_code);
1023 if (pull->offset != pull->data_size) {
1024 dcesrv_save_call(call, "extrabytes");
1025 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
1026 pull->data_size - pull->offset));
1029 /* call the dispatch function */
1030 status = context->iface->dispatch(call, call, call->r);
1031 if (!NT_STATUS_IS_OK(status)) {
1032 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
1033 context->iface->name,
1034 call->pkt.u.request.opnum,
1035 dcerpc_errstr(pull, call->fault_code)));
1036 return dcesrv_fault(call, call->fault_code);
1039 /* add the call to the pending list */
1040 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
1042 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
1043 return NT_STATUS_OK;
1046 return dcesrv_reply(call);
1049 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
1051 struct ndr_push *push;
1054 uint32_t total_length, chunk_size;
1055 struct dcesrv_connection_context *context = call->context;
1056 size_t sig_size = 0;
1058 /* call the reply function */
1059 status = context->iface->reply(call, call, call->r);
1060 if (!NT_STATUS_IS_OK(status)) {
1061 return dcesrv_fault(call, call->fault_code);
1064 /* form the reply NDR */
1065 push = ndr_push_init_ctx(call);
1066 NT_STATUS_HAVE_NO_MEMORY(push);
1068 /* carry over the pointer count to the reply in case we are
1069 using full pointer. See NDR specification for full
1071 push->ptr_count = call->ndr_pull->ptr_count;
1073 if (lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
1074 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1077 status = context->iface->ndr_push(call, call, push, call->r);
1078 if (!NT_STATUS_IS_OK(status)) {
1079 return dcesrv_fault(call, call->fault_code);
1082 stub = ndr_push_blob(push);
1084 total_length = stub.length;
1086 /* we can write a full max_recv_frag size, minus the dcerpc
1087 request header size */
1088 chunk_size = call->conn->cli_max_recv_frag;
1089 chunk_size -= DCERPC_REQUEST_LENGTH;
1090 if (call->conn->auth_state.auth_info &&
1091 call->conn->auth_state.gensec_security) {
1092 sig_size = gensec_sig_size(call->conn->auth_state.gensec_security,
1093 call->conn->cli_max_recv_frag);
1095 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1096 chunk_size -= sig_size;
1099 chunk_size -= (chunk_size % 16);
1103 struct data_blob_list_item *rep;
1104 struct ncacn_packet pkt;
1106 rep = talloc(call, struct data_blob_list_item);
1107 NT_STATUS_HAVE_NO_MEMORY(rep);
1109 length = MIN(chunk_size, stub.length);
1111 /* form the dcerpc response packet */
1112 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
1113 pkt.auth_length = 0;
1114 pkt.call_id = call->pkt.call_id;
1115 pkt.ptype = DCERPC_PKT_RESPONSE;
1117 if (stub.length == total_length) {
1118 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1120 if (length == stub.length) {
1121 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1123 pkt.u.response.alloc_hint = stub.length;
1124 pkt.u.response.context_id = call->pkt.u.request.context_id;
1125 pkt.u.response.cancel_count = 0;
1126 pkt.u.response.stub_and_verifier.data = stub.data;
1127 pkt.u.response.stub_and_verifier.length = length;
1129 if (!dcesrv_auth_response(call, &rep->blob, sig_size, &pkt)) {
1130 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
1133 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
1135 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
1137 stub.data += length;
1138 stub.length -= length;
1139 } while (stub.length != 0);
1141 /* move the call from the pending to the finished calls list */
1142 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
1144 if (call->conn->call_list && call->conn->call_list->replies) {
1145 if (call->conn->transport.report_output_data) {
1146 call->conn->transport.report_output_data(call->conn);
1150 return NT_STATUS_OK;
1154 remove the call from the right list when freed
1156 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1158 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1162 _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_local_address(struct dcesrv_connection *conn)
1164 return conn->local_address;
1167 _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_remote_address(struct dcesrv_connection *conn)
1169 return conn->remote_address;
1173 process some input to a dcerpc endpoint server.
1175 NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
1176 struct ncacn_packet *pkt,
1180 struct dcesrv_call_state *call;
1182 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1184 data_blob_free(&blob);
1186 return NT_STATUS_NO_MEMORY;
1188 call->conn = dce_conn;
1189 call->event_ctx = dce_conn->event_ctx;
1190 call->msg_ctx = dce_conn->msg_ctx;
1191 call->state_flags = call->conn->state_flags;
1192 call->time = timeval_current();
1193 call->list = DCESRV_LIST_NONE;
1195 talloc_steal(call, pkt);
1196 talloc_steal(call, blob.data);
1199 talloc_set_destructor(call, dcesrv_call_dequeue);
1201 /* we have to check the signing here, before combining the
1203 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1204 !dcesrv_auth_request(call, &blob)) {
1205 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1208 /* see if this is a continued packet */
1209 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1210 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1211 struct dcesrv_call_state *call2 = call;
1212 uint32_t alloc_size;
1214 /* we only allow fragmented requests, no other packet types */
1215 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1216 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1219 /* this is a continuation of an existing call - find the call then
1220 tack it on the end */
1221 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1223 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1226 if (call->pkt.ptype != call2->pkt.ptype) {
1227 /* trying to play silly buggers are we? */
1228 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1231 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1232 call2->pkt.u.request.stub_and_verifier.length;
1233 if (call->pkt.u.request.alloc_hint > alloc_size) {
1234 alloc_size = call->pkt.u.request.alloc_hint;
1237 call->pkt.u.request.stub_and_verifier.data =
1238 talloc_realloc(call,
1239 call->pkt.u.request.stub_and_verifier.data,
1240 uint8_t, alloc_size);
1241 if (!call->pkt.u.request.stub_and_verifier.data) {
1242 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1244 memcpy(call->pkt.u.request.stub_and_verifier.data +
1245 call->pkt.u.request.stub_and_verifier.length,
1246 call2->pkt.u.request.stub_and_verifier.data,
1247 call2->pkt.u.request.stub_and_verifier.length);
1248 call->pkt.u.request.stub_and_verifier.length +=
1249 call2->pkt.u.request.stub_and_verifier.length;
1251 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1256 /* this may not be the last pdu in the chain - if its isn't then
1257 just put it on the incoming_fragmented_call_list and wait for the rest */
1258 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1259 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1260 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1261 return NT_STATUS_OK;
1264 /* This removes any fragments we may have had stashed away */
1265 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1267 switch (call->pkt.ptype) {
1268 case DCERPC_PKT_BIND:
1269 status = dcesrv_bind(call);
1271 case DCERPC_PKT_AUTH3:
1272 status = dcesrv_auth3(call);
1274 case DCERPC_PKT_ALTER:
1275 status = dcesrv_alter(call);
1277 case DCERPC_PKT_REQUEST:
1278 status = dcesrv_request(call);
1281 status = NT_STATUS_INVALID_PARAMETER;
1285 /* if we are going to be sending a reply then add
1286 it to the list of pending calls. We add it to the end to keep the call
1287 list in the order we will answer */
1288 if (!NT_STATUS_IS_OK(status)) {
1295 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1296 struct loadparm_context *lp_ctx,
1297 const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1300 struct dcesrv_context *dce_ctx;
1303 if (!endpoint_servers) {
1304 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1305 return NT_STATUS_INTERNAL_ERROR;
1308 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1309 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1310 dce_ctx->endpoint_list = NULL;
1311 dce_ctx->lp_ctx = lp_ctx;
1312 dce_ctx->assoc_groups_idr = idr_init(dce_ctx);
1313 NT_STATUS_HAVE_NO_MEMORY(dce_ctx->assoc_groups_idr);
1315 for (i=0;endpoint_servers[i];i++) {
1316 const struct dcesrv_endpoint_server *ep_server;
1318 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1320 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1321 return NT_STATUS_INTERNAL_ERROR;
1324 status = ep_server->init_server(dce_ctx, ep_server);
1325 if (!NT_STATUS_IS_OK(status)) {
1326 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1327 nt_errstr(status)));
1332 *_dce_ctx = dce_ctx;
1333 return NT_STATUS_OK;
1336 /* the list of currently registered DCERPC endpoint servers.
1338 static struct ep_server {
1339 struct dcesrv_endpoint_server *ep_server;
1340 } *ep_servers = NULL;
1341 static int num_ep_servers;
1344 register a DCERPC endpoint server.
1346 The 'name' can be later used by other backends to find the operations
1347 structure for this backend.
1349 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1351 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1353 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1355 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1356 /* its already registered! */
1357 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1359 return NT_STATUS_OBJECT_NAME_COLLISION;
1362 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1364 smb_panic("out of memory in dcerpc_register");
1367 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1368 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1372 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1375 return NT_STATUS_OK;
1379 return the operations structure for a named backend of the specified type
1381 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1385 for (i=0;i<num_ep_servers;i++) {
1386 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1387 return ep_servers[i].ep_server;
1394 void dcerpc_server_init(struct loadparm_context *lp_ctx)
1396 static bool initialized;
1397 extern NTSTATUS dcerpc_server_wkssvc_init(void);
1398 extern NTSTATUS dcerpc_server_drsuapi_init(void);
1399 extern NTSTATUS dcerpc_server_winreg_init(void);
1400 extern NTSTATUS dcerpc_server_spoolss_init(void);
1401 extern NTSTATUS dcerpc_server_epmapper_init(void);
1402 extern NTSTATUS dcerpc_server_srvsvc_init(void);
1403 extern NTSTATUS dcerpc_server_netlogon_init(void);
1404 extern NTSTATUS dcerpc_server_rpcecho_init(void);
1405 extern NTSTATUS dcerpc_server_unixinfo_init(void);
1406 extern NTSTATUS dcerpc_server_samr_init(void);
1407 extern NTSTATUS dcerpc_server_remote_init(void);
1408 extern NTSTATUS dcerpc_server_lsa_init(void);
1409 extern NTSTATUS dcerpc_server_browser_init(void);
1410 extern NTSTATUS dcerpc_server_eventlog6_init(void);
1411 init_module_fn static_init[] = { STATIC_dcerpc_server_MODULES };
1412 init_module_fn *shared_init;
1419 shared_init = load_samba_modules(NULL, lp_ctx, "dcerpc_server");
1421 run_init_functions(static_init);
1422 run_init_functions(shared_init);
1424 talloc_free(shared_init);
1428 return the DCERPC module version, and the size of some critical types
1429 This can be used by endpoint server modules to either detect compilation errors, or provide
1430 multiple implementations for different smbd compilation options in one module
1432 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1434 static const struct dcesrv_critical_sizes critical_sizes = {
1435 DCERPC_MODULE_VERSION,
1436 sizeof(struct dcesrv_context),
1437 sizeof(struct dcesrv_endpoint),
1438 sizeof(struct dcesrv_endpoint_server),
1439 sizeof(struct dcesrv_interface),
1440 sizeof(struct dcesrv_if_list),
1441 sizeof(struct dcesrv_connection),
1442 sizeof(struct dcesrv_call_state),
1443 sizeof(struct dcesrv_auth),
1444 sizeof(struct dcesrv_handle)
1447 return &critical_sizes;
1450 static void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, const char *reason)
1452 struct stream_connection *srv_conn;
1453 srv_conn = talloc_get_type(dce_conn->transport.private_data,
1454 struct stream_connection);
1456 stream_terminate_connection(srv_conn, reason);
1458 /* We need this include to be able to compile on some plateforms
1459 * (ie. freebsd 7.2) as it seems that <sys/uio.h> is not included
1461 * It has to be that deep because otherwise we have a conflict on
1462 * const struct dcesrv_interface declaration.
1463 * This is mostly due to socket_wrapper defining #define bind swrap_bind
1464 * which conflict with the bind used before.
1466 #include "system/network.h"
1468 struct dcesrv_sock_reply_state {
1469 struct dcesrv_connection *dce_conn;
1470 struct dcesrv_call_state *call;
1474 static void dcesrv_sock_reply_done(struct tevent_req *subreq);
1476 static void dcesrv_sock_report_output_data(struct dcesrv_connection *dce_conn)
1478 struct dcesrv_call_state *call;
1480 call = dce_conn->call_list;
1481 if (!call || !call->replies) {
1485 while (call->replies) {
1486 struct data_blob_list_item *rep = call->replies;
1487 struct dcesrv_sock_reply_state *substate;
1488 struct tevent_req *subreq;
1490 substate = talloc(call, struct dcesrv_sock_reply_state);
1492 dcesrv_terminate_connection(dce_conn, "no memory");
1496 substate->dce_conn = dce_conn;
1497 substate->call = NULL;
1499 DLIST_REMOVE(call->replies, rep);
1501 if (call->replies == NULL) {
1502 substate->call = call;
1505 substate->iov.iov_base = (void *) rep->blob.data;
1506 substate->iov.iov_len = rep->blob.length;
1508 subreq = tstream_writev_queue_send(substate,
1509 dce_conn->event_ctx,
1511 dce_conn->send_queue,
1514 dcesrv_terminate_connection(dce_conn, "no memory");
1517 tevent_req_set_callback(subreq, dcesrv_sock_reply_done,
1521 DLIST_REMOVE(call->conn->call_list, call);
1522 call->list = DCESRV_LIST_NONE;
1525 static void dcesrv_sock_reply_done(struct tevent_req *subreq)
1527 struct dcesrv_sock_reply_state *substate = tevent_req_callback_data(subreq,
1528 struct dcesrv_sock_reply_state);
1532 struct dcesrv_call_state *call = substate->call;
1534 ret = tstream_writev_queue_recv(subreq, &sys_errno);
1535 TALLOC_FREE(subreq);
1537 status = map_nt_error_from_unix(sys_errno);
1538 dcesrv_terminate_connection(substate->dce_conn, nt_errstr(status));
1542 talloc_free(substate);
1551 struct dcesrv_socket_context {
1552 const struct dcesrv_endpoint *endpoint;
1553 struct dcesrv_context *dcesrv_ctx;
1557 static void dcesrv_read_fragment_done(struct tevent_req *subreq);
1559 static void dcesrv_sock_accept(struct stream_connection *srv_conn)
1562 struct dcesrv_socket_context *dcesrv_sock =
1563 talloc_get_type(srv_conn->private_data, struct dcesrv_socket_context);
1564 struct dcesrv_connection *dcesrv_conn = NULL;
1566 struct tevent_req *subreq;
1567 struct loadparm_context *lp_ctx = dcesrv_sock->dcesrv_ctx->lp_ctx;
1569 if (!srv_conn->session_info) {
1570 status = auth_anonymous_session_info(srv_conn,
1572 &srv_conn->session_info);
1573 if (!NT_STATUS_IS_OK(status)) {
1574 DEBUG(0,("dcesrv_sock_accept: auth_anonymous_session_info failed: %s\n",
1575 nt_errstr(status)));
1576 stream_terminate_connection(srv_conn, nt_errstr(status));
1581 status = dcesrv_endpoint_connect(dcesrv_sock->dcesrv_ctx,
1583 dcesrv_sock->endpoint,
1584 srv_conn->session_info,
1585 srv_conn->event.ctx,
1587 srv_conn->server_id,
1588 DCESRV_CALL_STATE_FLAG_MAY_ASYNC,
1590 if (!NT_STATUS_IS_OK(status)) {
1591 DEBUG(0,("dcesrv_sock_accept: dcesrv_endpoint_connect failed: %s\n",
1592 nt_errstr(status)));
1593 stream_terminate_connection(srv_conn, nt_errstr(status));
1597 dcesrv_conn->transport.private_data = srv_conn;
1598 dcesrv_conn->transport.report_output_data = dcesrv_sock_report_output_data;
1600 TALLOC_FREE(srv_conn->event.fde);
1602 dcesrv_conn->send_queue = tevent_queue_create(dcesrv_conn, "dcesrv send queue");
1603 if (!dcesrv_conn->send_queue) {
1604 status = NT_STATUS_NO_MEMORY;
1605 DEBUG(0,("dcesrv_sock_accept: tevent_queue_create(%s)\n",
1606 nt_errstr(status)));
1607 stream_terminate_connection(srv_conn, nt_errstr(status));
1611 if (dcesrv_sock->endpoint->ep_description->transport == NCACN_NP) {
1612 dcesrv_conn->auth_state.session_key = dcesrv_inherited_session_key;
1613 dcesrv_conn->stream = talloc_move(dcesrv_conn,
1614 &srv_conn->tstream);
1616 ret = tstream_bsd_existing_socket(dcesrv_conn,
1617 socket_get_fd(srv_conn->socket),
1618 &dcesrv_conn->stream);
1620 status = map_nt_error_from_unix(errno);
1621 DEBUG(0, ("dcesrv_sock_accept: "
1622 "failed to setup tstream: %s\n",
1623 nt_errstr(status)));
1624 stream_terminate_connection(srv_conn, nt_errstr(status));
1627 socket_set_flags(srv_conn->socket, SOCKET_FLAG_NOCLOSE);
1630 dcesrv_conn->local_address = srv_conn->local_address;
1631 dcesrv_conn->remote_address = srv_conn->remote_address;
1633 srv_conn->private_data = dcesrv_conn;
1635 irpc_add_name(srv_conn->msg_ctx, "rpc_server");
1637 subreq = dcerpc_read_ncacn_packet_send(dcesrv_conn,
1638 dcesrv_conn->event_ctx,
1639 dcesrv_conn->stream);
1641 status = NT_STATUS_NO_MEMORY;
1642 DEBUG(0,("dcesrv_sock_accept: dcerpc_read_fragment_buffer_send(%s)\n",
1643 nt_errstr(status)));
1644 stream_terminate_connection(srv_conn, nt_errstr(status));
1647 tevent_req_set_callback(subreq, dcesrv_read_fragment_done, dcesrv_conn);
1652 static void dcesrv_read_fragment_done(struct tevent_req *subreq)
1654 struct dcesrv_connection *dce_conn = tevent_req_callback_data(subreq,
1655 struct dcesrv_connection);
1656 struct ncacn_packet *pkt;
1660 status = dcerpc_read_ncacn_packet_recv(subreq, dce_conn,
1662 TALLOC_FREE(subreq);
1663 if (!NT_STATUS_IS_OK(status)) {
1664 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1668 status = dcesrv_process_ncacn_packet(dce_conn, pkt, buffer);
1669 if (!NT_STATUS_IS_OK(status)) {
1670 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1674 subreq = dcerpc_read_ncacn_packet_send(dce_conn,
1675 dce_conn->event_ctx,
1678 status = NT_STATUS_NO_MEMORY;
1679 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1682 tevent_req_set_callback(subreq, dcesrv_read_fragment_done, dce_conn);
1685 static void dcesrv_sock_recv(struct stream_connection *conn, uint16_t flags)
1687 struct dcesrv_connection *dce_conn = talloc_get_type(conn->private_data,
1688 struct dcesrv_connection);
1689 dcesrv_terminate_connection(dce_conn, "dcesrv_sock_recv triggered");
1692 static void dcesrv_sock_send(struct stream_connection *conn, uint16_t flags)
1694 struct dcesrv_connection *dce_conn = talloc_get_type(conn->private_data,
1695 struct dcesrv_connection);
1696 dcesrv_terminate_connection(dce_conn, "dcesrv_sock_send triggered");
1700 static const struct stream_server_ops dcesrv_stream_ops = {
1702 .accept_connection = dcesrv_sock_accept,
1703 .recv_handler = dcesrv_sock_recv,
1704 .send_handler = dcesrv_sock_send,
1707 static NTSTATUS dcesrv_add_ep_unix(struct dcesrv_context *dce_ctx,
1708 struct loadparm_context *lp_ctx,
1709 struct dcesrv_endpoint *e,
1710 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1712 struct dcesrv_socket_context *dcesrv_sock;
1716 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1717 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1719 /* remember the endpoint of this socket */
1720 dcesrv_sock->endpoint = e;
1721 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1723 status = stream_setup_socket(event_ctx, lp_ctx,
1724 model_ops, &dcesrv_stream_ops,
1725 "unix", e->ep_description->endpoint, &port,
1726 lpcfg_socket_options(lp_ctx),
1728 if (!NT_STATUS_IS_OK(status)) {
1729 DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n",
1730 e->ep_description->endpoint, nt_errstr(status)));
1736 static NTSTATUS dcesrv_add_ep_ncalrpc(struct dcesrv_context *dce_ctx,
1737 struct loadparm_context *lp_ctx,
1738 struct dcesrv_endpoint *e,
1739 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1741 struct dcesrv_socket_context *dcesrv_sock;
1746 if (!e->ep_description->endpoint) {
1747 /* No identifier specified: use DEFAULT.
1748 * DO NOT hardcode this value anywhere else. Rather, specify
1749 * no endpoint and let the epmapper worry about it. */
1750 e->ep_description->endpoint = talloc_strdup(dce_ctx, "DEFAULT");
1753 full_path = talloc_asprintf(dce_ctx, "%s/%s", lpcfg_ncalrpc_dir(lp_ctx),
1754 e->ep_description->endpoint);
1756 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1757 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1759 /* remember the endpoint of this socket */
1760 dcesrv_sock->endpoint = e;
1761 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1763 status = stream_setup_socket(event_ctx, lp_ctx,
1764 model_ops, &dcesrv_stream_ops,
1765 "unix", full_path, &port,
1766 lpcfg_socket_options(lp_ctx),
1768 if (!NT_STATUS_IS_OK(status)) {
1769 DEBUG(0,("service_setup_stream_socket(identifier=%s,path=%s) failed - %s\n",
1770 e->ep_description->endpoint, full_path, nt_errstr(status)));
1775 static NTSTATUS dcesrv_add_ep_np(struct dcesrv_context *dce_ctx,
1776 struct loadparm_context *lp_ctx,
1777 struct dcesrv_endpoint *e,
1778 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1780 struct dcesrv_socket_context *dcesrv_sock;
1783 if (e->ep_description->endpoint == NULL) {
1784 DEBUG(0, ("Endpoint mandatory for named pipes\n"));
1785 return NT_STATUS_INVALID_PARAMETER;
1788 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1789 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1791 /* remember the endpoint of this socket */
1792 dcesrv_sock->endpoint = e;
1793 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1795 status = tstream_setup_named_pipe(event_ctx, lp_ctx,
1796 model_ops, &dcesrv_stream_ops,
1797 e->ep_description->endpoint,
1799 if (!NT_STATUS_IS_OK(status)) {
1800 DEBUG(0,("stream_setup_named_pipe(pipe=%s) failed - %s\n",
1801 e->ep_description->endpoint, nt_errstr(status)));
1805 return NT_STATUS_OK;
1809 add a socket address to the list of events, one event per dcerpc endpoint
1811 static NTSTATUS add_socket_rpc_tcp_iface(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e,
1812 struct tevent_context *event_ctx, const struct model_ops *model_ops,
1813 const char *address)
1815 struct dcesrv_socket_context *dcesrv_sock;
1819 if (e->ep_description->endpoint) {
1820 port = atoi(e->ep_description->endpoint);
1823 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1824 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1826 /* remember the endpoint of this socket */
1827 dcesrv_sock->endpoint = e;
1828 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1830 status = stream_setup_socket(event_ctx, dce_ctx->lp_ctx,
1831 model_ops, &dcesrv_stream_ops,
1832 "ipv4", address, &port,
1833 lpcfg_socket_options(dce_ctx->lp_ctx),
1835 if (!NT_STATUS_IS_OK(status)) {
1836 DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) failed - %s\n",
1837 address, port, nt_errstr(status)));
1840 if (e->ep_description->endpoint == NULL) {
1841 e->ep_description->endpoint = talloc_asprintf(dce_ctx, "%d", port);
1847 #include "lib/socket/netif.h" /* Included here to work around the fact that socket_wrapper redefines bind() */
1849 static NTSTATUS dcesrv_add_ep_tcp(struct dcesrv_context *dce_ctx,
1850 struct loadparm_context *lp_ctx,
1851 struct dcesrv_endpoint *e,
1852 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1856 /* Add TCP/IP sockets */
1857 if (lpcfg_interfaces(lp_ctx) && lpcfg_bind_interfaces_only(lp_ctx)) {
1860 struct interface *ifaces;
1862 load_interfaces(dce_ctx, lpcfg_interfaces(lp_ctx), &ifaces);
1864 num_interfaces = iface_count(ifaces);
1865 for(i = 0; i < num_interfaces; i++) {
1866 const char *address = iface_n_ip(ifaces, i);
1867 status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, address);
1868 NT_STATUS_NOT_OK_RETURN(status);
1871 status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops,
1872 lpcfg_socket_address(lp_ctx));
1873 NT_STATUS_NOT_OK_RETURN(status);
1876 return NT_STATUS_OK;
1879 NTSTATUS dcesrv_add_ep(struct dcesrv_context *dce_ctx,
1880 struct loadparm_context *lp_ctx,
1881 struct dcesrv_endpoint *e,
1882 struct tevent_context *event_ctx,
1883 const struct model_ops *model_ops)
1885 switch (e->ep_description->transport) {
1886 case NCACN_UNIX_STREAM:
1887 return dcesrv_add_ep_unix(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1890 return dcesrv_add_ep_ncalrpc(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1893 return dcesrv_add_ep_tcp(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1896 return dcesrv_add_ep_np(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1899 return NT_STATUS_NOT_SUPPORTED;