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 "librpc/gen_ndr/ndr_dcerpc.h"
25 #include "auth/auth.h"
26 #include "auth/gensec/gensec.h"
27 #include "../lib/util/dlinklist.h"
28 #include "rpc_server/dcerpc_server.h"
29 #include "rpc_server/dcerpc_server_proto.h"
30 #include "librpc/rpc/dcerpc_proto.h"
31 #include "lib/events/events.h"
32 #include "smbd/service_task.h"
33 #include "smbd/service_stream.h"
34 #include "smbd/service.h"
35 #include "system/filesys.h"
36 #include "libcli/security/security.h"
37 #include "param/param.h"
39 /* this is only used when the client asks for an unknown interface */
40 #define DUMMY_ASSOC_GROUP 0x0FFFFFFF
42 extern const struct dcesrv_interface dcesrv_mgmt_interface;
46 find an association group given a assoc_group_id
48 static struct dcesrv_assoc_group *dcesrv_assoc_group_find(struct dcesrv_context *dce_ctx,
53 id_ptr = idr_find(dce_ctx->assoc_groups_idr, id);
57 return talloc_get_type_abort(id_ptr, struct dcesrv_assoc_group);
61 take a reference to an existing association group
63 static struct dcesrv_assoc_group *dcesrv_assoc_group_reference(TALLOC_CTX *mem_ctx,
64 struct dcesrv_context *dce_ctx,
67 struct dcesrv_assoc_group *assoc_group;
69 assoc_group = dcesrv_assoc_group_find(dce_ctx, id);
70 if (assoc_group == NULL) {
71 DEBUG(0,(__location__ ": Failed to find assoc_group 0x%08x\n", id));
74 return talloc_reference(mem_ctx, assoc_group);
77 static int dcesrv_assoc_group_destructor(struct dcesrv_assoc_group *assoc_group)
80 ret = idr_remove(assoc_group->dce_ctx->assoc_groups_idr, assoc_group->id);
82 DEBUG(0,(__location__ ": Failed to remove assoc_group 0x%08x\n",
89 allocate a new association group
91 static struct dcesrv_assoc_group *dcesrv_assoc_group_new(TALLOC_CTX *mem_ctx,
92 struct dcesrv_context *dce_ctx)
94 struct dcesrv_assoc_group *assoc_group;
97 assoc_group = talloc_zero(mem_ctx, struct dcesrv_assoc_group);
98 if (assoc_group == NULL) {
102 id = idr_get_new_random(dce_ctx->assoc_groups_idr, assoc_group, UINT16_MAX);
104 talloc_free(assoc_group);
105 DEBUG(0,(__location__ ": Out of association groups!\n"));
109 assoc_group->id = id;
110 assoc_group->dce_ctx = dce_ctx;
112 talloc_set_destructor(assoc_group, dcesrv_assoc_group_destructor);
119 see if two endpoints match
121 static bool endpoints_match(const struct dcerpc_binding *ep1,
122 const struct dcerpc_binding *ep2)
124 if (ep1->transport != ep2->transport) {
128 if (!ep1->endpoint || !ep2->endpoint) {
129 return ep1->endpoint == ep2->endpoint;
132 if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
139 find an endpoint in the dcesrv_context
141 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
142 const struct dcerpc_binding *ep_description)
144 struct dcesrv_endpoint *ep;
145 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
146 if (endpoints_match(ep->ep_description, ep_description)) {
154 find a registered context_id from a bind or alter_context
156 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn,
159 struct dcesrv_connection_context *c;
160 for (c=conn->contexts;c;c=c->next) {
161 if (c->context_id == context_id) return c;
167 see if a uuid and if_version match to an interface
169 static bool interface_match(const struct dcesrv_interface *if1,
170 const struct dcesrv_interface *if2)
172 return (if1->syntax_id.if_version == if2->syntax_id.if_version &&
173 GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
177 find the interface operations on an endpoint
179 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
180 const struct dcesrv_interface *iface)
182 struct dcesrv_if_list *ifl;
183 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
184 if (interface_match(&(ifl->iface), iface)) {
185 return &(ifl->iface);
192 see if a uuid and if_version match to an interface
194 static bool interface_match_by_uuid(const struct dcesrv_interface *iface,
195 const struct GUID *uuid, uint32_t if_version)
197 return (iface->syntax_id.if_version == if_version &&
198 GUID_equal(&iface->syntax_id.uuid, uuid));
202 find the interface operations on an endpoint by uuid
204 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
205 const struct GUID *uuid, uint32_t if_version)
207 struct dcesrv_if_list *ifl;
208 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
209 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
210 return &(ifl->iface);
217 find the earlier parts of a fragmented call awaiting reassembily
219 static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
221 struct dcesrv_call_state *c;
222 for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
223 if (c->pkt.call_id == call_id) {
231 register an interface on an endpoint
233 _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
235 const struct dcesrv_interface *iface,
236 const struct security_descriptor *sd)
238 struct dcesrv_endpoint *ep;
239 struct dcesrv_if_list *ifl;
240 struct dcerpc_binding *binding;
244 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
246 if (NT_STATUS_IS_ERR(status)) {
247 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
251 /* check if this endpoint exists
253 if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
254 ep = talloc(dce_ctx, struct dcesrv_endpoint);
256 return NT_STATUS_NO_MEMORY;
259 ep->ep_description = talloc_reference(ep, binding);
262 /* add mgmt interface */
263 ifl = talloc(dce_ctx, struct dcesrv_if_list);
265 return NT_STATUS_NO_MEMORY;
268 memcpy(&(ifl->iface), &dcesrv_mgmt_interface,
269 sizeof(struct dcesrv_interface));
271 DLIST_ADD(ep->interface_list, ifl);
274 /* see if the interface is already registered on te endpoint */
275 if (find_interface(ep, iface)!=NULL) {
276 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
277 iface->name, ep_name));
278 return NT_STATUS_OBJECT_NAME_COLLISION;
281 /* talloc a new interface list element */
282 ifl = talloc(dce_ctx, struct dcesrv_if_list);
284 return NT_STATUS_NO_MEMORY;
287 /* copy the given interface struct to the one on the endpoints interface list */
288 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
290 /* if we have a security descriptor given,
291 * we should see if we can set it up on the endpoint
294 /* if there's currently no security descriptor given on the endpoint
297 if (ep->sd == NULL) {
298 ep->sd = security_descriptor_copy(dce_ctx, sd);
301 /* if now there's no security descriptor given on the endpoint
302 * something goes wrong, either we failed to copy the security descriptor
303 * or there was already one on the endpoint
305 if (ep->sd != NULL) {
306 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
307 " on endpoint '%s'\n",
308 iface->name, ep_name));
309 if (add_ep) free(ep);
311 return NT_STATUS_OBJECT_NAME_COLLISION;
315 /* finally add the interface on the endpoint */
316 DLIST_ADD(ep->interface_list, ifl);
318 /* if it's a new endpoint add it to the dcesrv_context */
320 DLIST_ADD(dce_ctx->endpoint_list, ep);
323 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
324 iface->name, ep_name));
329 NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
330 DATA_BLOB *session_key)
332 if (p->auth_state.session_info->session_key.length) {
333 *session_key = p->auth_state.session_info->session_key;
336 return NT_STATUS_NO_USER_SESSION_KEY;
339 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *c,
340 DATA_BLOB *session_key)
342 return dcerpc_generic_session_key(NULL, session_key);
346 fetch the user session key - may be default (above) or the SMB session key
348 The key is always truncated to 16 bytes
350 _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
351 DATA_BLOB *session_key)
353 NTSTATUS status = p->auth_state.session_key(p, session_key);
354 if (!NT_STATUS_IS_OK(status)) {
358 session_key->length = MIN(session_key->length, 16);
364 connect to a dcerpc endpoint
366 _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
368 const struct dcesrv_endpoint *ep,
369 struct auth_session_info *session_info,
370 struct tevent_context *event_ctx,
371 struct messaging_context *msg_ctx,
372 struct server_id server_id,
373 uint32_t state_flags,
374 struct dcesrv_connection **_p)
376 struct dcesrv_connection *p;
379 return NT_STATUS_ACCESS_DENIED;
382 p = talloc(mem_ctx, struct dcesrv_connection);
383 NT_STATUS_HAVE_NO_MEMORY(p);
385 if (!talloc_reference(p, session_info)) {
387 return NT_STATUS_NO_MEMORY;
390 p->dce_ctx = dce_ctx;
394 p->packet_log_dir = lp_lockdir(dce_ctx->lp_ctx);
395 p->incoming_fragmented_call_list = NULL;
396 p->pending_call_list = NULL;
397 p->cli_max_recv_frag = 0;
398 p->partial_input = data_blob(NULL, 0);
399 p->auth_state.auth_info = NULL;
400 p->auth_state.gensec_security = NULL;
401 p->auth_state.session_info = session_info;
402 p->auth_state.session_key = dcesrv_generic_session_key;
403 p->event_ctx = event_ctx;
404 p->msg_ctx = msg_ctx;
405 p->server_id = server_id;
406 p->processing = false;
407 p->state_flags = state_flags;
408 ZERO_STRUCT(p->transport);
414 static void dcesrv_init_hdr(struct ncacn_packet *pkt, bool bigendian)
417 pkt->rpc_vers_minor = 0;
421 pkt->drep[0] = DCERPC_DREP_LE;
429 move a call from an existing linked list to the specified list. This
430 prevents bugs where we forget to remove the call from a previous
433 static void dcesrv_call_set_list(struct dcesrv_call_state *call,
434 enum dcesrv_call_list list)
436 switch (call->list) {
437 case DCESRV_LIST_NONE:
439 case DCESRV_LIST_CALL_LIST:
440 DLIST_REMOVE(call->conn->call_list, call);
442 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
443 DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
445 case DCESRV_LIST_PENDING_CALL_LIST:
446 DLIST_REMOVE(call->conn->pending_call_list, call);
451 case DCESRV_LIST_NONE:
453 case DCESRV_LIST_CALL_LIST:
454 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
456 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
457 DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
459 case DCESRV_LIST_PENDING_CALL_LIST:
460 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
466 return a dcerpc fault
468 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
470 struct ncacn_packet pkt;
471 struct data_blob_list_item *rep;
475 /* setup a bind_ack */
476 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
478 pkt.call_id = call->pkt.call_id;
479 pkt.ptype = DCERPC_PKT_FAULT;
480 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
481 pkt.u.fault.alloc_hint = 0;
482 pkt.u.fault.context_id = 0;
483 pkt.u.fault.cancel_count = 0;
484 pkt.u.fault.status = fault_code;
487 pkt.u.fault._pad = data_blob_const(zeros, sizeof(zeros));
489 rep = talloc(call, struct data_blob_list_item);
491 return NT_STATUS_NO_MEMORY;
494 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
495 if (!NT_STATUS_IS_OK(status)) {
499 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
501 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
502 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
504 if (call->conn->call_list && call->conn->call_list->replies) {
505 if (call->conn->transport.report_output_data) {
506 call->conn->transport.report_output_data(call->conn);
515 return a dcerpc bind_nak
517 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
519 struct ncacn_packet pkt;
520 struct data_blob_list_item *rep;
523 /* setup a bind_nak */
524 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
526 pkt.call_id = call->pkt.call_id;
527 pkt.ptype = DCERPC_PKT_BIND_NAK;
528 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
529 pkt.u.bind_nak.reject_reason = reason;
530 if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
531 pkt.u.bind_nak.versions.v.num_versions = 0;
534 rep = talloc(call, struct data_blob_list_item);
536 return NT_STATUS_NO_MEMORY;
539 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
540 if (!NT_STATUS_IS_OK(status)) {
544 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
546 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
547 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
549 if (call->conn->call_list && call->conn->call_list->replies) {
550 if (call->conn->transport.report_output_data) {
551 call->conn->transport.report_output_data(call->conn);
558 static int dcesrv_connection_context_destructor(struct dcesrv_connection_context *c)
560 DLIST_REMOVE(c->conn->contexts, c);
563 c->iface->unbind(c, c->iface);
570 handle a bind request
572 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
574 uint32_t if_version, transfer_syntax_version;
575 struct GUID uuid, *transfer_syntax_uuid;
576 struct ncacn_packet pkt;
577 struct data_blob_list_item *rep;
579 uint32_t result=0, reason=0;
581 const struct dcesrv_interface *iface;
582 uint32_t extra_flags = 0;
585 if provided, check the assoc_group is valid
587 if (call->pkt.u.bind.assoc_group_id != 0 &&
588 lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
589 dcesrv_assoc_group_find(call->conn->dce_ctx, call->pkt.u.bind.assoc_group_id) == NULL) {
590 return dcesrv_bind_nak(call, 0);
593 if (call->pkt.u.bind.num_contexts < 1 ||
594 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
595 return dcesrv_bind_nak(call, 0);
598 context_id = call->pkt.u.bind.ctx_list[0].context_id;
600 /* you can't bind twice on one context */
601 if (dcesrv_find_context(call->conn, context_id) != NULL) {
602 return dcesrv_bind_nak(call, 0);
605 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
606 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
608 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
609 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
610 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
611 ndr_transfer_syntax.if_version != transfer_syntax_version) {
612 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
613 /* we only do NDR encoded dcerpc */
614 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
615 talloc_free(uuid_str);
616 return dcesrv_bind_nak(call, 0);
619 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
621 char *uuid_str = GUID_string(call, &uuid);
622 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
623 talloc_free(uuid_str);
625 /* we don't know about that interface */
626 result = DCERPC_BIND_PROVIDER_REJECT;
627 reason = DCERPC_BIND_REASON_ASYNTAX;
631 /* add this context to the list of available context_ids */
632 struct dcesrv_connection_context *context = talloc(call->conn,
633 struct dcesrv_connection_context);
634 if (context == NULL) {
635 return dcesrv_bind_nak(call, 0);
637 context->conn = call->conn;
638 context->iface = iface;
639 context->context_id = context_id;
640 if (call->pkt.u.bind.assoc_group_id != 0) {
641 context->assoc_group = dcesrv_assoc_group_reference(context,
643 call->pkt.u.bind.assoc_group_id);
645 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
647 if (context->assoc_group == NULL) {
648 talloc_free(context);
649 return dcesrv_bind_nak(call, 0);
651 context->private_data = NULL;
652 DLIST_ADD(call->conn->contexts, context);
653 call->context = context;
654 talloc_set_destructor(context, dcesrv_connection_context_destructor);
656 status = iface->bind(call, iface);
657 if (!NT_STATUS_IS_OK(status)) {
658 char *uuid_str = GUID_string(call, &uuid);
659 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
660 uuid_str, if_version, nt_errstr(status)));
661 talloc_free(uuid_str);
662 /* we don't want to trigger the iface->unbind() hook */
663 context->iface = NULL;
664 talloc_free(call->context);
665 call->context = NULL;
666 return dcesrv_bind_nak(call, 0);
670 if (call->conn->cli_max_recv_frag == 0) {
671 call->conn->cli_max_recv_frag = MIN(0x2000, call->pkt.u.bind.max_recv_frag);
674 if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) &&
675 lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","header signing", false)) {
676 call->conn->state_flags |= DCESRV_CALL_STATE_FLAG_HEADER_SIGNING;
677 extra_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
680 /* handle any authentication that is being requested */
681 if (!dcesrv_auth_bind(call)) {
682 talloc_free(call->context);
683 call->context = NULL;
684 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
687 /* setup a bind_ack */
688 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
690 pkt.call_id = call->pkt.call_id;
691 pkt.ptype = DCERPC_PKT_BIND_ACK;
692 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
693 pkt.u.bind_ack.max_xmit_frag = call->conn->cli_max_recv_frag;
694 pkt.u.bind_ack.max_recv_frag = 0x2000;
697 make it possible for iface->bind() to specify the assoc_group_id
698 This helps the openchange mapiproxy plugin to work correctly.
703 pkt.u.bind_ack.assoc_group_id = call->context->assoc_group->id;
705 pkt.u.bind_ack.assoc_group_id = DUMMY_ASSOC_GROUP;
709 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
710 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
712 pkt.u.bind_ack.secondary_address = "";
714 pkt.u.bind_ack.num_results = 1;
715 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
716 if (!pkt.u.bind_ack.ctx_list) {
717 talloc_free(call->context);
718 call->context = NULL;
719 return NT_STATUS_NO_MEMORY;
721 pkt.u.bind_ack.ctx_list[0].result = result;
722 pkt.u.bind_ack.ctx_list[0].reason = reason;
723 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
724 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
726 status = dcesrv_auth_bind_ack(call, &pkt);
727 if (!NT_STATUS_IS_OK(status)) {
728 talloc_free(call->context);
729 call->context = NULL;
730 return dcesrv_bind_nak(call, 0);
733 rep = talloc(call, struct data_blob_list_item);
735 talloc_free(call->context);
736 call->context = NULL;
737 return NT_STATUS_NO_MEMORY;
740 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
741 if (!NT_STATUS_IS_OK(status)) {
742 talloc_free(call->context);
743 call->context = NULL;
747 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
749 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
750 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
752 if (call->conn->call_list && call->conn->call_list->replies) {
753 if (call->conn->transport.report_output_data) {
754 call->conn->transport.report_output_data(call->conn);
763 handle a auth3 request
765 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
767 /* handle the auth3 in the auth code */
768 if (!dcesrv_auth_auth3(call)) {
769 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
774 /* we don't send a reply to a auth3 request, except by a
781 handle a bind request
783 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
785 uint32_t if_version, transfer_syntax_version;
786 struct dcesrv_connection_context *context;
787 const struct dcesrv_interface *iface;
788 struct GUID uuid, *transfer_syntax_uuid;
791 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
792 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
794 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
795 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
796 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
797 ndr_transfer_syntax.if_version != transfer_syntax_version) {
798 /* we only do NDR encoded dcerpc */
799 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
802 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
804 char *uuid_str = GUID_string(call, &uuid);
805 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
806 talloc_free(uuid_str);
807 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
810 /* add this context to the list of available context_ids */
811 context = talloc(call->conn, struct dcesrv_connection_context);
812 if (context == NULL) {
813 return NT_STATUS_NO_MEMORY;
815 context->conn = call->conn;
816 context->iface = iface;
817 context->context_id = context_id;
818 if (call->pkt.u.alter.assoc_group_id != 0) {
819 context->assoc_group = dcesrv_assoc_group_reference(context,
821 call->pkt.u.alter.assoc_group_id);
823 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
825 if (context->assoc_group == NULL) {
826 talloc_free(context);
827 call->context = NULL;
828 return NT_STATUS_NO_MEMORY;
830 context->private_data = NULL;
831 DLIST_ADD(call->conn->contexts, context);
832 call->context = context;
833 talloc_set_destructor(context, dcesrv_connection_context_destructor);
835 status = iface->bind(call, iface);
836 if (!NT_STATUS_IS_OK(status)) {
837 /* we don't want to trigger the iface->unbind() hook */
838 context->iface = NULL;
839 talloc_free(context);
840 call->context = NULL;
849 handle a alter context request
851 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
853 struct ncacn_packet pkt;
854 struct data_blob_list_item *rep;
856 uint32_t result=0, reason=0;
859 /* handle any authentication that is being requested */
860 if (!dcesrv_auth_alter(call)) {
861 /* TODO: work out the right reject code */
862 result = DCERPC_BIND_PROVIDER_REJECT;
863 reason = DCERPC_BIND_REASON_ASYNTAX;
866 context_id = call->pkt.u.alter.ctx_list[0].context_id;
868 /* see if they are asking for a new interface */
870 call->context = dcesrv_find_context(call->conn, context_id);
871 if (!call->context) {
872 status = dcesrv_alter_new_context(call, context_id);
873 if (!NT_STATUS_IS_OK(status)) {
874 result = DCERPC_BIND_PROVIDER_REJECT;
875 reason = DCERPC_BIND_REASON_ASYNTAX;
881 call->pkt.u.alter.assoc_group_id != 0 &&
882 lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
883 call->pkt.u.alter.assoc_group_id != call->context->assoc_group->id) {
884 DEBUG(0,(__location__ ": Failed attempt to use new assoc_group in alter context (0x%08x 0x%08x)\n",
885 call->context->assoc_group->id, call->pkt.u.alter.assoc_group_id));
886 /* TODO: can they ask for a new association group? */
887 result = DCERPC_BIND_PROVIDER_REJECT;
888 reason = DCERPC_BIND_REASON_ASYNTAX;
891 /* setup a alter_resp */
892 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
894 pkt.call_id = call->pkt.call_id;
895 pkt.ptype = DCERPC_PKT_ALTER_RESP;
896 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
897 pkt.u.alter_resp.max_xmit_frag = 0x2000;
898 pkt.u.alter_resp.max_recv_frag = 0x2000;
900 pkt.u.alter_resp.assoc_group_id = call->context->assoc_group->id;
902 pkt.u.alter_resp.assoc_group_id = 0;
904 pkt.u.alter_resp.num_results = 1;
905 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
906 if (!pkt.u.alter_resp.ctx_list) {
907 return NT_STATUS_NO_MEMORY;
909 pkt.u.alter_resp.ctx_list[0].result = result;
910 pkt.u.alter_resp.ctx_list[0].reason = reason;
911 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
912 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
913 pkt.u.alter_resp.secondary_address = "";
915 status = dcesrv_auth_alter_ack(call, &pkt);
916 if (!NT_STATUS_IS_OK(status)) {
917 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
918 || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
919 || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
920 || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
921 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
923 return dcesrv_fault(call, 0);
926 rep = talloc(call, struct data_blob_list_item);
928 return NT_STATUS_NO_MEMORY;
931 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
932 if (!NT_STATUS_IS_OK(status)) {
936 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
938 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
939 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
941 if (call->conn->call_list && call->conn->call_list->replies) {
942 if (call->conn->transport.report_output_data) {
943 call->conn->transport.report_output_data(call->conn);
951 handle a dcerpc request packet
953 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
955 struct ndr_pull *pull;
957 struct dcesrv_connection_context *context;
959 /* if authenticated, and the mech we use can't do async replies, don't use them... */
960 if (call->conn->auth_state.gensec_security &&
961 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
962 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
965 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
966 if (context == NULL) {
967 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
970 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call,
971 lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
972 NT_STATUS_HAVE_NO_MEMORY(pull);
974 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
976 call->context = context;
977 call->ndr_pull = pull;
979 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
980 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
983 /* unravel the NDR for the packet */
984 status = context->iface->ndr_pull(call, call, pull, &call->r);
985 if (!NT_STATUS_IS_OK(status)) {
986 return dcesrv_fault(call, call->fault_code);
989 if (pull->offset != pull->data_size) {
990 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
991 pull->data_size - pull->offset));
992 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
995 /* call the dispatch function */
996 status = context->iface->dispatch(call, call, call->r);
997 if (!NT_STATUS_IS_OK(status)) {
998 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
999 context->iface->name,
1000 call->pkt.u.request.opnum,
1001 dcerpc_errstr(pull, call->fault_code)));
1002 return dcesrv_fault(call, call->fault_code);
1005 /* add the call to the pending list */
1006 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
1008 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
1009 return NT_STATUS_OK;
1012 return dcesrv_reply(call);
1015 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
1017 struct ndr_push *push;
1020 uint32_t total_length, chunk_size;
1021 struct dcesrv_connection_context *context = call->context;
1022 size_t sig_size = 0;
1024 /* call the reply function */
1025 status = context->iface->reply(call, call, call->r);
1026 if (!NT_STATUS_IS_OK(status)) {
1027 return dcesrv_fault(call, call->fault_code);
1030 /* form the reply NDR */
1031 push = ndr_push_init_ctx(call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
1032 NT_STATUS_HAVE_NO_MEMORY(push);
1034 /* carry over the pointer count to the reply in case we are
1035 using full pointer. See NDR specification for full
1037 push->ptr_count = call->ndr_pull->ptr_count;
1039 if (lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
1040 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1043 status = context->iface->ndr_push(call, call, push, call->r);
1044 if (!NT_STATUS_IS_OK(status)) {
1045 return dcesrv_fault(call, call->fault_code);
1048 stub = ndr_push_blob(push);
1050 total_length = stub.length;
1052 /* we can write a full max_recv_frag size, minus the dcerpc
1053 request header size */
1054 chunk_size = call->conn->cli_max_recv_frag;
1055 chunk_size -= DCERPC_REQUEST_LENGTH;
1056 if (call->conn->auth_state.auth_info &&
1057 call->conn->auth_state.gensec_security) {
1058 sig_size = gensec_sig_size(call->conn->auth_state.gensec_security,
1059 call->conn->cli_max_recv_frag);
1061 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1062 chunk_size -= sig_size;
1065 chunk_size -= (chunk_size % 16);
1069 struct data_blob_list_item *rep;
1070 struct ncacn_packet pkt;
1072 rep = talloc(call, struct data_blob_list_item);
1073 NT_STATUS_HAVE_NO_MEMORY(rep);
1075 length = MIN(chunk_size, stub.length);
1077 /* form the dcerpc response packet */
1078 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
1079 pkt.auth_length = 0;
1080 pkt.call_id = call->pkt.call_id;
1081 pkt.ptype = DCERPC_PKT_RESPONSE;
1083 if (stub.length == total_length) {
1084 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1086 if (length == stub.length) {
1087 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1089 pkt.u.response.alloc_hint = stub.length;
1090 pkt.u.response.context_id = call->pkt.u.request.context_id;
1091 pkt.u.response.cancel_count = 0;
1092 pkt.u.response.stub_and_verifier.data = stub.data;
1093 pkt.u.response.stub_and_verifier.length = length;
1095 if (!dcesrv_auth_response(call, &rep->blob, sig_size, &pkt)) {
1096 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
1099 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
1101 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
1103 stub.data += length;
1104 stub.length -= length;
1105 } while (stub.length != 0);
1107 /* move the call from the pending to the finished calls list */
1108 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
1110 if (call->conn->call_list && call->conn->call_list->replies) {
1111 if (call->conn->transport.report_output_data) {
1112 call->conn->transport.report_output_data(call->conn);
1116 return NT_STATUS_OK;
1119 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1121 if (!conn->transport.get_my_addr) {
1125 return conn->transport.get_my_addr(conn, mem_ctx);
1128 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1130 if (!conn->transport.get_peer_addr) {
1134 return conn->transport.get_peer_addr(conn, mem_ctx);
1139 remove the call from the right list when freed
1141 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1143 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1148 process some input to a dcerpc endpoint server.
1150 NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
1151 struct ncacn_packet *pkt,
1155 struct dcesrv_call_state *call;
1157 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1159 data_blob_free(&blob);
1161 return NT_STATUS_NO_MEMORY;
1163 call->conn = dce_conn;
1164 call->event_ctx = dce_conn->event_ctx;
1165 call->msg_ctx = dce_conn->msg_ctx;
1166 call->state_flags = call->conn->state_flags;
1167 call->time = timeval_current();
1168 call->list = DCESRV_LIST_NONE;
1170 talloc_steal(call, pkt);
1171 talloc_steal(call, blob.data);
1174 talloc_set_destructor(call, dcesrv_call_dequeue);
1176 /* we have to check the signing here, before combining the
1178 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1179 !dcesrv_auth_request(call, &blob)) {
1180 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1183 /* see if this is a continued packet */
1184 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1185 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1186 struct dcesrv_call_state *call2 = call;
1187 uint32_t alloc_size;
1189 /* we only allow fragmented requests, no other packet types */
1190 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1191 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1194 /* this is a continuation of an existing call - find the call then
1195 tack it on the end */
1196 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1198 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1201 if (call->pkt.ptype != call2->pkt.ptype) {
1202 /* trying to play silly buggers are we? */
1203 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1206 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1207 call2->pkt.u.request.stub_and_verifier.length;
1208 if (call->pkt.u.request.alloc_hint > alloc_size) {
1209 alloc_size = call->pkt.u.request.alloc_hint;
1212 call->pkt.u.request.stub_and_verifier.data =
1213 talloc_realloc(call,
1214 call->pkt.u.request.stub_and_verifier.data,
1215 uint8_t, alloc_size);
1216 if (!call->pkt.u.request.stub_and_verifier.data) {
1217 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1219 memcpy(call->pkt.u.request.stub_and_verifier.data +
1220 call->pkt.u.request.stub_and_verifier.length,
1221 call2->pkt.u.request.stub_and_verifier.data,
1222 call2->pkt.u.request.stub_and_verifier.length);
1223 call->pkt.u.request.stub_and_verifier.length +=
1224 call2->pkt.u.request.stub_and_verifier.length;
1226 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1231 /* this may not be the last pdu in the chain - if its isn't then
1232 just put it on the incoming_fragmented_call_list and wait for the rest */
1233 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1234 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1235 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1236 return NT_STATUS_OK;
1239 /* This removes any fragments we may have had stashed away */
1240 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1242 switch (call->pkt.ptype) {
1243 case DCERPC_PKT_BIND:
1244 status = dcesrv_bind(call);
1246 case DCERPC_PKT_AUTH3:
1247 status = dcesrv_auth3(call);
1249 case DCERPC_PKT_ALTER:
1250 status = dcesrv_alter(call);
1252 case DCERPC_PKT_REQUEST:
1253 status = dcesrv_request(call);
1256 status = NT_STATUS_INVALID_PARAMETER;
1260 /* if we are going to be sending a reply then add
1261 it to the list of pending calls. We add it to the end to keep the call
1262 list in the order we will answer */
1263 if (!NT_STATUS_IS_OK(status)) {
1270 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1271 struct loadparm_context *lp_ctx,
1272 const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1275 struct dcesrv_context *dce_ctx;
1278 if (!endpoint_servers) {
1279 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1280 return NT_STATUS_INTERNAL_ERROR;
1283 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1284 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1285 dce_ctx->endpoint_list = NULL;
1286 dce_ctx->lp_ctx = lp_ctx;
1287 dce_ctx->assoc_groups_idr = idr_init(dce_ctx);
1288 NT_STATUS_HAVE_NO_MEMORY(dce_ctx->assoc_groups_idr);
1290 for (i=0;endpoint_servers[i];i++) {
1291 const struct dcesrv_endpoint_server *ep_server;
1293 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1295 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1296 return NT_STATUS_INTERNAL_ERROR;
1299 status = ep_server->init_server(dce_ctx, ep_server);
1300 if (!NT_STATUS_IS_OK(status)) {
1301 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1302 nt_errstr(status)));
1307 *_dce_ctx = dce_ctx;
1308 return NT_STATUS_OK;
1311 /* the list of currently registered DCERPC endpoint servers.
1313 static struct ep_server {
1314 struct dcesrv_endpoint_server *ep_server;
1315 } *ep_servers = NULL;
1316 static int num_ep_servers;
1319 register a DCERPC endpoint server.
1321 The 'name' can be later used by other backends to find the operations
1322 structure for this backend.
1324 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1326 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1328 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1330 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1331 /* its already registered! */
1332 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1334 return NT_STATUS_OBJECT_NAME_COLLISION;
1337 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1339 smb_panic("out of memory in dcerpc_register");
1342 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1343 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1347 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1350 return NT_STATUS_OK;
1354 return the operations structure for a named backend of the specified type
1356 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1360 for (i=0;i<num_ep_servers;i++) {
1361 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1362 return ep_servers[i].ep_server;
1369 void dcerpc_server_init(struct loadparm_context *lp_ctx)
1371 static bool initialized;
1372 extern NTSTATUS dcerpc_server_wkssvc_init(void);
1373 extern NTSTATUS dcerpc_server_drsuapi_init(void);
1374 extern NTSTATUS dcerpc_server_winreg_init(void);
1375 extern NTSTATUS dcerpc_server_spoolss_init(void);
1376 extern NTSTATUS dcerpc_server_epmapper_init(void);
1377 extern NTSTATUS dcerpc_server_srvsvc_init(void);
1378 extern NTSTATUS dcerpc_server_netlogon_init(void);
1379 extern NTSTATUS dcerpc_server_rpcecho_init(void);
1380 extern NTSTATUS dcerpc_server_unixinfo_init(void);
1381 extern NTSTATUS dcerpc_server_samr_init(void);
1382 extern NTSTATUS dcerpc_server_remote_init(void);
1383 extern NTSTATUS dcerpc_server_lsa_init(void);
1384 extern NTSTATUS dcerpc_server_browser_init(void);
1385 init_module_fn static_init[] = { STATIC_dcerpc_server_MODULES };
1386 init_module_fn *shared_init;
1393 shared_init = load_samba_modules(NULL, lp_ctx, "dcerpc_server");
1395 run_init_functions(static_init);
1396 run_init_functions(shared_init);
1398 talloc_free(shared_init);
1402 return the DCERPC module version, and the size of some critical types
1403 This can be used by endpoint server modules to either detect compilation errors, or provide
1404 multiple implementations for different smbd compilation options in one module
1406 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1408 static const struct dcesrv_critical_sizes critical_sizes = {
1409 DCERPC_MODULE_VERSION,
1410 sizeof(struct dcesrv_context),
1411 sizeof(struct dcesrv_endpoint),
1412 sizeof(struct dcesrv_endpoint_server),
1413 sizeof(struct dcesrv_interface),
1414 sizeof(struct dcesrv_if_list),
1415 sizeof(struct dcesrv_connection),
1416 sizeof(struct dcesrv_call_state),
1417 sizeof(struct dcesrv_auth),
1418 sizeof(struct dcesrv_handle)
1421 return &critical_sizes;