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 dcesrv_find_context(call->conn, context_id) == NULL) {
798 status = dcesrv_alter_new_context(call, context_id);
799 if (!NT_STATUS_IS_OK(status)) {
800 result = DCERPC_BIND_PROVIDER_REJECT;
801 reason = DCERPC_BIND_REASON_ASYNTAX;
806 call->pkt.u.alter.assoc_group_id != 0 &&
807 lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
808 call->pkt.u.alter.assoc_group_id != call->context->assoc_group_id) {
809 /* TODO: work out what to return here */
810 result = DCERPC_BIND_PROVIDER_REJECT;
811 reason = DCERPC_BIND_REASON_ASYNTAX;
814 /* setup a alter_resp */
815 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
817 pkt.call_id = call->pkt.call_id;
818 pkt.ptype = DCERPC_PKT_ALTER_RESP;
819 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
820 pkt.u.alter_resp.max_xmit_frag = 0x2000;
821 pkt.u.alter_resp.max_recv_frag = 0x2000;
822 pkt.u.alter_resp.assoc_group_id = call->context->assoc_group_id;
823 pkt.u.alter_resp.num_results = 1;
824 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
825 if (!pkt.u.alter_resp.ctx_list) {
826 return NT_STATUS_NO_MEMORY;
828 pkt.u.alter_resp.ctx_list[0].result = result;
829 pkt.u.alter_resp.ctx_list[0].reason = reason;
830 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
831 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
832 pkt.u.alter_resp.secondary_address = "";
834 status = dcesrv_auth_alter_ack(call, &pkt);
835 if (!NT_STATUS_IS_OK(status)) {
836 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
837 || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
838 || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
839 || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
840 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
842 return dcesrv_fault(call, 0);
845 rep = talloc(call, struct data_blob_list_item);
847 return NT_STATUS_NO_MEMORY;
850 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
851 if (!NT_STATUS_IS_OK(status)) {
855 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
857 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
858 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
864 handle a dcerpc request packet
866 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
868 struct ndr_pull *pull;
870 struct dcesrv_connection_context *context;
872 /* if authenticated, and the mech we use can't do async replies, don't use them... */
873 if (call->conn->auth_state.gensec_security &&
874 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
875 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
878 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
879 if (context == NULL) {
880 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
883 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call,
884 lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
885 NT_STATUS_HAVE_NO_MEMORY(pull);
887 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
889 call->context = context;
890 call->ndr_pull = pull;
892 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
893 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
896 /* unravel the NDR for the packet */
897 status = context->iface->ndr_pull(call, call, pull, &call->r);
898 if (!NT_STATUS_IS_OK(status)) {
899 return dcesrv_fault(call, call->fault_code);
902 if (pull->offset != pull->data_size) {
903 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
904 pull->data_size - pull->offset));
905 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
908 /* call the dispatch function */
909 status = context->iface->dispatch(call, call, call->r);
910 if (!NT_STATUS_IS_OK(status)) {
911 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
912 context->iface->name,
913 call->pkt.u.request.opnum,
914 dcerpc_errstr(pull, call->fault_code)));
915 return dcesrv_fault(call, call->fault_code);
918 /* add the call to the pending list */
919 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
921 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
925 return dcesrv_reply(call);
928 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
930 struct ndr_push *push;
933 uint32_t total_length, chunk_size;
934 struct dcesrv_connection_context *context = call->context;
937 /* call the reply function */
938 status = context->iface->reply(call, call, call->r);
939 if (!NT_STATUS_IS_OK(status)) {
940 return dcesrv_fault(call, call->fault_code);
943 /* form the reply NDR */
944 push = ndr_push_init_ctx(call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
945 NT_STATUS_HAVE_NO_MEMORY(push);
947 /* carry over the pointer count to the reply in case we are
948 using full pointer. See NDR specification for full
950 push->ptr_count = call->ndr_pull->ptr_count;
952 if (lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
953 push->flags |= LIBNDR_FLAG_BIGENDIAN;
956 status = context->iface->ndr_push(call, call, push, call->r);
957 if (!NT_STATUS_IS_OK(status)) {
958 return dcesrv_fault(call, call->fault_code);
961 stub = ndr_push_blob(push);
963 total_length = stub.length;
965 /* we can write a full max_recv_frag size, minus the dcerpc
966 request header size */
967 chunk_size = call->conn->cli_max_recv_frag;
968 chunk_size -= DCERPC_REQUEST_LENGTH;
969 if (call->conn->auth_state.auth_info &&
970 call->conn->auth_state.gensec_security) {
971 sig_size = gensec_sig_size(call->conn->auth_state.gensec_security,
972 call->conn->cli_max_recv_frag);
974 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
975 chunk_size -= sig_size;
978 chunk_size -= (chunk_size % 16);
982 struct data_blob_list_item *rep;
983 struct ncacn_packet pkt;
985 rep = talloc(call, struct data_blob_list_item);
986 NT_STATUS_HAVE_NO_MEMORY(rep);
988 length = MIN(chunk_size, stub.length);
990 /* form the dcerpc response packet */
991 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
993 pkt.call_id = call->pkt.call_id;
994 pkt.ptype = DCERPC_PKT_RESPONSE;
996 if (stub.length == total_length) {
997 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
999 if (length == stub.length) {
1000 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1002 pkt.u.response.alloc_hint = stub.length;
1003 pkt.u.response.context_id = call->pkt.u.request.context_id;
1004 pkt.u.response.cancel_count = 0;
1005 pkt.u.response.stub_and_verifier.data = stub.data;
1006 pkt.u.response.stub_and_verifier.length = length;
1008 if (!dcesrv_auth_response(call, &rep->blob, sig_size, &pkt)) {
1009 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
1012 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
1014 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
1016 stub.data += length;
1017 stub.length -= length;
1018 } while (stub.length != 0);
1020 /* move the call from the pending to the finished calls list */
1021 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
1023 if (call->conn->call_list && call->conn->call_list->replies) {
1024 if (call->conn->transport.report_output_data) {
1025 call->conn->transport.report_output_data(call->conn);
1029 return NT_STATUS_OK;
1032 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1034 if (!conn->transport.get_my_addr) {
1038 return conn->transport.get_my_addr(conn, mem_ctx);
1041 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1043 if (!conn->transport.get_peer_addr) {
1047 return conn->transport.get_peer_addr(conn, mem_ctx);
1051 work out if we have a full packet yet
1053 static bool dce_full_packet(const DATA_BLOB *data)
1055 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
1058 if (dcerpc_get_frag_length(data) > data->length) {
1065 we might have consumed only part of our input - advance past that part
1067 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
1071 if (dce_conn->partial_input.length == offset) {
1072 data_blob_free(&dce_conn->partial_input);
1076 blob = dce_conn->partial_input;
1077 dce_conn->partial_input = data_blob(blob.data + offset,
1078 blob.length - offset);
1079 data_blob_free(&blob);
1083 remove the call from the right list when freed
1085 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1087 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1092 process some input to a dcerpc endpoint server.
1094 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
1096 struct ndr_pull *ndr;
1097 enum ndr_err_code ndr_err;
1099 struct dcesrv_call_state *call;
1102 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1104 talloc_free(dce_conn->partial_input.data);
1105 return NT_STATUS_NO_MEMORY;
1107 call->conn = dce_conn;
1108 call->event_ctx = dce_conn->event_ctx;
1109 call->msg_ctx = dce_conn->msg_ctx;
1110 call->state_flags = call->conn->state_flags;
1111 call->time = timeval_current();
1112 call->list = DCESRV_LIST_NONE;
1114 talloc_set_destructor(call, dcesrv_call_dequeue);
1116 blob = dce_conn->partial_input;
1117 blob.length = dcerpc_get_frag_length(&blob);
1119 ndr = ndr_pull_init_blob(&blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
1121 talloc_free(dce_conn->partial_input.data);
1123 return NT_STATUS_NO_MEMORY;
1126 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
1127 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
1130 if (CVAL(blob.data, DCERPC_PFC_OFFSET) & DCERPC_PFC_FLAG_OBJECT_UUID) {
1131 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
1134 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
1135 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1136 talloc_free(dce_conn->partial_input.data);
1138 return ndr_map_error2ntstatus(ndr_err);
1141 /* we have to check the signing here, before combining the
1143 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1144 !dcesrv_auth_request(call, &blob)) {
1145 dce_partial_advance(dce_conn, blob.length);
1146 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1149 dce_partial_advance(dce_conn, blob.length);
1151 /* see if this is a continued packet */
1152 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1153 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1154 struct dcesrv_call_state *call2 = call;
1155 uint32_t alloc_size;
1157 /* we only allow fragmented requests, no other packet types */
1158 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1159 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1162 /* this is a continuation of an existing call - find the call then
1163 tack it on the end */
1164 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1166 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1169 if (call->pkt.ptype != call2->pkt.ptype) {
1170 /* trying to play silly buggers are we? */
1171 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1174 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1175 call2->pkt.u.request.stub_and_verifier.length;
1176 if (call->pkt.u.request.alloc_hint > alloc_size) {
1177 alloc_size = call->pkt.u.request.alloc_hint;
1180 call->pkt.u.request.stub_and_verifier.data =
1181 talloc_realloc(call,
1182 call->pkt.u.request.stub_and_verifier.data,
1183 uint8_t, alloc_size);
1184 if (!call->pkt.u.request.stub_and_verifier.data) {
1185 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1187 memcpy(call->pkt.u.request.stub_and_verifier.data +
1188 call->pkt.u.request.stub_and_verifier.length,
1189 call2->pkt.u.request.stub_and_verifier.data,
1190 call2->pkt.u.request.stub_and_verifier.length);
1191 call->pkt.u.request.stub_and_verifier.length +=
1192 call2->pkt.u.request.stub_and_verifier.length;
1194 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1199 /* this may not be the last pdu in the chain - if its isn't then
1200 just put it on the incoming_fragmented_call_list and wait for the rest */
1201 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1202 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1203 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1204 return NT_STATUS_OK;
1207 /* This removes any fragments we may have had stashed away */
1208 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1210 switch (call->pkt.ptype) {
1211 case DCERPC_PKT_BIND:
1212 status = dcesrv_bind(call);
1214 case DCERPC_PKT_AUTH3:
1215 status = dcesrv_auth3(call);
1217 case DCERPC_PKT_ALTER:
1218 status = dcesrv_alter(call);
1220 case DCERPC_PKT_REQUEST:
1221 status = dcesrv_request(call);
1224 status = NT_STATUS_INVALID_PARAMETER;
1228 /* if we are going to be sending a reply then add
1229 it to the list of pending calls. We add it to the end to keep the call
1230 list in the order we will answer */
1231 if (!NT_STATUS_IS_OK(status)) {
1240 provide some input to a dcerpc endpoint server. This passes data
1241 from a dcerpc client into the server
1243 _PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1247 dce_conn->partial_input.data = talloc_realloc(dce_conn,
1248 dce_conn->partial_input.data,
1250 dce_conn->partial_input.length + data->length);
1251 if (!dce_conn->partial_input.data) {
1252 return NT_STATUS_NO_MEMORY;
1254 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1255 data->data, data->length);
1256 dce_conn->partial_input.length += data->length;
1258 while (dce_full_packet(&dce_conn->partial_input)) {
1259 status = dcesrv_input_process(dce_conn);
1260 if (!NT_STATUS_IS_OK(status)) {
1265 return NT_STATUS_OK;
1269 retrieve some output from a dcerpc server
1270 The caller supplies a function that will be called to do the
1273 The first argument to write_fn() will be 'private', the second will
1274 be a pointer to a buffer containing the data to be sent and the 3rd
1275 will be a pointer to a size_t variable that will be set to the
1276 number of bytes that are consumed from the output.
1278 from the current fragment
1280 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
1282 NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1285 struct dcesrv_call_state *call;
1286 struct data_blob_list_item *rep;
1289 call = dce_conn->call_list;
1290 if (!call || !call->replies) {
1291 if (dce_conn->pending_call_list) {
1292 /* TODO: we need to say act async here
1293 * as we know we have pending requests
1294 * which will be finished at a time
1296 return NT_STATUS_FOOBAR;
1298 return NT_STATUS_FOOBAR;
1300 rep = call->replies;
1302 status = write_fn(private_data, &rep->blob, &nwritten);
1303 NT_STATUS_IS_ERR_RETURN(status);
1305 rep->blob.length -= nwritten;
1306 rep->blob.data += nwritten;
1308 if (rep->blob.length == 0) {
1309 /* we're done with this section of the call */
1310 DLIST_REMOVE(call->replies, rep);
1313 if (call->replies == NULL) {
1314 /* we're done with the whole call */
1315 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1322 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1323 struct loadparm_context *lp_ctx,
1324 const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1327 struct dcesrv_context *dce_ctx;
1330 if (!endpoint_servers) {
1331 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1332 return NT_STATUS_INTERNAL_ERROR;
1335 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1336 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1337 dce_ctx->endpoint_list = NULL;
1338 dce_ctx->lp_ctx = lp_ctx;
1340 for (i=0;endpoint_servers[i];i++) {
1341 const struct dcesrv_endpoint_server *ep_server;
1343 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1345 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1346 return NT_STATUS_INTERNAL_ERROR;
1349 status = ep_server->init_server(dce_ctx, ep_server);
1350 if (!NT_STATUS_IS_OK(status)) {
1351 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1352 nt_errstr(status)));
1357 *_dce_ctx = dce_ctx;
1358 return NT_STATUS_OK;
1361 /* the list of currently registered DCERPC endpoint servers.
1363 static struct ep_server {
1364 struct dcesrv_endpoint_server *ep_server;
1365 } *ep_servers = NULL;
1366 static int num_ep_servers;
1369 register a DCERPC endpoint server.
1371 The 'name' can be later used by other backends to find the operations
1372 structure for this backend.
1374 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1376 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1378 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1380 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1381 /* its already registered! */
1382 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1384 return NT_STATUS_OBJECT_NAME_COLLISION;
1387 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1389 smb_panic("out of memory in dcerpc_register");
1392 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1393 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1397 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1400 return NT_STATUS_OK;
1404 return the operations structure for a named backend of the specified type
1406 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1410 for (i=0;i<num_ep_servers;i++) {
1411 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1412 return ep_servers[i].ep_server;
1420 return the DCERPC module version, and the size of some critical types
1421 This can be used by endpoint server modules to either detect compilation errors, or provide
1422 multiple implementations for different smbd compilation options in one module
1424 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1426 static const struct dcesrv_critical_sizes critical_sizes = {
1427 DCERPC_MODULE_VERSION,
1428 sizeof(struct dcesrv_context),
1429 sizeof(struct dcesrv_endpoint),
1430 sizeof(struct dcesrv_endpoint_server),
1431 sizeof(struct dcesrv_interface),
1432 sizeof(struct dcesrv_if_list),
1433 sizeof(struct dcesrv_connection),
1434 sizeof(struct dcesrv_call_state),
1435 sizeof(struct dcesrv_auth),
1436 sizeof(struct dcesrv_handle)
1439 return &critical_sizes;
1443 initialise the dcerpc server context for ncacn_np based services
1445 _PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
1446 struct dcesrv_context **_dce_ctx)
1449 struct dcesrv_context *dce_ctx;
1451 status = dcesrv_init_context(mem_ctx, lp_ctx, lp_dcerpc_endpoint_servers(lp_ctx), &dce_ctx);
1452 NT_STATUS_NOT_OK_RETURN(status);
1454 *_dce_ctx = dce_ctx;
1455 return NT_STATUS_OK;