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);
78 allocate a new association group
80 static struct dcesrv_assoc_group *dcesrv_assoc_group_new(TALLOC_CTX *mem_ctx,
81 struct dcesrv_context *dce_ctx)
83 struct dcesrv_assoc_group *assoc_group;
86 assoc_group = talloc_zero(mem_ctx, struct dcesrv_assoc_group);
87 if (assoc_group == NULL) {
91 id = idr_get_new_random(dce_ctx->assoc_groups_idr, assoc_group, UINT16_MAX);
93 talloc_free(assoc_group);
94 DEBUG(0,(__location__ ": Out of association groups!\n"));
104 see if two endpoints match
106 static bool endpoints_match(const struct dcerpc_binding *ep1,
107 const struct dcerpc_binding *ep2)
109 if (ep1->transport != ep2->transport) {
113 if (!ep1->endpoint || !ep2->endpoint) {
114 return ep1->endpoint == ep2->endpoint;
117 if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
124 find an endpoint in the dcesrv_context
126 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
127 const struct dcerpc_binding *ep_description)
129 struct dcesrv_endpoint *ep;
130 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
131 if (endpoints_match(ep->ep_description, ep_description)) {
139 find a registered context_id from a bind or alter_context
141 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn,
144 struct dcesrv_connection_context *c;
145 for (c=conn->contexts;c;c=c->next) {
146 if (c->context_id == context_id) return c;
152 see if a uuid and if_version match to an interface
154 static bool interface_match(const struct dcesrv_interface *if1,
155 const struct dcesrv_interface *if2)
157 return (if1->syntax_id.if_version == if2->syntax_id.if_version &&
158 GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
162 find the interface operations on an endpoint
164 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
165 const struct dcesrv_interface *iface)
167 struct dcesrv_if_list *ifl;
168 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
169 if (interface_match(&(ifl->iface), iface)) {
170 return &(ifl->iface);
177 see if a uuid and if_version match to an interface
179 static bool interface_match_by_uuid(const struct dcesrv_interface *iface,
180 const struct GUID *uuid, uint32_t if_version)
182 return (iface->syntax_id.if_version == if_version &&
183 GUID_equal(&iface->syntax_id.uuid, uuid));
187 find the interface operations on an endpoint by uuid
189 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
190 const struct GUID *uuid, uint32_t if_version)
192 struct dcesrv_if_list *ifl;
193 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
194 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
195 return &(ifl->iface);
202 find the earlier parts of a fragmented call awaiting reassembily
204 static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
206 struct dcesrv_call_state *c;
207 for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
208 if (c->pkt.call_id == call_id) {
216 register an interface on an endpoint
218 _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
220 const struct dcesrv_interface *iface,
221 const struct security_descriptor *sd)
223 struct dcesrv_endpoint *ep;
224 struct dcesrv_if_list *ifl;
225 struct dcerpc_binding *binding;
229 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
231 if (NT_STATUS_IS_ERR(status)) {
232 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
236 /* check if this endpoint exists
238 if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
239 ep = talloc(dce_ctx, struct dcesrv_endpoint);
241 return NT_STATUS_NO_MEMORY;
244 ep->ep_description = talloc_reference(ep, binding);
247 /* add mgmt interface */
248 ifl = talloc(dce_ctx, struct dcesrv_if_list);
250 return NT_STATUS_NO_MEMORY;
253 memcpy(&(ifl->iface), &dcesrv_mgmt_interface,
254 sizeof(struct dcesrv_interface));
256 DLIST_ADD(ep->interface_list, ifl);
259 /* see if the interface is already registered on te endpoint */
260 if (find_interface(ep, iface)!=NULL) {
261 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
262 iface->name, ep_name));
263 return NT_STATUS_OBJECT_NAME_COLLISION;
266 /* talloc a new interface list element */
267 ifl = talloc(dce_ctx, struct dcesrv_if_list);
269 return NT_STATUS_NO_MEMORY;
272 /* copy the given interface struct to the one on the endpoints interface list */
273 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
275 /* if we have a security descriptor given,
276 * we should see if we can set it up on the endpoint
279 /* if there's currently no security descriptor given on the endpoint
282 if (ep->sd == NULL) {
283 ep->sd = security_descriptor_copy(dce_ctx, sd);
286 /* if now there's no security descriptor given on the endpoint
287 * something goes wrong, either we failed to copy the security descriptor
288 * or there was already one on the endpoint
290 if (ep->sd != NULL) {
291 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
292 " on endpoint '%s'\n",
293 iface->name, ep_name));
294 if (add_ep) free(ep);
296 return NT_STATUS_OBJECT_NAME_COLLISION;
300 /* finally add the interface on the endpoint */
301 DLIST_ADD(ep->interface_list, ifl);
303 /* if it's a new endpoint add it to the dcesrv_context */
305 DLIST_ADD(dce_ctx->endpoint_list, ep);
308 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
309 iface->name, ep_name));
314 NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
315 DATA_BLOB *session_key)
317 if (p->auth_state.session_info->session_key.length) {
318 *session_key = p->auth_state.session_info->session_key;
321 return NT_STATUS_NO_USER_SESSION_KEY;
324 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
325 DATA_BLOB *session_key)
327 /* this took quite a few CPU cycles to find ... */
328 session_key->data = discard_const_p(uint8_t, "SystemLibraryDTC");
329 session_key->length = 16;
334 fetch the user session key - may be default (above) or the SMB session key
336 The key is always truncated to 16 bytes
338 _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
339 DATA_BLOB *session_key)
341 NTSTATUS status = p->auth_state.session_key(p, session_key);
342 if (!NT_STATUS_IS_OK(status)) {
346 session_key->length = MIN(session_key->length, 16);
352 connect to a dcerpc endpoint
354 _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
356 const struct dcesrv_endpoint *ep,
357 struct auth_session_info *session_info,
358 struct tevent_context *event_ctx,
359 struct messaging_context *msg_ctx,
360 struct server_id server_id,
361 uint32_t state_flags,
362 struct dcesrv_connection **_p)
364 struct dcesrv_connection *p;
367 return NT_STATUS_ACCESS_DENIED;
370 p = talloc(mem_ctx, struct dcesrv_connection);
371 NT_STATUS_HAVE_NO_MEMORY(p);
373 if (!talloc_reference(p, session_info)) {
375 return NT_STATUS_NO_MEMORY;
378 p->dce_ctx = dce_ctx;
382 p->packet_log_dir = lp_lockdir(dce_ctx->lp_ctx);
383 p->incoming_fragmented_call_list = NULL;
384 p->pending_call_list = NULL;
385 p->cli_max_recv_frag = 0;
386 p->partial_input = data_blob(NULL, 0);
387 p->auth_state.auth_info = NULL;
388 p->auth_state.gensec_security = NULL;
389 p->auth_state.session_info = session_info;
390 p->auth_state.session_key = dcesrv_generic_session_key;
391 p->event_ctx = event_ctx;
392 p->msg_ctx = msg_ctx;
393 p->server_id = server_id;
394 p->processing = false;
395 p->state_flags = state_flags;
396 ZERO_STRUCT(p->transport);
402 static void dcesrv_init_hdr(struct ncacn_packet *pkt, bool bigendian)
405 pkt->rpc_vers_minor = 0;
409 pkt->drep[0] = DCERPC_DREP_LE;
417 move a call from an existing linked list to the specified list. This
418 prevents bugs where we forget to remove the call from a previous
421 static void dcesrv_call_set_list(struct dcesrv_call_state *call,
422 enum dcesrv_call_list list)
424 switch (call->list) {
425 case DCESRV_LIST_NONE:
427 case DCESRV_LIST_CALL_LIST:
428 DLIST_REMOVE(call->conn->call_list, call);
430 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
431 DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
433 case DCESRV_LIST_PENDING_CALL_LIST:
434 DLIST_REMOVE(call->conn->pending_call_list, call);
439 case DCESRV_LIST_NONE:
441 case DCESRV_LIST_CALL_LIST:
442 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
444 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
445 DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
447 case DCESRV_LIST_PENDING_CALL_LIST:
448 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
454 return a dcerpc fault
456 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
458 struct ncacn_packet pkt;
459 struct data_blob_list_item *rep;
463 /* setup a bind_ack */
464 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
466 pkt.call_id = call->pkt.call_id;
467 pkt.ptype = DCERPC_PKT_FAULT;
468 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
469 pkt.u.fault.alloc_hint = 0;
470 pkt.u.fault.context_id = 0;
471 pkt.u.fault.cancel_count = 0;
472 pkt.u.fault.status = fault_code;
475 pkt.u.fault._pad = data_blob_const(zeros, sizeof(zeros));
477 rep = talloc(call, struct data_blob_list_item);
479 return NT_STATUS_NO_MEMORY;
482 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
483 if (!NT_STATUS_IS_OK(status)) {
487 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
489 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
490 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
492 if (call->conn->call_list && call->conn->call_list->replies) {
493 if (call->conn->transport.report_output_data) {
494 call->conn->transport.report_output_data(call->conn);
503 return a dcerpc bind_nak
505 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
507 struct ncacn_packet pkt;
508 struct data_blob_list_item *rep;
511 /* setup a bind_nak */
512 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
514 pkt.call_id = call->pkt.call_id;
515 pkt.ptype = DCERPC_PKT_BIND_NAK;
516 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
517 pkt.u.bind_nak.reject_reason = reason;
518 if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
519 pkt.u.bind_nak.versions.v.num_versions = 0;
522 rep = talloc(call, struct data_blob_list_item);
524 return NT_STATUS_NO_MEMORY;
527 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
528 if (!NT_STATUS_IS_OK(status)) {
532 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
534 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
535 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
537 if (call->conn->call_list && call->conn->call_list->replies) {
538 if (call->conn->transport.report_output_data) {
539 call->conn->transport.report_output_data(call->conn);
546 static int dcesrv_connection_context_destructor(struct dcesrv_connection_context *c)
548 DLIST_REMOVE(c->conn->contexts, c);
551 c->iface->unbind(c, c->iface);
558 handle a bind request
560 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
562 uint32_t if_version, transfer_syntax_version;
563 struct GUID uuid, *transfer_syntax_uuid;
564 struct ncacn_packet pkt;
565 struct data_blob_list_item *rep;
567 uint32_t result=0, reason=0;
569 const struct dcesrv_interface *iface;
570 uint32_t extra_flags = 0;
573 if provided, check the assoc_group is valid
575 if (call->pkt.u.bind.assoc_group_id != 0 &&
576 lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
577 dcesrv_assoc_group_find(call->conn->dce_ctx, call->pkt.u.bind.assoc_group_id) == NULL) {
578 return dcesrv_bind_nak(call, 0);
581 if (call->pkt.u.bind.num_contexts < 1 ||
582 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
583 return dcesrv_bind_nak(call, 0);
586 context_id = call->pkt.u.bind.ctx_list[0].context_id;
588 /* you can't bind twice on one context */
589 if (dcesrv_find_context(call->conn, context_id) != NULL) {
590 return dcesrv_bind_nak(call, 0);
593 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
594 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
596 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
597 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
598 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
599 ndr_transfer_syntax.if_version != transfer_syntax_version) {
600 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
601 /* we only do NDR encoded dcerpc */
602 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
603 talloc_free(uuid_str);
604 return dcesrv_bind_nak(call, 0);
607 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
609 char *uuid_str = GUID_string(call, &uuid);
610 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
611 talloc_free(uuid_str);
613 /* we don't know about that interface */
614 result = DCERPC_BIND_PROVIDER_REJECT;
615 reason = DCERPC_BIND_REASON_ASYNTAX;
619 /* add this context to the list of available context_ids */
620 struct dcesrv_connection_context *context = talloc(call->conn,
621 struct dcesrv_connection_context);
622 if (context == NULL) {
623 return dcesrv_bind_nak(call, 0);
625 context->conn = call->conn;
626 context->iface = iface;
627 context->context_id = context_id;
628 if (call->pkt.u.bind.assoc_group_id != 0) {
629 context->assoc_group = dcesrv_assoc_group_reference(context,
631 call->pkt.u.bind.assoc_group_id);
633 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
635 if (context->assoc_group == NULL) {
636 talloc_free(context);
637 return dcesrv_bind_nak(call, 0);
639 context->private_data = NULL;
640 DLIST_ADD(call->conn->contexts, context);
641 call->context = context;
642 talloc_set_destructor(context, dcesrv_connection_context_destructor);
644 status = iface->bind(call, iface);
645 if (!NT_STATUS_IS_OK(status)) {
646 char *uuid_str = GUID_string(call, &uuid);
647 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
648 uuid_str, if_version, nt_errstr(status)));
649 talloc_free(uuid_str);
650 /* we don't want to trigger the iface->unbind() hook */
651 context->iface = NULL;
652 talloc_free(call->context);
653 call->context = NULL;
654 return dcesrv_bind_nak(call, 0);
658 if (call->conn->cli_max_recv_frag == 0) {
659 call->conn->cli_max_recv_frag = MIN(0x2000, call->pkt.u.bind.max_recv_frag);
662 if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) &&
663 lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","header signing", false)) {
664 call->conn->state_flags |= DCESRV_CALL_STATE_FLAG_HEADER_SIGNING;
665 extra_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
668 /* handle any authentication that is being requested */
669 if (!dcesrv_auth_bind(call)) {
670 talloc_free(call->context);
671 call->context = NULL;
672 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
675 /* setup a bind_ack */
676 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
678 pkt.call_id = call->pkt.call_id;
679 pkt.ptype = DCERPC_PKT_BIND_ACK;
680 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
681 pkt.u.bind_ack.max_xmit_frag = call->conn->cli_max_recv_frag;
682 pkt.u.bind_ack.max_recv_frag = 0x2000;
685 make it possible for iface->bind() to specify the assoc_group_id
686 This helps the openchange mapiproxy plugin to work correctly.
691 pkt.u.bind_ack.assoc_group_id = call->context->assoc_group->id;
693 pkt.u.bind_ack.assoc_group_id = DUMMY_ASSOC_GROUP;
697 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
698 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
700 pkt.u.bind_ack.secondary_address = "";
702 pkt.u.bind_ack.num_results = 1;
703 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
704 if (!pkt.u.bind_ack.ctx_list) {
705 talloc_free(call->context);
706 call->context = NULL;
707 return NT_STATUS_NO_MEMORY;
709 pkt.u.bind_ack.ctx_list[0].result = result;
710 pkt.u.bind_ack.ctx_list[0].reason = reason;
711 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
712 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
714 status = dcesrv_auth_bind_ack(call, &pkt);
715 if (!NT_STATUS_IS_OK(status)) {
716 talloc_free(call->context);
717 call->context = NULL;
718 return dcesrv_bind_nak(call, 0);
721 rep = talloc(call, struct data_blob_list_item);
723 talloc_free(call->context);
724 call->context = NULL;
725 return NT_STATUS_NO_MEMORY;
728 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
729 if (!NT_STATUS_IS_OK(status)) {
730 talloc_free(call->context);
731 call->context = NULL;
735 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
737 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
738 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
740 if (call->conn->call_list && call->conn->call_list->replies) {
741 if (call->conn->transport.report_output_data) {
742 call->conn->transport.report_output_data(call->conn);
751 handle a auth3 request
753 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
755 /* handle the auth3 in the auth code */
756 if (!dcesrv_auth_auth3(call)) {
757 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
762 /* we don't send a reply to a auth3 request, except by a
769 handle a bind request
771 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
773 uint32_t if_version, transfer_syntax_version;
774 struct dcesrv_connection_context *context;
775 const struct dcesrv_interface *iface;
776 struct GUID uuid, *transfer_syntax_uuid;
779 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
780 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
782 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
783 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
784 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
785 ndr_transfer_syntax.if_version != transfer_syntax_version) {
786 /* we only do NDR encoded dcerpc */
787 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
790 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
792 char *uuid_str = GUID_string(call, &uuid);
793 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
794 talloc_free(uuid_str);
795 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
798 /* add this context to the list of available context_ids */
799 context = talloc(call->conn, struct dcesrv_connection_context);
800 if (context == NULL) {
801 return NT_STATUS_NO_MEMORY;
803 context->conn = call->conn;
804 context->iface = iface;
805 context->context_id = context_id;
806 if (call->pkt.u.alter.assoc_group_id != 0) {
807 context->assoc_group = dcesrv_assoc_group_reference(context,
809 call->pkt.u.alter.assoc_group_id);
811 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
813 if (context->assoc_group == NULL) {
814 talloc_free(context);
815 call->context = NULL;
816 return NT_STATUS_NO_MEMORY;
818 context->private_data = NULL;
819 DLIST_ADD(call->conn->contexts, context);
820 call->context = context;
821 talloc_set_destructor(context, dcesrv_connection_context_destructor);
823 status = iface->bind(call, iface);
824 if (!NT_STATUS_IS_OK(status)) {
825 /* we don't want to trigger the iface->unbind() hook */
826 context->iface = NULL;
827 talloc_free(context);
828 call->context = NULL;
837 handle a alter context request
839 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
841 struct ncacn_packet pkt;
842 struct data_blob_list_item *rep;
844 uint32_t result=0, reason=0;
847 /* handle any authentication that is being requested */
848 if (!dcesrv_auth_alter(call)) {
849 /* TODO: work out the right reject code */
850 result = DCERPC_BIND_PROVIDER_REJECT;
851 reason = DCERPC_BIND_REASON_ASYNTAX;
854 context_id = call->pkt.u.alter.ctx_list[0].context_id;
856 /* see if they are asking for a new interface */
858 call->context = dcesrv_find_context(call->conn, context_id);
859 if (!call->context) {
860 status = dcesrv_alter_new_context(call, context_id);
861 if (!NT_STATUS_IS_OK(status)) {
862 result = DCERPC_BIND_PROVIDER_REJECT;
863 reason = DCERPC_BIND_REASON_ASYNTAX;
869 call->pkt.u.alter.assoc_group_id != 0 &&
870 lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
871 call->pkt.u.alter.assoc_group_id != call->context->assoc_group->id) {
872 DEBUG(0,(__location__ ": Failed attempt to use new assoc_group in alter context (0x%08x 0x%08x)\n",
873 call->context->assoc_group->id, call->pkt.u.alter.assoc_group_id));
874 /* TODO: can they ask for a new association group? */
875 result = DCERPC_BIND_PROVIDER_REJECT;
876 reason = DCERPC_BIND_REASON_ASYNTAX;
879 /* setup a alter_resp */
880 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
882 pkt.call_id = call->pkt.call_id;
883 pkt.ptype = DCERPC_PKT_ALTER_RESP;
884 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
885 pkt.u.alter_resp.max_xmit_frag = 0x2000;
886 pkt.u.alter_resp.max_recv_frag = 0x2000;
888 pkt.u.alter_resp.assoc_group_id = call->context->assoc_group->id;
890 pkt.u.alter_resp.assoc_group_id = 0;
892 pkt.u.alter_resp.num_results = 1;
893 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
894 if (!pkt.u.alter_resp.ctx_list) {
895 return NT_STATUS_NO_MEMORY;
897 pkt.u.alter_resp.ctx_list[0].result = result;
898 pkt.u.alter_resp.ctx_list[0].reason = reason;
899 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
900 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
901 pkt.u.alter_resp.secondary_address = "";
903 status = dcesrv_auth_alter_ack(call, &pkt);
904 if (!NT_STATUS_IS_OK(status)) {
905 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
906 || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
907 || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
908 || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
909 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
911 return dcesrv_fault(call, 0);
914 rep = talloc(call, struct data_blob_list_item);
916 return NT_STATUS_NO_MEMORY;
919 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
920 if (!NT_STATUS_IS_OK(status)) {
924 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
926 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
927 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
929 if (call->conn->call_list && call->conn->call_list->replies) {
930 if (call->conn->transport.report_output_data) {
931 call->conn->transport.report_output_data(call->conn);
939 handle a dcerpc request packet
941 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
943 struct ndr_pull *pull;
945 struct dcesrv_connection_context *context;
947 /* if authenticated, and the mech we use can't do async replies, don't use them... */
948 if (call->conn->auth_state.gensec_security &&
949 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
950 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
953 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
954 if (context == NULL) {
955 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
958 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call,
959 lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
960 NT_STATUS_HAVE_NO_MEMORY(pull);
962 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
964 call->context = context;
965 call->ndr_pull = pull;
967 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
968 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
971 /* unravel the NDR for the packet */
972 status = context->iface->ndr_pull(call, call, pull, &call->r);
973 if (!NT_STATUS_IS_OK(status)) {
974 return dcesrv_fault(call, call->fault_code);
977 if (pull->offset != pull->data_size) {
978 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
979 pull->data_size - pull->offset));
980 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
983 /* call the dispatch function */
984 status = context->iface->dispatch(call, call, call->r);
985 if (!NT_STATUS_IS_OK(status)) {
986 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
987 context->iface->name,
988 call->pkt.u.request.opnum,
989 dcerpc_errstr(pull, call->fault_code)));
990 return dcesrv_fault(call, call->fault_code);
993 /* add the call to the pending list */
994 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
996 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
1000 return dcesrv_reply(call);
1003 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
1005 struct ndr_push *push;
1008 uint32_t total_length, chunk_size;
1009 struct dcesrv_connection_context *context = call->context;
1010 size_t sig_size = 0;
1012 /* call the reply function */
1013 status = context->iface->reply(call, call, call->r);
1014 if (!NT_STATUS_IS_OK(status)) {
1015 return dcesrv_fault(call, call->fault_code);
1018 /* form the reply NDR */
1019 push = ndr_push_init_ctx(call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
1020 NT_STATUS_HAVE_NO_MEMORY(push);
1022 /* carry over the pointer count to the reply in case we are
1023 using full pointer. See NDR specification for full
1025 push->ptr_count = call->ndr_pull->ptr_count;
1027 if (lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
1028 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1031 status = context->iface->ndr_push(call, call, push, call->r);
1032 if (!NT_STATUS_IS_OK(status)) {
1033 return dcesrv_fault(call, call->fault_code);
1036 stub = ndr_push_blob(push);
1038 total_length = stub.length;
1040 /* we can write a full max_recv_frag size, minus the dcerpc
1041 request header size */
1042 chunk_size = call->conn->cli_max_recv_frag;
1043 chunk_size -= DCERPC_REQUEST_LENGTH;
1044 if (call->conn->auth_state.auth_info &&
1045 call->conn->auth_state.gensec_security) {
1046 sig_size = gensec_sig_size(call->conn->auth_state.gensec_security,
1047 call->conn->cli_max_recv_frag);
1049 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1050 chunk_size -= sig_size;
1053 chunk_size -= (chunk_size % 16);
1057 struct data_blob_list_item *rep;
1058 struct ncacn_packet pkt;
1060 rep = talloc(call, struct data_blob_list_item);
1061 NT_STATUS_HAVE_NO_MEMORY(rep);
1063 length = MIN(chunk_size, stub.length);
1065 /* form the dcerpc response packet */
1066 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
1067 pkt.auth_length = 0;
1068 pkt.call_id = call->pkt.call_id;
1069 pkt.ptype = DCERPC_PKT_RESPONSE;
1071 if (stub.length == total_length) {
1072 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1074 if (length == stub.length) {
1075 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1077 pkt.u.response.alloc_hint = stub.length;
1078 pkt.u.response.context_id = call->pkt.u.request.context_id;
1079 pkt.u.response.cancel_count = 0;
1080 pkt.u.response.stub_and_verifier.data = stub.data;
1081 pkt.u.response.stub_and_verifier.length = length;
1083 if (!dcesrv_auth_response(call, &rep->blob, sig_size, &pkt)) {
1084 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
1087 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
1089 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
1091 stub.data += length;
1092 stub.length -= length;
1093 } while (stub.length != 0);
1095 /* move the call from the pending to the finished calls list */
1096 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
1098 if (call->conn->call_list && call->conn->call_list->replies) {
1099 if (call->conn->transport.report_output_data) {
1100 call->conn->transport.report_output_data(call->conn);
1104 return NT_STATUS_OK;
1107 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1109 if (!conn->transport.get_my_addr) {
1113 return conn->transport.get_my_addr(conn, mem_ctx);
1116 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1118 if (!conn->transport.get_peer_addr) {
1122 return conn->transport.get_peer_addr(conn, mem_ctx);
1127 remove the call from the right list when freed
1129 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1131 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1136 process some input to a dcerpc endpoint server.
1138 NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
1139 struct ncacn_packet *pkt,
1143 struct dcesrv_call_state *call;
1145 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1147 data_blob_free(&blob);
1149 return NT_STATUS_NO_MEMORY;
1151 call->conn = dce_conn;
1152 call->event_ctx = dce_conn->event_ctx;
1153 call->msg_ctx = dce_conn->msg_ctx;
1154 call->state_flags = call->conn->state_flags;
1155 call->time = timeval_current();
1156 call->list = DCESRV_LIST_NONE;
1158 talloc_steal(call, pkt);
1159 talloc_steal(call, blob.data);
1162 talloc_set_destructor(call, dcesrv_call_dequeue);
1164 /* we have to check the signing here, before combining the
1166 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1167 !dcesrv_auth_request(call, &blob)) {
1168 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1171 /* see if this is a continued packet */
1172 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1173 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1174 struct dcesrv_call_state *call2 = call;
1175 uint32_t alloc_size;
1177 /* we only allow fragmented requests, no other packet types */
1178 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1179 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1182 /* this is a continuation of an existing call - find the call then
1183 tack it on the end */
1184 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1186 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1189 if (call->pkt.ptype != call2->pkt.ptype) {
1190 /* trying to play silly buggers are we? */
1191 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1194 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1195 call2->pkt.u.request.stub_and_verifier.length;
1196 if (call->pkt.u.request.alloc_hint > alloc_size) {
1197 alloc_size = call->pkt.u.request.alloc_hint;
1200 call->pkt.u.request.stub_and_verifier.data =
1201 talloc_realloc(call,
1202 call->pkt.u.request.stub_and_verifier.data,
1203 uint8_t, alloc_size);
1204 if (!call->pkt.u.request.stub_and_verifier.data) {
1205 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1207 memcpy(call->pkt.u.request.stub_and_verifier.data +
1208 call->pkt.u.request.stub_and_verifier.length,
1209 call2->pkt.u.request.stub_and_verifier.data,
1210 call2->pkt.u.request.stub_and_verifier.length);
1211 call->pkt.u.request.stub_and_verifier.length +=
1212 call2->pkt.u.request.stub_and_verifier.length;
1214 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1219 /* this may not be the last pdu in the chain - if its isn't then
1220 just put it on the incoming_fragmented_call_list and wait for the rest */
1221 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1222 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1223 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1224 return NT_STATUS_OK;
1227 /* This removes any fragments we may have had stashed away */
1228 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1230 switch (call->pkt.ptype) {
1231 case DCERPC_PKT_BIND:
1232 status = dcesrv_bind(call);
1234 case DCERPC_PKT_AUTH3:
1235 status = dcesrv_auth3(call);
1237 case DCERPC_PKT_ALTER:
1238 status = dcesrv_alter(call);
1240 case DCERPC_PKT_REQUEST:
1241 status = dcesrv_request(call);
1244 status = NT_STATUS_INVALID_PARAMETER;
1248 /* if we are going to be sending a reply then add
1249 it to the list of pending calls. We add it to the end to keep the call
1250 list in the order we will answer */
1251 if (!NT_STATUS_IS_OK(status)) {
1258 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1259 struct loadparm_context *lp_ctx,
1260 const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1263 struct dcesrv_context *dce_ctx;
1266 if (!endpoint_servers) {
1267 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1268 return NT_STATUS_INTERNAL_ERROR;
1271 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1272 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1273 dce_ctx->endpoint_list = NULL;
1274 dce_ctx->lp_ctx = lp_ctx;
1275 dce_ctx->assoc_groups_idr = idr_init(dce_ctx);
1276 NT_STATUS_HAVE_NO_MEMORY(dce_ctx->assoc_groups_idr);
1278 for (i=0;endpoint_servers[i];i++) {
1279 const struct dcesrv_endpoint_server *ep_server;
1281 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1283 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1284 return NT_STATUS_INTERNAL_ERROR;
1287 status = ep_server->init_server(dce_ctx, ep_server);
1288 if (!NT_STATUS_IS_OK(status)) {
1289 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1290 nt_errstr(status)));
1295 *_dce_ctx = dce_ctx;
1296 return NT_STATUS_OK;
1299 /* the list of currently registered DCERPC endpoint servers.
1301 static struct ep_server {
1302 struct dcesrv_endpoint_server *ep_server;
1303 } *ep_servers = NULL;
1304 static int num_ep_servers;
1307 register a DCERPC endpoint server.
1309 The 'name' can be later used by other backends to find the operations
1310 structure for this backend.
1312 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1314 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1316 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1318 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1319 /* its already registered! */
1320 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1322 return NT_STATUS_OBJECT_NAME_COLLISION;
1325 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1327 smb_panic("out of memory in dcerpc_register");
1330 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1331 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1335 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1338 return NT_STATUS_OK;
1342 return the operations structure for a named backend of the specified type
1344 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1348 for (i=0;i<num_ep_servers;i++) {
1349 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1350 return ep_servers[i].ep_server;
1357 void dcerpc_server_init(struct loadparm_context *lp_ctx)
1359 static bool initialized;
1360 extern NTSTATUS dcerpc_server_wkssvc_init(void);
1361 extern NTSTATUS dcerpc_server_drsuapi_init(void);
1362 extern NTSTATUS dcerpc_server_winreg_init(void);
1363 extern NTSTATUS dcerpc_server_spoolss_init(void);
1364 extern NTSTATUS dcerpc_server_epmapper_init(void);
1365 extern NTSTATUS dcerpc_server_srvsvc_init(void);
1366 extern NTSTATUS dcerpc_server_netlogon_init(void);
1367 extern NTSTATUS dcerpc_server_rpcecho_init(void);
1368 extern NTSTATUS dcerpc_server_unixinfo_init(void);
1369 extern NTSTATUS dcerpc_server_samr_init(void);
1370 extern NTSTATUS dcerpc_server_remote_init(void);
1371 extern NTSTATUS dcerpc_server_lsa_init(void);
1372 extern NTSTATUS dcerpc_server_browser_init(void);
1373 init_module_fn static_init[] = { STATIC_dcerpc_server_MODULES };
1374 init_module_fn *shared_init;
1381 shared_init = load_samba_modules(NULL, lp_ctx, "dcerpc_server");
1383 run_init_functions(static_init);
1384 run_init_functions(shared_init);
1386 talloc_free(shared_init);
1390 return the DCERPC module version, and the size of some critical types
1391 This can be used by endpoint server modules to either detect compilation errors, or provide
1392 multiple implementations for different smbd compilation options in one module
1394 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1396 static const struct dcesrv_critical_sizes critical_sizes = {
1397 DCERPC_MODULE_VERSION,
1398 sizeof(struct dcesrv_context),
1399 sizeof(struct dcesrv_endpoint),
1400 sizeof(struct dcesrv_endpoint_server),
1401 sizeof(struct dcesrv_interface),
1402 sizeof(struct dcesrv_if_list),
1403 sizeof(struct dcesrv_connection),
1404 sizeof(struct dcesrv_call_state),
1405 sizeof(struct dcesrv_auth),
1406 sizeof(struct dcesrv_handle)
1409 return &critical_sizes;