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 #define SAMBA_ASSOC_GROUP 0x12345678
41 extern const struct dcesrv_interface dcesrv_mgmt_interface;
44 see if two endpoints match
46 static bool endpoints_match(const struct dcerpc_binding *ep1,
47 const struct dcerpc_binding *ep2)
49 if (ep1->transport != ep2->transport) {
53 if (!ep1->endpoint || !ep2->endpoint) {
54 return ep1->endpoint == ep2->endpoint;
57 if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
64 find an endpoint in the dcesrv_context
66 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
67 const struct dcerpc_binding *ep_description)
69 struct dcesrv_endpoint *ep;
70 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
71 if (endpoints_match(ep->ep_description, ep_description)) {
79 find a registered context_id from a bind or alter_context
81 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn,
84 struct dcesrv_connection_context *c;
85 for (c=conn->contexts;c;c=c->next) {
86 if (c->context_id == context_id) return c;
92 see if a uuid and if_version match to an interface
94 static bool interface_match(const struct dcesrv_interface *if1,
95 const struct dcesrv_interface *if2)
97 return (if1->syntax_id.if_version == if2->syntax_id.if_version &&
98 GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
102 find the interface operations on an endpoint
104 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
105 const struct dcesrv_interface *iface)
107 struct dcesrv_if_list *ifl;
108 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
109 if (interface_match(&(ifl->iface), iface)) {
110 return &(ifl->iface);
117 see if a uuid and if_version match to an interface
119 static bool interface_match_by_uuid(const struct dcesrv_interface *iface,
120 const struct GUID *uuid, uint32_t if_version)
122 return (iface->syntax_id.if_version == if_version &&
123 GUID_equal(&iface->syntax_id.uuid, uuid));
127 find the interface operations on an endpoint by uuid
129 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
130 const struct GUID *uuid, uint32_t if_version)
132 struct dcesrv_if_list *ifl;
133 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
134 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
135 return &(ifl->iface);
142 find the earlier parts of a fragmented call awaiting reassembily
144 static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
146 struct dcesrv_call_state *c;
147 for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
148 if (c->pkt.call_id == call_id) {
156 register an interface on an endpoint
158 _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
160 const struct dcesrv_interface *iface,
161 const struct security_descriptor *sd)
163 struct dcesrv_endpoint *ep;
164 struct dcesrv_if_list *ifl;
165 struct dcerpc_binding *binding;
169 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
171 if (NT_STATUS_IS_ERR(status)) {
172 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
176 /* check if this endpoint exists
178 if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
179 ep = talloc(dce_ctx, struct dcesrv_endpoint);
181 return NT_STATUS_NO_MEMORY;
184 ep->ep_description = talloc_reference(ep, binding);
187 /* add mgmt interface */
188 ifl = talloc(dce_ctx, struct dcesrv_if_list);
190 return NT_STATUS_NO_MEMORY;
193 memcpy(&(ifl->iface), &dcesrv_mgmt_interface,
194 sizeof(struct dcesrv_interface));
196 DLIST_ADD(ep->interface_list, ifl);
199 /* see if the interface is already registered on te endpoint */
200 if (find_interface(ep, iface)!=NULL) {
201 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
202 iface->name, ep_name));
203 return NT_STATUS_OBJECT_NAME_COLLISION;
206 /* talloc a new interface list element */
207 ifl = talloc(dce_ctx, struct dcesrv_if_list);
209 return NT_STATUS_NO_MEMORY;
212 /* copy the given interface struct to the one on the endpoints interface list */
213 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
215 /* if we have a security descriptor given,
216 * we should see if we can set it up on the endpoint
219 /* if there's currently no security descriptor given on the endpoint
222 if (ep->sd == NULL) {
223 ep->sd = security_descriptor_copy(dce_ctx, sd);
226 /* if now there's no security descriptor given on the endpoint
227 * something goes wrong, either we failed to copy the security descriptor
228 * or there was already one on the endpoint
230 if (ep->sd != NULL) {
231 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
232 " on endpoint '%s'\n",
233 iface->name, ep_name));
234 if (add_ep) free(ep);
236 return NT_STATUS_OBJECT_NAME_COLLISION;
240 /* finally add the interface on the endpoint */
241 DLIST_ADD(ep->interface_list, ifl);
243 /* if it's a new endpoint add it to the dcesrv_context */
245 DLIST_ADD(dce_ctx->endpoint_list, ep);
248 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
249 iface->name, ep_name));
254 NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
255 DATA_BLOB *session_key)
257 if (p->auth_state.session_info->session_key.length) {
258 *session_key = p->auth_state.session_info->session_key;
261 return NT_STATUS_NO_USER_SESSION_KEY;
264 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
265 DATA_BLOB *session_key)
267 /* this took quite a few CPU cycles to find ... */
268 session_key->data = discard_const_p(uint8_t, "SystemLibraryDTC");
269 session_key->length = 16;
274 fetch the user session key - may be default (above) or the SMB session key
276 The key is always truncated to 16 bytes
278 _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
279 DATA_BLOB *session_key)
281 NTSTATUS status = p->auth_state.session_key(p, session_key);
282 if (!NT_STATUS_IS_OK(status)) {
286 session_key->length = MIN(session_key->length, 16);
293 destroy a link to an endpoint
295 static int dcesrv_endpoint_destructor(struct dcesrv_connection *p)
297 while (p->contexts) {
298 struct dcesrv_connection_context *c = p->contexts;
300 DLIST_REMOVE(p->contexts, c);
303 c->iface->unbind(c, c->iface);
312 connect to a dcerpc endpoint
314 _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
316 const struct dcesrv_endpoint *ep,
317 struct auth_session_info *session_info,
318 struct event_context *event_ctx,
319 struct messaging_context *msg_ctx,
320 struct server_id server_id,
321 uint32_t state_flags,
322 struct dcesrv_connection **_p)
324 struct dcesrv_connection *p;
327 return NT_STATUS_ACCESS_DENIED;
330 p = talloc(mem_ctx, struct dcesrv_connection);
331 NT_STATUS_HAVE_NO_MEMORY(p);
333 if (!talloc_reference(p, session_info)) {
335 return NT_STATUS_NO_MEMORY;
338 p->dce_ctx = dce_ctx;
342 p->packet_log_dir = lp_lockdir(dce_ctx->lp_ctx);
343 p->incoming_fragmented_call_list = NULL;
344 p->pending_call_list = NULL;
345 p->cli_max_recv_frag = 0;
346 p->partial_input = data_blob(NULL, 0);
347 p->auth_state.auth_info = NULL;
348 p->auth_state.gensec_security = NULL;
349 p->auth_state.session_info = session_info;
350 p->auth_state.session_key = dcesrv_generic_session_key;
351 p->event_ctx = event_ctx;
352 p->msg_ctx = msg_ctx;
353 p->server_id = server_id;
354 p->processing = false;
355 p->state_flags = state_flags;
356 ZERO_STRUCT(p->transport);
358 talloc_set_destructor(p, dcesrv_endpoint_destructor);
365 search and connect to a dcerpc endpoint
367 _PUBLIC_ NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
369 const struct dcerpc_binding *ep_description,
370 struct auth_session_info *session_info,
371 struct event_context *event_ctx,
372 struct messaging_context *msg_ctx,
373 struct server_id server_id,
374 uint32_t state_flags,
375 struct dcesrv_connection **dce_conn_p)
378 const struct dcesrv_endpoint *ep;
380 /* make sure this endpoint exists */
381 ep = find_endpoint(dce_ctx, ep_description);
383 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
386 status = dcesrv_endpoint_connect(dce_ctx, mem_ctx, ep, session_info,
387 event_ctx, msg_ctx, server_id,
388 state_flags, dce_conn_p);
389 NT_STATUS_NOT_OK_RETURN(status);
391 (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
393 /* TODO: check security descriptor of the endpoint here
394 * if it's a smb named pipe
395 * if it's failed free dce_conn_p
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);
497 return a dcerpc bind_nak
499 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
501 struct ncacn_packet pkt;
502 struct data_blob_list_item *rep;
505 /* setup a bind_nak */
506 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
508 pkt.call_id = call->pkt.call_id;
509 pkt.ptype = DCERPC_PKT_BIND_NAK;
510 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
511 pkt.u.bind_nak.reject_reason = reason;
512 if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
513 pkt.u.bind_nak.versions.v.num_versions = 0;
516 rep = talloc(call, struct data_blob_list_item);
518 return NT_STATUS_NO_MEMORY;
521 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
522 if (!NT_STATUS_IS_OK(status)) {
526 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
528 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
529 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
536 handle a bind request
538 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
540 uint32_t if_version, transfer_syntax_version;
541 struct GUID uuid, *transfer_syntax_uuid;
542 struct ncacn_packet pkt;
543 struct data_blob_list_item *rep;
545 uint32_t result=0, reason=0;
547 const struct dcesrv_interface *iface;
548 uint32_t extra_flags = 0;
551 * Association groups allow policy handles to be shared across
552 * multiple client connections. We don't implement this yet.
554 * So we just allow 0 if the client wants to create a new
557 * And we allow the 0x12345678 value, we give away as
558 * assoc_group_id back to the clients
560 if (call->pkt.u.bind.assoc_group_id != 0 &&
561 lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
562 call->pkt.u.bind.assoc_group_id != SAMBA_ASSOC_GROUP) {
563 return dcesrv_bind_nak(call, 0);
566 if (call->pkt.u.bind.num_contexts < 1 ||
567 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
568 return dcesrv_bind_nak(call, 0);
571 context_id = call->pkt.u.bind.ctx_list[0].context_id;
573 /* you can't bind twice on one context */
574 if (dcesrv_find_context(call->conn, context_id) != NULL) {
575 return dcesrv_bind_nak(call, 0);
578 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
579 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
581 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
582 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
583 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
584 ndr_transfer_syntax.if_version != transfer_syntax_version) {
585 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
586 /* we only do NDR encoded dcerpc */
587 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
588 talloc_free(uuid_str);
589 return dcesrv_bind_nak(call, 0);
592 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
594 char *uuid_str = GUID_string(call, &uuid);
595 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
596 talloc_free(uuid_str);
598 /* we don't know about that interface */
599 result = DCERPC_BIND_PROVIDER_REJECT;
600 reason = DCERPC_BIND_REASON_ASYNTAX;
604 /* add this context to the list of available context_ids */
605 struct dcesrv_connection_context *context = talloc(call->conn,
606 struct dcesrv_connection_context);
607 if (context == NULL) {
608 return dcesrv_bind_nak(call, 0);
610 context->conn = call->conn;
611 context->iface = iface;
612 context->context_id = context_id;
614 * we need to send a non zero assoc_group_id here to make longhorn happy,
615 * it also matches samba3
617 context->assoc_group_id = SAMBA_ASSOC_GROUP;
618 context->private = NULL;
619 context->handles = NULL;
620 DLIST_ADD(call->conn->contexts, context);
621 call->context = context;
624 if (call->conn->cli_max_recv_frag == 0) {
625 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
628 if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) &&
629 lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","header signing", false)) {
630 call->conn->state_flags |= DCESRV_CALL_STATE_FLAG_HEADER_SIGNING;
631 extra_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
634 /* handle any authentication that is being requested */
635 if (!dcesrv_auth_bind(call)) {
636 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
639 /* setup a bind_ack */
640 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
642 pkt.call_id = call->pkt.call_id;
643 pkt.ptype = DCERPC_PKT_BIND_ACK;
644 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
645 pkt.u.bind_ack.max_xmit_frag = 0x2000;
646 pkt.u.bind_ack.max_recv_frag = 0x2000;
647 pkt.u.bind_ack.assoc_group_id = call->context->assoc_group_id;
649 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
650 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
652 pkt.u.bind_ack.secondary_address = "";
654 pkt.u.bind_ack.num_results = 1;
655 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
656 if (!pkt.u.bind_ack.ctx_list) {
657 return NT_STATUS_NO_MEMORY;
659 pkt.u.bind_ack.ctx_list[0].result = result;
660 pkt.u.bind_ack.ctx_list[0].reason = reason;
661 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
662 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
664 status = dcesrv_auth_bind_ack(call, &pkt);
665 if (!NT_STATUS_IS_OK(status)) {
666 return dcesrv_bind_nak(call, 0);
670 status = iface->bind(call, iface);
671 if (!NT_STATUS_IS_OK(status)) {
672 char *uuid_str = GUID_string(call, &uuid);
673 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
674 uuid_str, if_version, nt_errstr(status)));
675 talloc_free(uuid_str);
676 return dcesrv_bind_nak(call, 0);
680 /* the iface->bind() might change the assoc_group_id */
681 pkt.u.bind_ack.assoc_group_id = call->context->assoc_group_id;
683 rep = talloc(call, struct data_blob_list_item);
685 return NT_STATUS_NO_MEMORY;
688 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
689 if (!NT_STATUS_IS_OK(status)) {
693 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
695 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
696 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
703 handle a auth3 request
705 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
707 /* handle the auth3 in the auth code */
708 if (!dcesrv_auth_auth3(call)) {
709 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
714 /* we don't send a reply to a auth3 request, except by a
721 handle a bind request
723 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
725 uint32_t if_version, transfer_syntax_version;
726 struct dcesrv_connection_context *context;
727 const struct dcesrv_interface *iface;
728 struct GUID uuid, *transfer_syntax_uuid;
731 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
732 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
734 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
735 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
736 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
737 ndr_transfer_syntax.if_version != transfer_syntax_version) {
738 /* we only do NDR encoded dcerpc */
739 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
742 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
744 char *uuid_str = GUID_string(call, &uuid);
745 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
746 talloc_free(uuid_str);
747 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
750 /* add this context to the list of available context_ids */
751 context = talloc(call->conn, struct dcesrv_connection_context);
752 if (context == NULL) {
753 return NT_STATUS_NO_MEMORY;
755 context->conn = call->conn;
756 context->iface = iface;
757 context->context_id = context_id;
758 context->assoc_group_id = SAMBA_ASSOC_GROUP;
759 context->private = NULL;
760 context->handles = NULL;
761 DLIST_ADD(call->conn->contexts, context);
762 call->context = context;
765 status = iface->bind(call, iface);
766 if (!NT_STATUS_IS_OK(status)) {
776 handle a alter context request
778 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
780 struct ncacn_packet pkt;
781 struct data_blob_list_item *rep;
783 uint32_t result=0, reason=0;
786 /* handle any authentication that is being requested */
787 if (!dcesrv_auth_alter(call)) {
788 /* TODO: work out the right reject code */
789 result = DCERPC_BIND_PROVIDER_REJECT;
790 reason = DCERPC_BIND_REASON_ASYNTAX;
793 context_id = call->pkt.u.alter.ctx_list[0].context_id;
795 /* see if they are asking for a new interface */
797 call->context = dcesrv_find_context(call->conn, context_id);
798 if (!call->context) {
799 status = dcesrv_alter_new_context(call, context_id);
800 if (!NT_STATUS_IS_OK(status)) {
801 result = DCERPC_BIND_PROVIDER_REJECT;
802 reason = DCERPC_BIND_REASON_ASYNTAX;
808 call->pkt.u.alter.assoc_group_id != 0 &&
809 lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
810 call->pkt.u.alter.assoc_group_id != call->context->assoc_group_id) {
811 /* TODO: work out what to return here */
812 result = DCERPC_BIND_PROVIDER_REJECT;
813 reason = DCERPC_BIND_REASON_ASYNTAX;
816 /* setup a alter_resp */
817 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
819 pkt.call_id = call->pkt.call_id;
820 pkt.ptype = DCERPC_PKT_ALTER_RESP;
821 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
822 pkt.u.alter_resp.max_xmit_frag = 0x2000;
823 pkt.u.alter_resp.max_recv_frag = 0x2000;
825 pkt.u.alter_resp.assoc_group_id = call->context->assoc_group_id;
827 pkt.u.alter_resp.assoc_group_id = 0;
829 pkt.u.alter_resp.num_results = 1;
830 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
831 if (!pkt.u.alter_resp.ctx_list) {
832 return NT_STATUS_NO_MEMORY;
834 pkt.u.alter_resp.ctx_list[0].result = result;
835 pkt.u.alter_resp.ctx_list[0].reason = reason;
836 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
837 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
838 pkt.u.alter_resp.secondary_address = "";
840 status = dcesrv_auth_alter_ack(call, &pkt);
841 if (!NT_STATUS_IS_OK(status)) {
842 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
843 || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
844 || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
845 || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
846 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
848 return dcesrv_fault(call, 0);
851 rep = talloc(call, struct data_blob_list_item);
853 return NT_STATUS_NO_MEMORY;
856 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
857 if (!NT_STATUS_IS_OK(status)) {
861 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
863 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
864 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
870 handle a dcerpc request packet
872 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
874 struct ndr_pull *pull;
876 struct dcesrv_connection_context *context;
878 /* if authenticated, and the mech we use can't do async replies, don't use them... */
879 if (call->conn->auth_state.gensec_security &&
880 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
881 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
884 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
885 if (context == NULL) {
886 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
889 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call,
890 lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
891 NT_STATUS_HAVE_NO_MEMORY(pull);
893 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
895 call->context = context;
896 call->ndr_pull = pull;
898 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
899 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
902 /* unravel the NDR for the packet */
903 status = context->iface->ndr_pull(call, call, pull, &call->r);
904 if (!NT_STATUS_IS_OK(status)) {
905 return dcesrv_fault(call, call->fault_code);
908 if (pull->offset != pull->data_size) {
909 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
910 pull->data_size - pull->offset));
911 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
914 /* call the dispatch function */
915 status = context->iface->dispatch(call, call, call->r);
916 if (!NT_STATUS_IS_OK(status)) {
917 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
918 context->iface->name,
919 call->pkt.u.request.opnum,
920 dcerpc_errstr(pull, call->fault_code)));
921 return dcesrv_fault(call, call->fault_code);
924 /* add the call to the pending list */
925 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
927 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
931 return dcesrv_reply(call);
934 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
936 struct ndr_push *push;
939 uint32_t total_length, chunk_size;
940 struct dcesrv_connection_context *context = call->context;
943 /* call the reply function */
944 status = context->iface->reply(call, call, call->r);
945 if (!NT_STATUS_IS_OK(status)) {
946 return dcesrv_fault(call, call->fault_code);
949 /* form the reply NDR */
950 push = ndr_push_init_ctx(call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
951 NT_STATUS_HAVE_NO_MEMORY(push);
953 /* carry over the pointer count to the reply in case we are
954 using full pointer. See NDR specification for full
956 push->ptr_count = call->ndr_pull->ptr_count;
958 if (lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
959 push->flags |= LIBNDR_FLAG_BIGENDIAN;
962 status = context->iface->ndr_push(call, call, push, call->r);
963 if (!NT_STATUS_IS_OK(status)) {
964 return dcesrv_fault(call, call->fault_code);
967 stub = ndr_push_blob(push);
969 total_length = stub.length;
971 /* we can write a full max_recv_frag size, minus the dcerpc
972 request header size */
973 chunk_size = call->conn->cli_max_recv_frag;
974 chunk_size -= DCERPC_REQUEST_LENGTH;
975 if (call->conn->auth_state.auth_info &&
976 call->conn->auth_state.gensec_security) {
977 sig_size = gensec_sig_size(call->conn->auth_state.gensec_security,
978 call->conn->cli_max_recv_frag);
980 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
981 chunk_size -= sig_size;
984 chunk_size -= (chunk_size % 16);
988 struct data_blob_list_item *rep;
989 struct ncacn_packet pkt;
991 rep = talloc(call, struct data_blob_list_item);
992 NT_STATUS_HAVE_NO_MEMORY(rep);
994 length = MIN(chunk_size, stub.length);
996 /* form the dcerpc response packet */
997 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
999 pkt.call_id = call->pkt.call_id;
1000 pkt.ptype = DCERPC_PKT_RESPONSE;
1002 if (stub.length == total_length) {
1003 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1005 if (length == stub.length) {
1006 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1008 pkt.u.response.alloc_hint = stub.length;
1009 pkt.u.response.context_id = call->pkt.u.request.context_id;
1010 pkt.u.response.cancel_count = 0;
1011 pkt.u.response.stub_and_verifier.data = stub.data;
1012 pkt.u.response.stub_and_verifier.length = length;
1014 if (!dcesrv_auth_response(call, &rep->blob, sig_size, &pkt)) {
1015 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
1018 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
1020 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
1022 stub.data += length;
1023 stub.length -= length;
1024 } while (stub.length != 0);
1026 /* move the call from the pending to the finished calls list */
1027 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
1029 if (call->conn->call_list && call->conn->call_list->replies) {
1030 if (call->conn->transport.report_output_data) {
1031 call->conn->transport.report_output_data(call->conn);
1035 return NT_STATUS_OK;
1038 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1040 if (!conn->transport.get_my_addr) {
1044 return conn->transport.get_my_addr(conn, mem_ctx);
1047 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1049 if (!conn->transport.get_peer_addr) {
1053 return conn->transport.get_peer_addr(conn, mem_ctx);
1057 work out if we have a full packet yet
1059 static bool dce_full_packet(const DATA_BLOB *data)
1061 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
1064 if (dcerpc_get_frag_length(data) > data->length) {
1071 we might have consumed only part of our input - advance past that part
1073 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
1077 if (dce_conn->partial_input.length == offset) {
1078 data_blob_free(&dce_conn->partial_input);
1082 blob = dce_conn->partial_input;
1083 dce_conn->partial_input = data_blob(blob.data + offset,
1084 blob.length - offset);
1085 data_blob_free(&blob);
1089 remove the call from the right list when freed
1091 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1093 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1098 process some input to a dcerpc endpoint server.
1100 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
1102 struct ndr_pull *ndr;
1103 enum ndr_err_code ndr_err;
1105 struct dcesrv_call_state *call;
1108 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1110 talloc_free(dce_conn->partial_input.data);
1111 return NT_STATUS_NO_MEMORY;
1113 call->conn = dce_conn;
1114 call->event_ctx = dce_conn->event_ctx;
1115 call->msg_ctx = dce_conn->msg_ctx;
1116 call->state_flags = call->conn->state_flags;
1117 call->time = timeval_current();
1118 call->list = DCESRV_LIST_NONE;
1120 talloc_set_destructor(call, dcesrv_call_dequeue);
1122 blob = dce_conn->partial_input;
1123 blob.length = dcerpc_get_frag_length(&blob);
1125 ndr = ndr_pull_init_blob(&blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
1127 talloc_free(dce_conn->partial_input.data);
1129 return NT_STATUS_NO_MEMORY;
1132 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
1133 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
1136 if (CVAL(blob.data, DCERPC_PFC_OFFSET) & DCERPC_PFC_FLAG_OBJECT_UUID) {
1137 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
1140 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
1141 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1142 talloc_free(dce_conn->partial_input.data);
1144 return ndr_map_error2ntstatus(ndr_err);
1147 /* we have to check the signing here, before combining the
1149 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1150 !dcesrv_auth_request(call, &blob)) {
1151 dce_partial_advance(dce_conn, blob.length);
1152 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1155 dce_partial_advance(dce_conn, blob.length);
1157 /* see if this is a continued packet */
1158 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1159 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1160 struct dcesrv_call_state *call2 = call;
1161 uint32_t alloc_size;
1163 /* we only allow fragmented requests, no other packet types */
1164 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1165 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1168 /* this is a continuation of an existing call - find the call then
1169 tack it on the end */
1170 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1172 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1175 if (call->pkt.ptype != call2->pkt.ptype) {
1176 /* trying to play silly buggers are we? */
1177 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1180 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1181 call2->pkt.u.request.stub_and_verifier.length;
1182 if (call->pkt.u.request.alloc_hint > alloc_size) {
1183 alloc_size = call->pkt.u.request.alloc_hint;
1186 call->pkt.u.request.stub_and_verifier.data =
1187 talloc_realloc(call,
1188 call->pkt.u.request.stub_and_verifier.data,
1189 uint8_t, alloc_size);
1190 if (!call->pkt.u.request.stub_and_verifier.data) {
1191 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1193 memcpy(call->pkt.u.request.stub_and_verifier.data +
1194 call->pkt.u.request.stub_and_verifier.length,
1195 call2->pkt.u.request.stub_and_verifier.data,
1196 call2->pkt.u.request.stub_and_verifier.length);
1197 call->pkt.u.request.stub_and_verifier.length +=
1198 call2->pkt.u.request.stub_and_verifier.length;
1200 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1205 /* this may not be the last pdu in the chain - if its isn't then
1206 just put it on the incoming_fragmented_call_list and wait for the rest */
1207 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1208 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1209 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1210 return NT_STATUS_OK;
1213 /* This removes any fragments we may have had stashed away */
1214 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1216 switch (call->pkt.ptype) {
1217 case DCERPC_PKT_BIND:
1218 status = dcesrv_bind(call);
1220 case DCERPC_PKT_AUTH3:
1221 status = dcesrv_auth3(call);
1223 case DCERPC_PKT_ALTER:
1224 status = dcesrv_alter(call);
1226 case DCERPC_PKT_REQUEST:
1227 status = dcesrv_request(call);
1230 status = NT_STATUS_INVALID_PARAMETER;
1234 /* if we are going to be sending a reply then add
1235 it to the list of pending calls. We add it to the end to keep the call
1236 list in the order we will answer */
1237 if (!NT_STATUS_IS_OK(status)) {
1246 provide some input to a dcerpc endpoint server. This passes data
1247 from a dcerpc client into the server
1249 _PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1253 dce_conn->partial_input.data = talloc_realloc(dce_conn,
1254 dce_conn->partial_input.data,
1256 dce_conn->partial_input.length + data->length);
1257 if (!dce_conn->partial_input.data) {
1258 return NT_STATUS_NO_MEMORY;
1260 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1261 data->data, data->length);
1262 dce_conn->partial_input.length += data->length;
1264 while (dce_full_packet(&dce_conn->partial_input)) {
1265 status = dcesrv_input_process(dce_conn);
1266 if (!NT_STATUS_IS_OK(status)) {
1271 return NT_STATUS_OK;
1275 retrieve some output from a dcerpc server
1276 The caller supplies a function that will be called to do the
1279 The first argument to write_fn() will be 'private', the second will
1280 be a pointer to a buffer containing the data to be sent and the 3rd
1281 will be a pointer to a size_t variable that will be set to the
1282 number of bytes that are consumed from the output.
1284 from the current fragment
1286 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
1288 NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1291 struct dcesrv_call_state *call;
1292 struct data_blob_list_item *rep;
1295 call = dce_conn->call_list;
1296 if (!call || !call->replies) {
1297 if (dce_conn->pending_call_list) {
1298 /* TODO: we need to say act async here
1299 * as we know we have pending requests
1300 * which will be finished at a time
1302 return NT_STATUS_FOOBAR;
1304 return NT_STATUS_FOOBAR;
1306 rep = call->replies;
1308 status = write_fn(private_data, &rep->blob, &nwritten);
1309 NT_STATUS_IS_ERR_RETURN(status);
1311 rep->blob.length -= nwritten;
1312 rep->blob.data += nwritten;
1314 if (rep->blob.length == 0) {
1315 /* we're done with this section of the call */
1316 DLIST_REMOVE(call->replies, rep);
1319 if (call->replies == NULL) {
1320 /* we're done with the whole call */
1321 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1328 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1329 struct loadparm_context *lp_ctx,
1330 const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1333 struct dcesrv_context *dce_ctx;
1336 if (!endpoint_servers) {
1337 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1338 return NT_STATUS_INTERNAL_ERROR;
1341 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1342 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1343 dce_ctx->endpoint_list = NULL;
1344 dce_ctx->lp_ctx = lp_ctx;
1346 for (i=0;endpoint_servers[i];i++) {
1347 const struct dcesrv_endpoint_server *ep_server;
1349 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1351 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1352 return NT_STATUS_INTERNAL_ERROR;
1355 status = ep_server->init_server(dce_ctx, ep_server);
1356 if (!NT_STATUS_IS_OK(status)) {
1357 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1358 nt_errstr(status)));
1363 *_dce_ctx = dce_ctx;
1364 return NT_STATUS_OK;
1367 /* the list of currently registered DCERPC endpoint servers.
1369 static struct ep_server {
1370 struct dcesrv_endpoint_server *ep_server;
1371 } *ep_servers = NULL;
1372 static int num_ep_servers;
1375 register a DCERPC endpoint server.
1377 The 'name' can be later used by other backends to find the operations
1378 structure for this backend.
1380 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1382 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1384 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1386 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1387 /* its already registered! */
1388 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1390 return NT_STATUS_OBJECT_NAME_COLLISION;
1393 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1395 smb_panic("out of memory in dcerpc_register");
1398 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1399 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1403 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1406 return NT_STATUS_OK;
1410 return the operations structure for a named backend of the specified type
1412 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1416 for (i=0;i<num_ep_servers;i++) {
1417 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1418 return ep_servers[i].ep_server;
1426 return the DCERPC module version, and the size of some critical types
1427 This can be used by endpoint server modules to either detect compilation errors, or provide
1428 multiple implementations for different smbd compilation options in one module
1430 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1432 static const struct dcesrv_critical_sizes critical_sizes = {
1433 DCERPC_MODULE_VERSION,
1434 sizeof(struct dcesrv_context),
1435 sizeof(struct dcesrv_endpoint),
1436 sizeof(struct dcesrv_endpoint_server),
1437 sizeof(struct dcesrv_interface),
1438 sizeof(struct dcesrv_if_list),
1439 sizeof(struct dcesrv_connection),
1440 sizeof(struct dcesrv_call_state),
1441 sizeof(struct dcesrv_auth),
1442 sizeof(struct dcesrv_handle)
1445 return &critical_sizes;
1449 initialise the dcerpc server context for ncacn_np based services
1451 _PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
1452 struct dcesrv_context **_dce_ctx)
1455 struct dcesrv_context *dce_ctx;
1457 status = dcesrv_init_context(mem_ctx, lp_ctx, lp_dcerpc_endpoint_servers(lp_ctx), &dce_ctx);
1458 NT_STATUS_NOT_OK_RETURN(status);
1460 *_dce_ctx = dce_ctx;
1461 return NT_STATUS_OK;