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 extern const struct dcesrv_interface dcesrv_mgmt_interface;
42 see if two endpoints match
44 static bool endpoints_match(const struct dcerpc_binding *ep1,
45 const struct dcerpc_binding *ep2)
47 if (ep1->transport != ep2->transport) {
51 if (!ep1->endpoint || !ep2->endpoint) {
52 return ep1->endpoint == ep2->endpoint;
55 if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
62 find an endpoint in the dcesrv_context
64 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
65 const struct dcerpc_binding *ep_description)
67 struct dcesrv_endpoint *ep;
68 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
69 if (endpoints_match(ep->ep_description, ep_description)) {
77 find a registered context_id from a bind or alter_context
79 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn,
82 struct dcesrv_connection_context *c;
83 for (c=conn->contexts;c;c=c->next) {
84 if (c->context_id == context_id) return c;
90 see if a uuid and if_version match to an interface
92 static bool interface_match(const struct dcesrv_interface *if1,
93 const struct dcesrv_interface *if2)
95 return (if1->syntax_id.if_version == if2->syntax_id.if_version &&
96 GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
100 find the interface operations on an endpoint
102 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
103 const struct dcesrv_interface *iface)
105 struct dcesrv_if_list *ifl;
106 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
107 if (interface_match(&(ifl->iface), iface)) {
108 return &(ifl->iface);
115 see if a uuid and if_version match to an interface
117 static bool interface_match_by_uuid(const struct dcesrv_interface *iface,
118 const struct GUID *uuid, uint32_t if_version)
120 return (iface->syntax_id.if_version == if_version &&
121 GUID_equal(&iface->syntax_id.uuid, uuid));
125 find the interface operations on an endpoint by uuid
127 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
128 const struct GUID *uuid, uint32_t if_version)
130 struct dcesrv_if_list *ifl;
131 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
132 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
133 return &(ifl->iface);
140 find the earlier parts of a fragmented call awaiting reassembily
142 static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
144 struct dcesrv_call_state *c;
145 for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
146 if (c->pkt.call_id == call_id) {
154 register an interface on an endpoint
156 _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
158 const struct dcesrv_interface *iface,
159 const struct security_descriptor *sd)
161 struct dcesrv_endpoint *ep;
162 struct dcesrv_if_list *ifl;
163 struct dcerpc_binding *binding;
167 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
169 if (NT_STATUS_IS_ERR(status)) {
170 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
174 /* check if this endpoint exists
176 if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
177 ep = talloc(dce_ctx, struct dcesrv_endpoint);
179 return NT_STATUS_NO_MEMORY;
182 ep->ep_description = talloc_reference(ep, binding);
185 /* add mgmt interface */
186 ifl = talloc(dce_ctx, struct dcesrv_if_list);
188 return NT_STATUS_NO_MEMORY;
191 memcpy(&(ifl->iface), &dcesrv_mgmt_interface,
192 sizeof(struct dcesrv_interface));
194 DLIST_ADD(ep->interface_list, ifl);
197 /* see if the interface is already registered on te endpoint */
198 if (find_interface(ep, iface)!=NULL) {
199 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
200 iface->name, ep_name));
201 return NT_STATUS_OBJECT_NAME_COLLISION;
204 /* talloc a new interface list element */
205 ifl = talloc(dce_ctx, struct dcesrv_if_list);
207 return NT_STATUS_NO_MEMORY;
210 /* copy the given interface struct to the one on the endpoints interface list */
211 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
213 /* if we have a security descriptor given,
214 * we should see if we can set it up on the endpoint
217 /* if there's currently no security descriptor given on the endpoint
220 if (ep->sd == NULL) {
221 ep->sd = security_descriptor_copy(dce_ctx, sd);
224 /* if now there's no security descriptor given on the endpoint
225 * something goes wrong, either we failed to copy the security descriptor
226 * or there was already one on the endpoint
228 if (ep->sd != NULL) {
229 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
230 " on endpoint '%s'\n",
231 iface->name, ep_name));
232 if (add_ep) free(ep);
234 return NT_STATUS_OBJECT_NAME_COLLISION;
238 /* finally add the interface on the endpoint */
239 DLIST_ADD(ep->interface_list, ifl);
241 /* if it's a new endpoint add it to the dcesrv_context */
243 DLIST_ADD(dce_ctx->endpoint_list, ep);
246 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
247 iface->name, ep_name));
252 static NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
253 DATA_BLOB *session_key)
255 if (p->auth_state.session_info->session_key.length) {
256 *session_key = p->auth_state.session_info->session_key;
259 return NT_STATUS_NO_USER_SESSION_KEY;
262 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
263 DATA_BLOB *session_key)
265 /* this took quite a few CPU cycles to find ... */
266 session_key->data = discard_const_p(uint8_t, "SystemLibraryDTC");
267 session_key->length = 16;
272 fetch the user session key - may be default (above) or the SMB session key
274 The key is always truncated to 16 bytes
276 _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
277 DATA_BLOB *session_key)
279 NTSTATUS status = p->auth_state.session_key(p, session_key);
280 if (!NT_STATUS_IS_OK(status)) {
284 session_key->length = MIN(session_key->length, 16);
291 destroy a link to an endpoint
293 static int dcesrv_endpoint_destructor(struct dcesrv_connection *p)
295 while (p->contexts) {
296 struct dcesrv_connection_context *c = p->contexts;
298 DLIST_REMOVE(p->contexts, c);
301 c->iface->unbind(c, c->iface);
310 connect to a dcerpc endpoint
312 _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
314 const struct dcesrv_endpoint *ep,
315 struct auth_session_info *session_info,
316 struct event_context *event_ctx,
317 struct messaging_context *msg_ctx,
318 struct server_id server_id,
319 uint32_t state_flags,
320 struct dcesrv_connection **_p)
322 struct dcesrv_connection *p;
325 return NT_STATUS_ACCESS_DENIED;
328 p = talloc(mem_ctx, struct dcesrv_connection);
329 NT_STATUS_HAVE_NO_MEMORY(p);
331 if (!talloc_reference(p, session_info)) {
333 return NT_STATUS_NO_MEMORY;
336 p->dce_ctx = dce_ctx;
340 p->incoming_fragmented_call_list = NULL;
341 p->pending_call_list = NULL;
342 p->cli_max_recv_frag = 0;
343 p->partial_input = data_blob(NULL, 0);
344 p->auth_state.auth_info = NULL;
345 p->auth_state.gensec_security = NULL;
346 p->auth_state.session_info = session_info;
347 p->auth_state.session_key = dcesrv_generic_session_key;
348 p->event_ctx = event_ctx;
349 p->msg_ctx = msg_ctx;
350 p->server_id = server_id;
351 p->processing = false;
352 p->state_flags = state_flags;
353 ZERO_STRUCT(p->transport);
355 talloc_set_destructor(p, dcesrv_endpoint_destructor);
362 search and connect to a dcerpc endpoint
364 _PUBLIC_ NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
366 const struct dcerpc_binding *ep_description,
367 struct auth_session_info *session_info,
368 struct event_context *event_ctx,
369 struct messaging_context *msg_ctx,
370 struct server_id server_id,
371 uint32_t state_flags,
372 struct dcesrv_connection **dce_conn_p)
375 const struct dcesrv_endpoint *ep;
377 /* make sure this endpoint exists */
378 ep = find_endpoint(dce_ctx, ep_description);
380 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
383 status = dcesrv_endpoint_connect(dce_ctx, mem_ctx, ep, session_info,
384 event_ctx, msg_ctx, server_id,
385 state_flags, dce_conn_p);
386 NT_STATUS_NOT_OK_RETURN(status);
388 (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
390 /* TODO: check security descriptor of the endpoint here
391 * if it's a smb named pipe
392 * if it's failed free dce_conn_p
399 static void dcesrv_init_hdr(struct ncacn_packet *pkt, bool bigendian)
402 pkt->rpc_vers_minor = 0;
406 pkt->drep[0] = DCERPC_DREP_LE;
414 move a call from an existing linked list to the specified list. This
415 prevents bugs where we forget to remove the call from a previous
418 static void dcesrv_call_set_list(struct dcesrv_call_state *call,
419 enum dcesrv_call_list list)
421 switch (call->list) {
422 case DCESRV_LIST_NONE:
424 case DCESRV_LIST_CALL_LIST:
425 DLIST_REMOVE(call->conn->call_list, call);
427 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
428 DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
430 case DCESRV_LIST_PENDING_CALL_LIST:
431 DLIST_REMOVE(call->conn->pending_call_list, call);
436 case DCESRV_LIST_NONE:
438 case DCESRV_LIST_CALL_LIST:
439 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
441 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
442 DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
444 case DCESRV_LIST_PENDING_CALL_LIST:
445 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
451 return a dcerpc fault
453 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
455 struct ncacn_packet pkt;
456 struct data_blob_list_item *rep;
460 /* setup a bind_ack */
461 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
463 pkt.call_id = call->pkt.call_id;
464 pkt.ptype = DCERPC_PKT_FAULT;
465 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
466 pkt.u.fault.alloc_hint = 0;
467 pkt.u.fault.context_id = 0;
468 pkt.u.fault.cancel_count = 0;
469 pkt.u.fault.status = fault_code;
472 pkt.u.fault._pad = data_blob_const(zeros, sizeof(zeros));
474 rep = talloc(call, struct data_blob_list_item);
476 return NT_STATUS_NO_MEMORY;
479 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
480 if (!NT_STATUS_IS_OK(status)) {
484 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
486 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
487 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
494 return a dcerpc bind_nak
496 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
498 struct ncacn_packet pkt;
499 struct data_blob_list_item *rep;
502 /* setup a bind_nak */
503 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
505 pkt.call_id = call->pkt.call_id;
506 pkt.ptype = DCERPC_PKT_BIND_NAK;
507 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
508 pkt.u.bind_nak.reject_reason = reason;
509 if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
510 pkt.u.bind_nak.versions.v.num_versions = 0;
513 rep = talloc(call, struct data_blob_list_item);
515 return NT_STATUS_NO_MEMORY;
518 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
519 if (!NT_STATUS_IS_OK(status)) {
523 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
525 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
526 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
533 handle a bind request
535 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
537 uint32_t if_version, transfer_syntax_version;
538 struct GUID uuid, *transfer_syntax_uuid;
539 struct ncacn_packet pkt;
540 struct data_blob_list_item *rep;
542 uint32_t result=0, reason=0;
544 const struct dcesrv_interface *iface;
547 * Association groups allow policy handles to be shared across
548 * multiple client connections. We don't implement this yet.
550 * So we just allow 0 if the client wants to create a new
553 * And we allow the 0x12345678 value, we give away as
554 * assoc_group_id back to the clients
556 if (call->pkt.u.bind.assoc_group_id != 0 &&
557 call->pkt.u.bind.assoc_group_id != 0x12345678) {
558 return dcesrv_bind_nak(call, 0);
561 if (call->pkt.u.bind.num_contexts < 1 ||
562 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
563 return dcesrv_bind_nak(call, 0);
566 context_id = call->pkt.u.bind.ctx_list[0].context_id;
568 /* you can't bind twice on one context */
569 if (dcesrv_find_context(call->conn, context_id) != NULL) {
570 return dcesrv_bind_nak(call, 0);
573 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
574 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
576 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
577 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
578 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
579 ndr_transfer_syntax.if_version != transfer_syntax_version) {
580 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
581 /* we only do NDR encoded dcerpc */
582 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
583 talloc_free(uuid_str);
584 return dcesrv_bind_nak(call, 0);
587 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
589 char *uuid_str = GUID_string(call, &uuid);
590 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
591 talloc_free(uuid_str);
593 /* we don't know about that interface */
594 result = DCERPC_BIND_PROVIDER_REJECT;
595 reason = DCERPC_BIND_REASON_ASYNTAX;
599 /* add this context to the list of available context_ids */
600 struct dcesrv_connection_context *context = talloc(call->conn,
601 struct dcesrv_connection_context);
602 if (context == NULL) {
603 return dcesrv_bind_nak(call, 0);
605 context->conn = call->conn;
606 context->iface = iface;
607 context->context_id = context_id;
608 context->private = NULL;
609 context->handles = NULL;
610 DLIST_ADD(call->conn->contexts, context);
611 call->context = context;
614 if (call->conn->cli_max_recv_frag == 0) {
615 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
618 /* handle any authentication that is being requested */
619 if (!dcesrv_auth_bind(call)) {
620 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
623 /* setup a bind_ack */
624 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
626 pkt.call_id = call->pkt.call_id;
627 pkt.ptype = DCERPC_PKT_BIND_ACK;
628 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
629 pkt.u.bind_ack.max_xmit_frag = 0x2000;
630 pkt.u.bind_ack.max_recv_frag = 0x2000;
631 /* we need to send a non zero assoc_group_id here to make longhorn happy, it also matches samba3 */
632 pkt.u.bind_ack.assoc_group_id = 0x12345678;
634 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
635 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
637 pkt.u.bind_ack.secondary_address = "";
639 pkt.u.bind_ack.num_results = 1;
640 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
641 if (!pkt.u.bind_ack.ctx_list) {
642 return NT_STATUS_NO_MEMORY;
644 pkt.u.bind_ack.ctx_list[0].result = result;
645 pkt.u.bind_ack.ctx_list[0].reason = reason;
646 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
647 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
649 status = dcesrv_auth_bind_ack(call, &pkt);
650 if (!NT_STATUS_IS_OK(status)) {
651 return dcesrv_bind_nak(call, 0);
655 status = iface->bind(call, iface);
656 if (!NT_STATUS_IS_OK(status)) {
657 char *uuid_str = GUID_string(call, &uuid);
658 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
659 uuid_str, if_version, nt_errstr(status)));
660 talloc_free(uuid_str);
661 return dcesrv_bind_nak(call, 0);
665 rep = talloc(call, struct data_blob_list_item);
667 return NT_STATUS_NO_MEMORY;
670 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
671 if (!NT_STATUS_IS_OK(status)) {
675 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
677 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
678 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
685 handle a auth3 request
687 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
689 /* handle the auth3 in the auth code */
690 if (!dcesrv_auth_auth3(call)) {
691 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
696 /* we don't send a reply to a auth3 request, except by a
703 handle a bind request
705 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
707 uint32_t if_version, transfer_syntax_version;
708 struct dcesrv_connection_context *context;
709 const struct dcesrv_interface *iface;
710 struct GUID uuid, *transfer_syntax_uuid;
713 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
714 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
716 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
717 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
718 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
719 ndr_transfer_syntax.if_version != transfer_syntax_version) {
720 /* we only do NDR encoded dcerpc */
721 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
724 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
726 char *uuid_str = GUID_string(call, &uuid);
727 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
728 talloc_free(uuid_str);
729 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
732 /* add this context to the list of available context_ids */
733 context = talloc(call->conn, struct dcesrv_connection_context);
734 if (context == NULL) {
735 return NT_STATUS_NO_MEMORY;
737 context->conn = call->conn;
738 context->iface = iface;
739 context->context_id = context_id;
740 context->private = NULL;
741 context->handles = NULL;
742 DLIST_ADD(call->conn->contexts, context);
743 call->context = context;
746 status = iface->bind(call, iface);
747 if (!NT_STATUS_IS_OK(status)) {
757 handle a alter context request
759 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
761 struct ncacn_packet pkt;
762 struct data_blob_list_item *rep;
764 uint32_t result=0, reason=0;
767 /* handle any authentication that is being requested */
768 if (!dcesrv_auth_alter(call)) {
769 /* TODO: work out the right reject code */
770 result = DCERPC_BIND_PROVIDER_REJECT;
771 reason = DCERPC_BIND_REASON_ASYNTAX;
774 context_id = call->pkt.u.alter.ctx_list[0].context_id;
776 /* see if they are asking for a new interface */
778 dcesrv_find_context(call->conn, context_id) == NULL) {
779 status = dcesrv_alter_new_context(call, context_id);
780 if (!NT_STATUS_IS_OK(status)) {
781 result = DCERPC_BIND_PROVIDER_REJECT;
782 reason = DCERPC_BIND_REASON_ASYNTAX;
786 /* setup a alter_resp */
787 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
789 pkt.call_id = call->pkt.call_id;
790 pkt.ptype = DCERPC_PKT_ALTER_RESP;
791 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
792 pkt.u.alter_resp.max_xmit_frag = 0x2000;
793 pkt.u.alter_resp.max_recv_frag = 0x2000;
794 pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
795 pkt.u.alter_resp.num_results = 1;
796 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
797 if (!pkt.u.alter_resp.ctx_list) {
798 return NT_STATUS_NO_MEMORY;
800 pkt.u.alter_resp.ctx_list[0].result = result;
801 pkt.u.alter_resp.ctx_list[0].reason = reason;
802 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
803 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
804 pkt.u.alter_resp.secondary_address = "";
806 status = dcesrv_auth_alter_ack(call, &pkt);
807 if (!NT_STATUS_IS_OK(status)) {
808 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
809 || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
810 || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
811 || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
812 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
814 return dcesrv_fault(call, 0);
817 rep = talloc(call, struct data_blob_list_item);
819 return NT_STATUS_NO_MEMORY;
822 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
823 if (!NT_STATUS_IS_OK(status)) {
827 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
829 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
830 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
836 handle a dcerpc request packet
838 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
840 struct ndr_pull *pull;
842 struct dcesrv_connection_context *context;
844 /* if authenticated, and the mech we use can't do async replies, don't use them... */
845 if (call->conn->auth_state.gensec_security &&
846 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
847 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
850 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
851 if (context == NULL) {
852 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
855 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call,
856 lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
857 NT_STATUS_HAVE_NO_MEMORY(pull);
859 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
861 call->context = context;
862 call->ndr_pull = pull;
864 if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
865 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
868 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
869 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
872 /* unravel the NDR for the packet */
873 status = context->iface->ndr_pull(call, call, pull, &call->r);
874 if (!NT_STATUS_IS_OK(status)) {
875 return dcesrv_fault(call, call->fault_code);
878 if (pull->offset != pull->data_size) {
879 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
880 pull->data_size - pull->offset));
881 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
884 /* call the dispatch function */
885 status = context->iface->dispatch(call, call, call->r);
886 if (!NT_STATUS_IS_OK(status)) {
887 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
888 context->iface->name,
889 call->pkt.u.request.opnum,
890 dcerpc_errstr(pull, call->fault_code)));
891 return dcesrv_fault(call, call->fault_code);
894 /* add the call to the pending list */
895 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
897 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
901 return dcesrv_reply(call);
904 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
906 struct ndr_push *push;
909 uint32_t total_length, chunk_size;
910 struct dcesrv_connection_context *context = call->context;
912 /* call the reply function */
913 status = context->iface->reply(call, call, call->r);
914 if (!NT_STATUS_IS_OK(status)) {
915 return dcesrv_fault(call, call->fault_code);
918 /* form the reply NDR */
919 push = ndr_push_init_ctx(call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
920 NT_STATUS_HAVE_NO_MEMORY(push);
922 /* carry over the pointer count to the reply in case we are
923 using full pointer. See NDR specification for full
925 push->ptr_count = call->ndr_pull->ptr_count;
927 if (lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
928 push->flags |= LIBNDR_FLAG_BIGENDIAN;
931 status = context->iface->ndr_push(call, call, push, call->r);
932 if (!NT_STATUS_IS_OK(status)) {
933 return dcesrv_fault(call, call->fault_code);
936 stub = ndr_push_blob(push);
938 total_length = stub.length;
940 /* we can write a full max_recv_frag size, minus the dcerpc
941 request header size */
942 chunk_size = call->conn->cli_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
946 struct data_blob_list_item *rep;
947 struct ncacn_packet pkt;
948 const uint32_t overhead = (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
950 rep = talloc(call, struct data_blob_list_item);
951 NT_STATUS_HAVE_NO_MEMORY(rep);
953 length = MIN(chunk_size, stub.length);
955 /* form the dcerpc response packet */
956 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
958 pkt.call_id = call->pkt.call_id;
959 pkt.ptype = DCERPC_PKT_RESPONSE;
961 if (stub.length == total_length) {
962 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
964 if (length == stub.length) {
965 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
967 pkt.u.response.alloc_hint = stub.length;
968 pkt.u.response.context_id = call->pkt.u.request.context_id;
969 pkt.u.response.cancel_count = 0;
970 pkt.u.response.stub_and_verifier.data = stub.data;
971 pkt.u.response.stub_and_verifier.length = length;
973 if (!dcesrv_auth_response(call, &rep->blob, &pkt)) {
974 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
977 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
979 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
982 stub.length -= length;
983 } while (stub.length != 0);
985 /* move the call from the pending to the finished calls list */
986 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
988 if (call->conn->call_list && call->conn->call_list->replies) {
989 if (call->conn->transport.report_output_data) {
990 call->conn->transport.report_output_data(call->conn);
997 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
999 if (!conn->transport.get_my_addr) {
1003 return conn->transport.get_my_addr(conn, mem_ctx);
1006 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1008 if (!conn->transport.get_peer_addr) {
1012 return conn->transport.get_peer_addr(conn, mem_ctx);
1016 work out if we have a full packet yet
1018 static bool dce_full_packet(const DATA_BLOB *data)
1020 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
1023 if (dcerpc_get_frag_length(data) > data->length) {
1030 we might have consumed only part of our input - advance past that part
1032 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
1036 if (dce_conn->partial_input.length == offset) {
1037 data_blob_free(&dce_conn->partial_input);
1041 blob = dce_conn->partial_input;
1042 dce_conn->partial_input = data_blob(blob.data + offset,
1043 blob.length - offset);
1044 data_blob_free(&blob);
1048 remove the call from the right list when freed
1050 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1052 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1057 process some input to a dcerpc endpoint server.
1059 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
1061 struct ndr_pull *ndr;
1062 enum ndr_err_code ndr_err;
1064 struct dcesrv_call_state *call;
1067 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1069 talloc_free(dce_conn->partial_input.data);
1070 return NT_STATUS_NO_MEMORY;
1072 call->conn = dce_conn;
1073 call->event_ctx = dce_conn->event_ctx;
1074 call->msg_ctx = dce_conn->msg_ctx;
1075 call->state_flags = call->conn->state_flags;
1076 call->time = timeval_current();
1077 call->list = DCESRV_LIST_NONE;
1079 talloc_set_destructor(call, dcesrv_call_dequeue);
1081 blob = dce_conn->partial_input;
1082 blob.length = dcerpc_get_frag_length(&blob);
1084 ndr = ndr_pull_init_blob(&blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
1086 talloc_free(dce_conn->partial_input.data);
1088 return NT_STATUS_NO_MEMORY;
1091 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
1092 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
1095 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
1096 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1097 talloc_free(dce_conn->partial_input.data);
1099 return ndr_map_error2ntstatus(ndr_err);
1102 /* we have to check the signing here, before combining the
1104 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1105 !dcesrv_auth_request(call, &blob)) {
1106 dce_partial_advance(dce_conn, blob.length);
1107 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1110 dce_partial_advance(dce_conn, blob.length);
1112 /* see if this is a continued packet */
1113 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1114 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1115 struct dcesrv_call_state *call2 = call;
1116 uint32_t alloc_size;
1118 /* we only allow fragmented requests, no other packet types */
1119 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1120 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1123 /* this is a continuation of an existing call - find the call then
1124 tack it on the end */
1125 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1127 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1130 if (call->pkt.ptype != call2->pkt.ptype) {
1131 /* trying to play silly buggers are we? */
1132 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1135 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1136 call2->pkt.u.request.stub_and_verifier.length;
1137 if (call->pkt.u.request.alloc_hint > alloc_size) {
1138 alloc_size = call->pkt.u.request.alloc_hint;
1141 call->pkt.u.request.stub_and_verifier.data =
1142 talloc_realloc(call,
1143 call->pkt.u.request.stub_and_verifier.data,
1144 uint8_t, alloc_size);
1145 if (!call->pkt.u.request.stub_and_verifier.data) {
1146 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1148 memcpy(call->pkt.u.request.stub_and_verifier.data +
1149 call->pkt.u.request.stub_and_verifier.length,
1150 call2->pkt.u.request.stub_and_verifier.data,
1151 call2->pkt.u.request.stub_and_verifier.length);
1152 call->pkt.u.request.stub_and_verifier.length +=
1153 call2->pkt.u.request.stub_and_verifier.length;
1155 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1160 /* this may not be the last pdu in the chain - if its isn't then
1161 just put it on the incoming_fragmented_call_list and wait for the rest */
1162 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1163 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1164 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1165 return NT_STATUS_OK;
1168 /* This removes any fragments we may have had stashed away */
1169 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1171 switch (call->pkt.ptype) {
1172 case DCERPC_PKT_BIND:
1173 status = dcesrv_bind(call);
1175 case DCERPC_PKT_AUTH3:
1176 status = dcesrv_auth3(call);
1178 case DCERPC_PKT_ALTER:
1179 status = dcesrv_alter(call);
1181 case DCERPC_PKT_REQUEST:
1182 status = dcesrv_request(call);
1185 status = NT_STATUS_INVALID_PARAMETER;
1189 /* if we are going to be sending a reply then add
1190 it to the list of pending calls. We add it to the end to keep the call
1191 list in the order we will answer */
1192 if (!NT_STATUS_IS_OK(status)) {
1201 provide some input to a dcerpc endpoint server. This passes data
1202 from a dcerpc client into the server
1204 _PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1208 dce_conn->partial_input.data = talloc_realloc(dce_conn,
1209 dce_conn->partial_input.data,
1211 dce_conn->partial_input.length + data->length);
1212 if (!dce_conn->partial_input.data) {
1213 return NT_STATUS_NO_MEMORY;
1215 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1216 data->data, data->length);
1217 dce_conn->partial_input.length += data->length;
1219 while (dce_full_packet(&dce_conn->partial_input)) {
1220 status = dcesrv_input_process(dce_conn);
1221 if (!NT_STATUS_IS_OK(status)) {
1226 return NT_STATUS_OK;
1230 retrieve some output from a dcerpc server
1231 The caller supplies a function that will be called to do the
1234 The first argument to write_fn() will be 'private', the second will
1235 be a pointer to a buffer containing the data to be sent and the 3rd
1236 will be a pointer to a size_t variable that will be set to the
1237 number of bytes that are consumed from the output.
1239 from the current fragment
1241 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
1243 NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1246 struct dcesrv_call_state *call;
1247 struct data_blob_list_item *rep;
1250 call = dce_conn->call_list;
1251 if (!call || !call->replies) {
1252 if (dce_conn->pending_call_list) {
1253 /* TODO: we need to say act async here
1254 * as we know we have pending requests
1255 * which will be finished at a time
1257 return NT_STATUS_FOOBAR;
1259 return NT_STATUS_FOOBAR;
1261 rep = call->replies;
1263 status = write_fn(private_data, &rep->blob, &nwritten);
1264 NT_STATUS_IS_ERR_RETURN(status);
1266 rep->blob.length -= nwritten;
1267 rep->blob.data += nwritten;
1269 if (rep->blob.length == 0) {
1270 /* we're done with this section of the call */
1271 DLIST_REMOVE(call->replies, rep);
1274 if (call->replies == NULL) {
1275 /* we're done with the whole call */
1276 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1283 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1284 struct loadparm_context *lp_ctx,
1285 const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1288 struct dcesrv_context *dce_ctx;
1291 if (!endpoint_servers) {
1292 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1293 return NT_STATUS_INTERNAL_ERROR;
1296 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1297 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1298 dce_ctx->endpoint_list = NULL;
1299 dce_ctx->lp_ctx = lp_ctx;
1301 for (i=0;endpoint_servers[i];i++) {
1302 const struct dcesrv_endpoint_server *ep_server;
1304 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1306 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1307 return NT_STATUS_INTERNAL_ERROR;
1310 status = ep_server->init_server(dce_ctx, ep_server);
1311 if (!NT_STATUS_IS_OK(status)) {
1312 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1313 nt_errstr(status)));
1318 *_dce_ctx = dce_ctx;
1319 return NT_STATUS_OK;
1322 /* the list of currently registered DCERPC endpoint servers.
1324 static struct ep_server {
1325 struct dcesrv_endpoint_server *ep_server;
1326 } *ep_servers = NULL;
1327 static int num_ep_servers;
1330 register a DCERPC endpoint server.
1332 The 'name' can be later used by other backends to find the operations
1333 structure for this backend.
1335 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1337 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1339 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1341 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1342 /* its already registered! */
1343 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1345 return NT_STATUS_OBJECT_NAME_COLLISION;
1348 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1350 smb_panic("out of memory in dcerpc_register");
1353 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1354 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1358 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1361 return NT_STATUS_OK;
1365 return the operations structure for a named backend of the specified type
1367 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1371 for (i=0;i<num_ep_servers;i++) {
1372 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1373 return ep_servers[i].ep_server;
1381 return the DCERPC module version, and the size of some critical types
1382 This can be used by endpoint server modules to either detect compilation errors, or provide
1383 multiple implementations for different smbd compilation options in one module
1385 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1387 static const struct dcesrv_critical_sizes critical_sizes = {
1388 DCERPC_MODULE_VERSION,
1389 sizeof(struct dcesrv_context),
1390 sizeof(struct dcesrv_endpoint),
1391 sizeof(struct dcesrv_endpoint_server),
1392 sizeof(struct dcesrv_interface),
1393 sizeof(struct dcesrv_if_list),
1394 sizeof(struct dcesrv_connection),
1395 sizeof(struct dcesrv_call_state),
1396 sizeof(struct dcesrv_auth),
1397 sizeof(struct dcesrv_handle)
1400 return &critical_sizes;
1404 initialise the dcerpc server context for ncacn_np based services
1406 _PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
1407 struct dcesrv_context **_dce_ctx)
1410 struct dcesrv_context *dce_ctx;
1412 status = dcesrv_init_context(mem_ctx, lp_ctx, lp_dcerpc_endpoint_servers(lp_ctx), &dce_ctx);
1413 NT_STATUS_NOT_OK_RETURN(status);
1415 *_dce_ctx = dce_ctx;
1416 return NT_STATUS_OK;