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"
34 /* this is only used when the client asks for an unknown interface */
35 #define DUMMY_ASSOC_GROUP 0x0FFFFFFF
37 extern const struct dcesrv_interface dcesrv_mgmt_interface;
41 find an association group given a assoc_group_id
43 static struct dcesrv_assoc_group *dcesrv_assoc_group_find(struct dcesrv_context *dce_ctx,
48 id_ptr = idr_find(dce_ctx->assoc_groups_idr, id);
52 return talloc_get_type_abort(id_ptr, struct dcesrv_assoc_group);
56 take a reference to an existing association group
58 static struct dcesrv_assoc_group *dcesrv_assoc_group_reference(TALLOC_CTX *mem_ctx,
59 struct dcesrv_context *dce_ctx,
62 struct dcesrv_assoc_group *assoc_group;
64 assoc_group = dcesrv_assoc_group_find(dce_ctx, id);
65 if (assoc_group == NULL) {
66 DEBUG(0,(__location__ ": Failed to find assoc_group 0x%08x\n", id));
69 return talloc_reference(mem_ctx, assoc_group);
72 static int dcesrv_assoc_group_destructor(struct dcesrv_assoc_group *assoc_group)
75 ret = idr_remove(assoc_group->dce_ctx->assoc_groups_idr, assoc_group->id);
77 DEBUG(0,(__location__ ": Failed to remove assoc_group 0x%08x\n",
84 allocate a new association group
86 static struct dcesrv_assoc_group *dcesrv_assoc_group_new(TALLOC_CTX *mem_ctx,
87 struct dcesrv_context *dce_ctx)
89 struct dcesrv_assoc_group *assoc_group;
92 assoc_group = talloc_zero(mem_ctx, struct dcesrv_assoc_group);
93 if (assoc_group == NULL) {
97 id = idr_get_new_random(dce_ctx->assoc_groups_idr, assoc_group, UINT16_MAX);
99 talloc_free(assoc_group);
100 DEBUG(0,(__location__ ": Out of association groups!\n"));
104 assoc_group->id = id;
105 assoc_group->dce_ctx = dce_ctx;
107 talloc_set_destructor(assoc_group, dcesrv_assoc_group_destructor);
114 see if two endpoints match
116 static bool endpoints_match(const struct dcerpc_binding *ep1,
117 const struct dcerpc_binding *ep2)
119 if (ep1->transport != ep2->transport) {
123 if (!ep1->endpoint || !ep2->endpoint) {
124 return ep1->endpoint == ep2->endpoint;
127 if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
134 find an endpoint in the dcesrv_context
136 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
137 const struct dcerpc_binding *ep_description)
139 struct dcesrv_endpoint *ep;
140 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
141 if (endpoints_match(ep->ep_description, ep_description)) {
149 find a registered context_id from a bind or alter_context
151 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn,
154 struct dcesrv_connection_context *c;
155 for (c=conn->contexts;c;c=c->next) {
156 if (c->context_id == context_id) return c;
162 see if a uuid and if_version match to an interface
164 static bool interface_match(const struct dcesrv_interface *if1,
165 const struct dcesrv_interface *if2)
167 return (if1->syntax_id.if_version == if2->syntax_id.if_version &&
168 GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
172 find the interface operations on an endpoint
174 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
175 const struct dcesrv_interface *iface)
177 struct dcesrv_if_list *ifl;
178 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
179 if (interface_match(&(ifl->iface), iface)) {
180 return &(ifl->iface);
187 see if a uuid and if_version match to an interface
189 static bool interface_match_by_uuid(const struct dcesrv_interface *iface,
190 const struct GUID *uuid, uint32_t if_version)
192 return (iface->syntax_id.if_version == if_version &&
193 GUID_equal(&iface->syntax_id.uuid, uuid));
197 find the interface operations on an endpoint by uuid
199 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
200 const struct GUID *uuid, uint32_t if_version)
202 struct dcesrv_if_list *ifl;
203 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
204 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
205 return &(ifl->iface);
212 find the earlier parts of a fragmented call awaiting reassembily
214 static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
216 struct dcesrv_call_state *c;
217 for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
218 if (c->pkt.call_id == call_id) {
226 register an interface on an endpoint
228 _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
230 const struct dcesrv_interface *iface,
231 const struct security_descriptor *sd)
233 struct dcesrv_endpoint *ep;
234 struct dcesrv_if_list *ifl;
235 struct dcerpc_binding *binding;
239 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
241 if (NT_STATUS_IS_ERR(status)) {
242 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
246 /* check if this endpoint exists
248 if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
249 ep = talloc(dce_ctx, struct dcesrv_endpoint);
251 return NT_STATUS_NO_MEMORY;
254 ep->ep_description = talloc_reference(ep, binding);
257 /* add mgmt interface */
258 ifl = talloc(dce_ctx, struct dcesrv_if_list);
260 return NT_STATUS_NO_MEMORY;
263 memcpy(&(ifl->iface), &dcesrv_mgmt_interface,
264 sizeof(struct dcesrv_interface));
266 DLIST_ADD(ep->interface_list, ifl);
269 /* see if the interface is already registered on te endpoint */
270 if (find_interface(ep, iface)!=NULL) {
271 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
272 iface->name, ep_name));
273 return NT_STATUS_OBJECT_NAME_COLLISION;
276 /* talloc a new interface list element */
277 ifl = talloc(dce_ctx, struct dcesrv_if_list);
279 return NT_STATUS_NO_MEMORY;
282 /* copy the given interface struct to the one on the endpoints interface list */
283 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
285 /* if we have a security descriptor given,
286 * we should see if we can set it up on the endpoint
289 /* if there's currently no security descriptor given on the endpoint
292 if (ep->sd == NULL) {
293 ep->sd = security_descriptor_copy(dce_ctx, sd);
296 /* if now there's no security descriptor given on the endpoint
297 * something goes wrong, either we failed to copy the security descriptor
298 * or there was already one on the endpoint
300 if (ep->sd != NULL) {
301 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
302 " on endpoint '%s'\n",
303 iface->name, ep_name));
304 if (add_ep) free(ep);
306 return NT_STATUS_OBJECT_NAME_COLLISION;
310 /* finally add the interface on the endpoint */
311 DLIST_ADD(ep->interface_list, ifl);
313 /* if it's a new endpoint add it to the dcesrv_context */
315 DLIST_ADD(dce_ctx->endpoint_list, ep);
318 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
319 iface->name, ep_name));
324 NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
325 DATA_BLOB *session_key)
327 if (p->auth_state.session_info->session_key.length) {
328 *session_key = p->auth_state.session_info->session_key;
331 return NT_STATUS_NO_USER_SESSION_KEY;
334 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *c,
335 DATA_BLOB *session_key)
337 return dcerpc_generic_session_key(NULL, session_key);
341 fetch the user session key - may be default (above) or the SMB session key
343 The key is always truncated to 16 bytes
345 _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
346 DATA_BLOB *session_key)
348 NTSTATUS status = p->auth_state.session_key(p, session_key);
349 if (!NT_STATUS_IS_OK(status)) {
353 session_key->length = MIN(session_key->length, 16);
359 connect to a dcerpc endpoint
361 _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
363 const struct dcesrv_endpoint *ep,
364 struct auth_session_info *session_info,
365 struct tevent_context *event_ctx,
366 struct messaging_context *msg_ctx,
367 struct server_id server_id,
368 uint32_t state_flags,
369 struct dcesrv_connection **_p)
371 struct dcesrv_connection *p;
374 return NT_STATUS_ACCESS_DENIED;
377 p = talloc(mem_ctx, struct dcesrv_connection);
378 NT_STATUS_HAVE_NO_MEMORY(p);
380 if (!talloc_reference(p, session_info)) {
382 return NT_STATUS_NO_MEMORY;
385 p->dce_ctx = dce_ctx;
389 p->packet_log_dir = lpcfg_lockdir(dce_ctx->lp_ctx);
390 p->incoming_fragmented_call_list = NULL;
391 p->pending_call_list = NULL;
392 p->cli_max_recv_frag = 0;
393 p->partial_input = data_blob(NULL, 0);
394 p->auth_state.auth_info = NULL;
395 p->auth_state.gensec_security = NULL;
396 p->auth_state.session_info = session_info;
397 p->auth_state.session_key = dcesrv_generic_session_key;
398 p->event_ctx = event_ctx;
399 p->msg_ctx = msg_ctx;
400 p->server_id = server_id;
401 p->processing = false;
402 p->state_flags = state_flags;
403 ZERO_STRUCT(p->transport);
409 static void dcesrv_init_hdr(struct ncacn_packet *pkt, bool bigendian)
412 pkt->rpc_vers_minor = 0;
416 pkt->drep[0] = DCERPC_DREP_LE;
424 move a call from an existing linked list to the specified list. This
425 prevents bugs where we forget to remove the call from a previous
428 static void dcesrv_call_set_list(struct dcesrv_call_state *call,
429 enum dcesrv_call_list list)
431 switch (call->list) {
432 case DCESRV_LIST_NONE:
434 case DCESRV_LIST_CALL_LIST:
435 DLIST_REMOVE(call->conn->call_list, call);
437 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
438 DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
440 case DCESRV_LIST_PENDING_CALL_LIST:
441 DLIST_REMOVE(call->conn->pending_call_list, call);
446 case DCESRV_LIST_NONE:
448 case DCESRV_LIST_CALL_LIST:
449 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
451 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
452 DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
454 case DCESRV_LIST_PENDING_CALL_LIST:
455 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
461 return a dcerpc fault
463 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
465 struct ncacn_packet pkt;
466 struct data_blob_list_item *rep;
470 /* setup a bind_ack */
471 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
473 pkt.call_id = call->pkt.call_id;
474 pkt.ptype = DCERPC_PKT_FAULT;
475 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
476 pkt.u.fault.alloc_hint = 0;
477 pkt.u.fault.context_id = 0;
478 pkt.u.fault.cancel_count = 0;
479 pkt.u.fault.status = fault_code;
482 pkt.u.fault._pad = data_blob_const(zeros, sizeof(zeros));
484 rep = talloc(call, struct data_blob_list_item);
486 return NT_STATUS_NO_MEMORY;
489 status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
490 if (!NT_STATUS_IS_OK(status)) {
494 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
496 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
497 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
499 if (call->conn->call_list && call->conn->call_list->replies) {
500 if (call->conn->transport.report_output_data) {
501 call->conn->transport.report_output_data(call->conn);
510 return a dcerpc bind_nak
512 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
514 struct ncacn_packet pkt;
515 struct data_blob_list_item *rep;
518 /* setup a bind_nak */
519 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
521 pkt.call_id = call->pkt.call_id;
522 pkt.ptype = DCERPC_PKT_BIND_NAK;
523 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
524 pkt.u.bind_nak.reject_reason = reason;
525 if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
526 pkt.u.bind_nak.versions.v.num_versions = 0;
529 rep = talloc(call, struct data_blob_list_item);
531 return NT_STATUS_NO_MEMORY;
534 status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
535 if (!NT_STATUS_IS_OK(status)) {
539 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
541 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
542 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
544 if (call->conn->call_list && call->conn->call_list->replies) {
545 if (call->conn->transport.report_output_data) {
546 call->conn->transport.report_output_data(call->conn);
553 static int dcesrv_connection_context_destructor(struct dcesrv_connection_context *c)
555 DLIST_REMOVE(c->conn->contexts, c);
557 if (c->iface && c->iface->unbind) {
558 c->iface->unbind(c, c->iface);
565 handle a bind request
567 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
569 uint32_t if_version, transfer_syntax_version;
570 struct GUID uuid, *transfer_syntax_uuid;
571 struct ncacn_packet pkt;
572 struct data_blob_list_item *rep;
574 uint32_t result=0, reason=0;
576 const struct dcesrv_interface *iface;
577 uint32_t extra_flags = 0;
580 if provided, check the assoc_group is valid
582 if (call->pkt.u.bind.assoc_group_id != 0 &&
583 lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
584 dcesrv_assoc_group_find(call->conn->dce_ctx, call->pkt.u.bind.assoc_group_id) == NULL) {
585 return dcesrv_bind_nak(call, 0);
588 if (call->pkt.u.bind.num_contexts < 1 ||
589 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
590 return dcesrv_bind_nak(call, 0);
593 context_id = call->pkt.u.bind.ctx_list[0].context_id;
595 /* you can't bind twice on one context */
596 if (dcesrv_find_context(call->conn, context_id) != NULL) {
597 return dcesrv_bind_nak(call, 0);
600 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
601 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
603 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
604 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
605 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
606 ndr_transfer_syntax.if_version != transfer_syntax_version) {
607 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
608 /* we only do NDR encoded dcerpc */
609 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
610 talloc_free(uuid_str);
611 return dcesrv_bind_nak(call, 0);
614 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
616 char *uuid_str = GUID_string(call, &uuid);
617 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
618 talloc_free(uuid_str);
620 /* we don't know about that interface */
621 result = DCERPC_BIND_PROVIDER_REJECT;
622 reason = DCERPC_BIND_REASON_ASYNTAX;
626 /* add this context to the list of available context_ids */
627 struct dcesrv_connection_context *context = talloc(call->conn,
628 struct dcesrv_connection_context);
629 if (context == NULL) {
630 return dcesrv_bind_nak(call, 0);
632 context->conn = call->conn;
633 context->iface = iface;
634 context->context_id = context_id;
635 if (call->pkt.u.bind.assoc_group_id != 0) {
636 context->assoc_group = dcesrv_assoc_group_reference(context,
638 call->pkt.u.bind.assoc_group_id);
640 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
642 if (context->assoc_group == NULL) {
643 talloc_free(context);
644 return dcesrv_bind_nak(call, 0);
646 context->private_data = NULL;
647 DLIST_ADD(call->conn->contexts, context);
648 call->context = context;
649 talloc_set_destructor(context, dcesrv_connection_context_destructor);
651 status = iface->bind(call, iface, if_version);
652 if (!NT_STATUS_IS_OK(status)) {
653 char *uuid_str = GUID_string(call, &uuid);
654 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
655 uuid_str, if_version, nt_errstr(status)));
656 talloc_free(uuid_str);
657 /* we don't want to trigger the iface->unbind() hook */
658 context->iface = NULL;
659 talloc_free(call->context);
660 call->context = NULL;
661 return dcesrv_bind_nak(call, 0);
665 if (call->conn->cli_max_recv_frag == 0) {
666 call->conn->cli_max_recv_frag = MIN(0x2000, call->pkt.u.bind.max_recv_frag);
669 if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) &&
670 lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","header signing", false)) {
671 call->conn->state_flags |= DCESRV_CALL_STATE_FLAG_HEADER_SIGNING;
672 extra_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
675 /* handle any authentication that is being requested */
676 if (!dcesrv_auth_bind(call)) {
677 talloc_free(call->context);
678 call->context = NULL;
679 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
682 /* setup a bind_ack */
683 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
685 pkt.call_id = call->pkt.call_id;
686 pkt.ptype = DCERPC_PKT_BIND_ACK;
687 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
688 pkt.u.bind_ack.max_xmit_frag = call->conn->cli_max_recv_frag;
689 pkt.u.bind_ack.max_recv_frag = 0x2000;
692 make it possible for iface->bind() to specify the assoc_group_id
693 This helps the openchange mapiproxy plugin to work correctly.
698 pkt.u.bind_ack.assoc_group_id = call->context->assoc_group->id;
700 pkt.u.bind_ack.assoc_group_id = DUMMY_ASSOC_GROUP;
704 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
705 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
707 pkt.u.bind_ack.secondary_address = "";
709 pkt.u.bind_ack.num_results = 1;
710 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
711 if (!pkt.u.bind_ack.ctx_list) {
712 talloc_free(call->context);
713 call->context = NULL;
714 return NT_STATUS_NO_MEMORY;
716 pkt.u.bind_ack.ctx_list[0].result = result;
717 pkt.u.bind_ack.ctx_list[0].reason = reason;
718 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
719 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
721 status = dcesrv_auth_bind_ack(call, &pkt);
722 if (!NT_STATUS_IS_OK(status)) {
723 talloc_free(call->context);
724 call->context = NULL;
725 return dcesrv_bind_nak(call, 0);
728 rep = talloc(call, struct data_blob_list_item);
730 talloc_free(call->context);
731 call->context = NULL;
732 return NT_STATUS_NO_MEMORY;
735 status = ncacn_push_auth(&rep->blob, call, &pkt,
736 call->conn->auth_state.auth_info);
737 if (!NT_STATUS_IS_OK(status)) {
738 talloc_free(call->context);
739 call->context = NULL;
743 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
745 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
746 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
748 if (call->conn->call_list && call->conn->call_list->replies) {
749 if (call->conn->transport.report_output_data) {
750 call->conn->transport.report_output_data(call->conn);
759 handle a auth3 request
761 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
763 /* handle the auth3 in the auth code */
764 if (!dcesrv_auth_auth3(call)) {
765 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
770 /* we don't send a reply to a auth3 request, except by a
777 handle a bind request
779 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
781 uint32_t if_version, transfer_syntax_version;
782 struct dcesrv_connection_context *context;
783 const struct dcesrv_interface *iface;
784 struct GUID uuid, *transfer_syntax_uuid;
787 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
788 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
790 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
791 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
792 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
793 ndr_transfer_syntax.if_version != transfer_syntax_version) {
794 /* we only do NDR encoded dcerpc */
795 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
798 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
800 char *uuid_str = GUID_string(call, &uuid);
801 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
802 talloc_free(uuid_str);
803 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
806 /* add this context to the list of available context_ids */
807 context = talloc(call->conn, struct dcesrv_connection_context);
808 if (context == NULL) {
809 return NT_STATUS_NO_MEMORY;
811 context->conn = call->conn;
812 context->iface = iface;
813 context->context_id = context_id;
814 if (call->pkt.u.alter.assoc_group_id != 0) {
815 context->assoc_group = dcesrv_assoc_group_reference(context,
817 call->pkt.u.alter.assoc_group_id);
819 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
821 if (context->assoc_group == NULL) {
822 talloc_free(context);
823 call->context = NULL;
824 return NT_STATUS_NO_MEMORY;
826 context->private_data = NULL;
827 DLIST_ADD(call->conn->contexts, context);
828 call->context = context;
829 talloc_set_destructor(context, dcesrv_connection_context_destructor);
831 status = iface->bind(call, iface, if_version);
832 if (!NT_STATUS_IS_OK(status)) {
833 /* we don't want to trigger the iface->unbind() hook */
834 context->iface = NULL;
835 talloc_free(context);
836 call->context = NULL;
845 handle a alter context request
847 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
849 struct ncacn_packet pkt;
850 struct data_blob_list_item *rep;
852 uint32_t result=0, reason=0;
855 /* handle any authentication that is being requested */
856 if (!dcesrv_auth_alter(call)) {
857 /* TODO: work out the right reject code */
858 result = DCERPC_BIND_PROVIDER_REJECT;
859 reason = DCERPC_BIND_REASON_ASYNTAX;
862 context_id = call->pkt.u.alter.ctx_list[0].context_id;
864 /* see if they are asking for a new interface */
866 call->context = dcesrv_find_context(call->conn, context_id);
867 if (!call->context) {
868 status = dcesrv_alter_new_context(call, context_id);
869 if (!NT_STATUS_IS_OK(status)) {
870 result = DCERPC_BIND_PROVIDER_REJECT;
871 reason = DCERPC_BIND_REASON_ASYNTAX;
877 call->pkt.u.alter.assoc_group_id != 0 &&
878 lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
879 call->pkt.u.alter.assoc_group_id != call->context->assoc_group->id) {
880 DEBUG(0,(__location__ ": Failed attempt to use new assoc_group in alter context (0x%08x 0x%08x)\n",
881 call->context->assoc_group->id, call->pkt.u.alter.assoc_group_id));
882 /* TODO: can they ask for a new association group? */
883 result = DCERPC_BIND_PROVIDER_REJECT;
884 reason = DCERPC_BIND_REASON_ASYNTAX;
887 /* setup a alter_resp */
888 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
890 pkt.call_id = call->pkt.call_id;
891 pkt.ptype = DCERPC_PKT_ALTER_RESP;
892 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
893 pkt.u.alter_resp.max_xmit_frag = 0x2000;
894 pkt.u.alter_resp.max_recv_frag = 0x2000;
896 pkt.u.alter_resp.assoc_group_id = call->context->assoc_group->id;
898 pkt.u.alter_resp.assoc_group_id = 0;
900 pkt.u.alter_resp.num_results = 1;
901 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
902 if (!pkt.u.alter_resp.ctx_list) {
903 return NT_STATUS_NO_MEMORY;
905 pkt.u.alter_resp.ctx_list[0].result = result;
906 pkt.u.alter_resp.ctx_list[0].reason = reason;
907 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
908 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
909 pkt.u.alter_resp.secondary_address = "";
911 status = dcesrv_auth_alter_ack(call, &pkt);
912 if (!NT_STATUS_IS_OK(status)) {
913 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
914 || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
915 || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
916 || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
917 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
919 return dcesrv_fault(call, 0);
922 rep = talloc(call, struct data_blob_list_item);
924 return NT_STATUS_NO_MEMORY;
927 status = ncacn_push_auth(&rep->blob, call, &pkt, call->conn->auth_state.auth_info);
928 if (!NT_STATUS_IS_OK(status)) {
932 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
934 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
935 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
937 if (call->conn->call_list && call->conn->call_list->replies) {
938 if (call->conn->transport.report_output_data) {
939 call->conn->transport.report_output_data(call->conn);
947 possibly save the call for inspection with ndrdump
949 static void dcesrv_save_call(struct dcesrv_call_state *call, const char *why)
954 dump_dir = lpcfg_parm_string(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv", "stubs directory");
958 fname = talloc_asprintf(call, "%s/RPC-%s-%u-%s.dat",
960 call->context->iface->name,
961 call->pkt.u.request.opnum,
963 if (file_save(fname, call->pkt.u.request.stub_and_verifier.data, call->pkt.u.request.stub_and_verifier.length)) {
964 DEBUG(0,("RPC SAVED %s\n", fname));
971 handle a dcerpc request packet
973 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
975 struct ndr_pull *pull;
977 struct dcesrv_connection_context *context;
979 /* if authenticated, and the mech we use can't do async replies, don't use them... */
980 if (call->conn->auth_state.gensec_security &&
981 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
982 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
985 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
986 if (context == NULL) {
987 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
990 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
991 NT_STATUS_HAVE_NO_MEMORY(pull);
993 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
995 call->context = context;
996 call->ndr_pull = pull;
998 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
999 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1002 /* unravel the NDR for the packet */
1003 status = context->iface->ndr_pull(call, call, pull, &call->r);
1004 if (!NT_STATUS_IS_OK(status)) {
1005 if (call->fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
1006 /* we got an unknown call */
1007 DEBUG(3,(__location__ ": Unknown RPC call %u on %s\n",
1008 call->pkt.u.request.opnum, context->iface->name));
1009 dcesrv_save_call(call, "unknown");
1011 dcesrv_save_call(call, "pullfail");
1013 return dcesrv_fault(call, call->fault_code);
1016 if (pull->offset != pull->data_size) {
1017 dcesrv_save_call(call, "extrabytes");
1018 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
1019 pull->data_size - pull->offset));
1022 /* call the dispatch function */
1023 status = context->iface->dispatch(call, call, call->r);
1024 if (!NT_STATUS_IS_OK(status)) {
1025 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
1026 context->iface->name,
1027 call->pkt.u.request.opnum,
1028 dcerpc_errstr(pull, call->fault_code)));
1029 return dcesrv_fault(call, call->fault_code);
1032 /* add the call to the pending list */
1033 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
1035 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
1036 return NT_STATUS_OK;
1039 return dcesrv_reply(call);
1042 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
1044 struct ndr_push *push;
1047 uint32_t total_length, chunk_size;
1048 struct dcesrv_connection_context *context = call->context;
1049 size_t sig_size = 0;
1051 /* call the reply function */
1052 status = context->iface->reply(call, call, call->r);
1053 if (!NT_STATUS_IS_OK(status)) {
1054 return dcesrv_fault(call, call->fault_code);
1057 /* form the reply NDR */
1058 push = ndr_push_init_ctx(call);
1059 NT_STATUS_HAVE_NO_MEMORY(push);
1061 /* carry over the pointer count to the reply in case we are
1062 using full pointer. See NDR specification for full
1064 push->ptr_count = call->ndr_pull->ptr_count;
1066 if (lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
1067 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1070 status = context->iface->ndr_push(call, call, push, call->r);
1071 if (!NT_STATUS_IS_OK(status)) {
1072 return dcesrv_fault(call, call->fault_code);
1075 stub = ndr_push_blob(push);
1077 total_length = stub.length;
1079 /* we can write a full max_recv_frag size, minus the dcerpc
1080 request header size */
1081 chunk_size = call->conn->cli_max_recv_frag;
1082 chunk_size -= DCERPC_REQUEST_LENGTH;
1083 if (call->conn->auth_state.auth_info &&
1084 call->conn->auth_state.gensec_security) {
1085 sig_size = gensec_sig_size(call->conn->auth_state.gensec_security,
1086 call->conn->cli_max_recv_frag);
1088 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1089 chunk_size -= sig_size;
1092 chunk_size -= (chunk_size % 16);
1096 struct data_blob_list_item *rep;
1097 struct ncacn_packet pkt;
1099 rep = talloc(call, struct data_blob_list_item);
1100 NT_STATUS_HAVE_NO_MEMORY(rep);
1102 length = MIN(chunk_size, stub.length);
1104 /* form the dcerpc response packet */
1105 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
1106 pkt.auth_length = 0;
1107 pkt.call_id = call->pkt.call_id;
1108 pkt.ptype = DCERPC_PKT_RESPONSE;
1110 if (stub.length == total_length) {
1111 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1113 if (length == stub.length) {
1114 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1116 pkt.u.response.alloc_hint = stub.length;
1117 pkt.u.response.context_id = call->pkt.u.request.context_id;
1118 pkt.u.response.cancel_count = 0;
1119 pkt.u.response.stub_and_verifier.data = stub.data;
1120 pkt.u.response.stub_and_verifier.length = length;
1122 if (!dcesrv_auth_response(call, &rep->blob, sig_size, &pkt)) {
1123 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
1126 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
1128 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
1130 stub.data += length;
1131 stub.length -= length;
1132 } while (stub.length != 0);
1134 /* move the call from the pending to the finished calls list */
1135 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
1137 if (call->conn->call_list && call->conn->call_list->replies) {
1138 if (call->conn->transport.report_output_data) {
1139 call->conn->transport.report_output_data(call->conn);
1143 return NT_STATUS_OK;
1147 remove the call from the right list when freed
1149 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1151 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1155 _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_local_address(struct dcesrv_connection *conn)
1157 return conn->local_address;
1160 _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_remote_address(struct dcesrv_connection *conn)
1162 return conn->remote_address;
1166 process some input to a dcerpc endpoint server.
1168 NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
1169 struct ncacn_packet *pkt,
1173 struct dcesrv_call_state *call;
1175 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1177 data_blob_free(&blob);
1179 return NT_STATUS_NO_MEMORY;
1181 call->conn = dce_conn;
1182 call->event_ctx = dce_conn->event_ctx;
1183 call->msg_ctx = dce_conn->msg_ctx;
1184 call->state_flags = call->conn->state_flags;
1185 call->time = timeval_current();
1186 call->list = DCESRV_LIST_NONE;
1188 talloc_steal(call, pkt);
1189 talloc_steal(call, blob.data);
1192 talloc_set_destructor(call, dcesrv_call_dequeue);
1194 /* we have to check the signing here, before combining the
1196 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1197 !dcesrv_auth_request(call, &blob)) {
1198 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1201 /* see if this is a continued packet */
1202 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1203 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1204 struct dcesrv_call_state *call2 = call;
1205 uint32_t alloc_size;
1207 /* we only allow fragmented requests, no other packet types */
1208 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1209 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1212 /* this is a continuation of an existing call - find the call then
1213 tack it on the end */
1214 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1216 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1219 if (call->pkt.ptype != call2->pkt.ptype) {
1220 /* trying to play silly buggers are we? */
1221 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1224 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1225 call2->pkt.u.request.stub_and_verifier.length;
1226 if (call->pkt.u.request.alloc_hint > alloc_size) {
1227 alloc_size = call->pkt.u.request.alloc_hint;
1230 call->pkt.u.request.stub_and_verifier.data =
1231 talloc_realloc(call,
1232 call->pkt.u.request.stub_and_verifier.data,
1233 uint8_t, alloc_size);
1234 if (!call->pkt.u.request.stub_and_verifier.data) {
1235 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1237 memcpy(call->pkt.u.request.stub_and_verifier.data +
1238 call->pkt.u.request.stub_and_verifier.length,
1239 call2->pkt.u.request.stub_and_verifier.data,
1240 call2->pkt.u.request.stub_and_verifier.length);
1241 call->pkt.u.request.stub_and_verifier.length +=
1242 call2->pkt.u.request.stub_and_verifier.length;
1244 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1249 /* this may not be the last pdu in the chain - if its isn't then
1250 just put it on the incoming_fragmented_call_list and wait for the rest */
1251 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1252 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1253 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1254 return NT_STATUS_OK;
1257 /* This removes any fragments we may have had stashed away */
1258 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1260 switch (call->pkt.ptype) {
1261 case DCERPC_PKT_BIND:
1262 status = dcesrv_bind(call);
1264 case DCERPC_PKT_AUTH3:
1265 status = dcesrv_auth3(call);
1267 case DCERPC_PKT_ALTER:
1268 status = dcesrv_alter(call);
1270 case DCERPC_PKT_REQUEST:
1271 status = dcesrv_request(call);
1274 status = NT_STATUS_INVALID_PARAMETER;
1278 /* if we are going to be sending a reply then add
1279 it to the list of pending calls. We add it to the end to keep the call
1280 list in the order we will answer */
1281 if (!NT_STATUS_IS_OK(status)) {
1288 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1289 struct loadparm_context *lp_ctx,
1290 const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1293 struct dcesrv_context *dce_ctx;
1296 if (!endpoint_servers) {
1297 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1298 return NT_STATUS_INTERNAL_ERROR;
1301 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1302 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1303 dce_ctx->endpoint_list = NULL;
1304 dce_ctx->lp_ctx = lp_ctx;
1305 dce_ctx->assoc_groups_idr = idr_init(dce_ctx);
1306 NT_STATUS_HAVE_NO_MEMORY(dce_ctx->assoc_groups_idr);
1308 for (i=0;endpoint_servers[i];i++) {
1309 const struct dcesrv_endpoint_server *ep_server;
1311 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1313 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1314 return NT_STATUS_INTERNAL_ERROR;
1317 status = ep_server->init_server(dce_ctx, ep_server);
1318 if (!NT_STATUS_IS_OK(status)) {
1319 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1320 nt_errstr(status)));
1325 *_dce_ctx = dce_ctx;
1326 return NT_STATUS_OK;
1329 /* the list of currently registered DCERPC endpoint servers.
1331 static struct ep_server {
1332 struct dcesrv_endpoint_server *ep_server;
1333 } *ep_servers = NULL;
1334 static int num_ep_servers;
1337 register a DCERPC endpoint server.
1339 The 'name' can be later used by other backends to find the operations
1340 structure for this backend.
1342 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1344 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1346 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1348 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1349 /* its already registered! */
1350 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1352 return NT_STATUS_OBJECT_NAME_COLLISION;
1355 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1357 smb_panic("out of memory in dcerpc_register");
1360 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1361 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1365 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1368 return NT_STATUS_OK;
1372 return the operations structure for a named backend of the specified type
1374 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1378 for (i=0;i<num_ep_servers;i++) {
1379 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1380 return ep_servers[i].ep_server;
1387 void dcerpc_server_init(struct loadparm_context *lp_ctx)
1389 static bool initialized;
1390 extern NTSTATUS dcerpc_server_wkssvc_init(void);
1391 extern NTSTATUS dcerpc_server_drsuapi_init(void);
1392 extern NTSTATUS dcerpc_server_winreg_init(void);
1393 extern NTSTATUS dcerpc_server_spoolss_init(void);
1394 extern NTSTATUS dcerpc_server_epmapper_init(void);
1395 extern NTSTATUS dcerpc_server_srvsvc_init(void);
1396 extern NTSTATUS dcerpc_server_netlogon_init(void);
1397 extern NTSTATUS dcerpc_server_rpcecho_init(void);
1398 extern NTSTATUS dcerpc_server_unixinfo_init(void);
1399 extern NTSTATUS dcerpc_server_samr_init(void);
1400 extern NTSTATUS dcerpc_server_remote_init(void);
1401 extern NTSTATUS dcerpc_server_lsa_init(void);
1402 extern NTSTATUS dcerpc_server_browser_init(void);
1403 extern NTSTATUS dcerpc_server_eventlog6_init(void);
1404 init_module_fn static_init[] = { STATIC_dcerpc_server_MODULES };
1405 init_module_fn *shared_init;
1412 shared_init = load_samba_modules(NULL, lp_ctx, "dcerpc_server");
1414 run_init_functions(static_init);
1415 run_init_functions(shared_init);
1417 talloc_free(shared_init);
1421 return the DCERPC module version, and the size of some critical types
1422 This can be used by endpoint server modules to either detect compilation errors, or provide
1423 multiple implementations for different smbd compilation options in one module
1425 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1427 static const struct dcesrv_critical_sizes critical_sizes = {
1428 DCERPC_MODULE_VERSION,
1429 sizeof(struct dcesrv_context),
1430 sizeof(struct dcesrv_endpoint),
1431 sizeof(struct dcesrv_endpoint_server),
1432 sizeof(struct dcesrv_interface),
1433 sizeof(struct dcesrv_if_list),
1434 sizeof(struct dcesrv_connection),
1435 sizeof(struct dcesrv_call_state),
1436 sizeof(struct dcesrv_auth),
1437 sizeof(struct dcesrv_handle)
1440 return &critical_sizes;