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;
546 if (call->pkt.u.bind.assoc_group_id != 0) {
547 return dcesrv_bind_nak(call, 0);
550 if (call->pkt.u.bind.num_contexts < 1 ||
551 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
552 return dcesrv_bind_nak(call, 0);
555 context_id = call->pkt.u.bind.ctx_list[0].context_id;
557 /* you can't bind twice on one context */
558 if (dcesrv_find_context(call->conn, context_id) != NULL) {
559 return dcesrv_bind_nak(call, 0);
562 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
563 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
565 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
566 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
567 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
568 ndr_transfer_syntax.if_version != transfer_syntax_version) {
569 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
570 /* we only do NDR encoded dcerpc */
571 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
572 talloc_free(uuid_str);
573 return dcesrv_bind_nak(call, 0);
576 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
578 char *uuid_str = GUID_string(call, &uuid);
579 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
580 talloc_free(uuid_str);
582 /* we don't know about that interface */
583 result = DCERPC_BIND_PROVIDER_REJECT;
584 reason = DCERPC_BIND_REASON_ASYNTAX;
588 /* add this context to the list of available context_ids */
589 struct dcesrv_connection_context *context = talloc(call->conn,
590 struct dcesrv_connection_context);
591 if (context == NULL) {
592 return dcesrv_bind_nak(call, 0);
594 context->conn = call->conn;
595 context->iface = iface;
596 context->context_id = context_id;
597 context->private = NULL;
598 context->handles = NULL;
599 DLIST_ADD(call->conn->contexts, context);
600 call->context = context;
603 if (call->conn->cli_max_recv_frag == 0) {
604 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
607 /* handle any authentication that is being requested */
608 if (!dcesrv_auth_bind(call)) {
609 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
612 /* setup a bind_ack */
613 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
615 pkt.call_id = call->pkt.call_id;
616 pkt.ptype = DCERPC_PKT_BIND_ACK;
617 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
618 pkt.u.bind_ack.max_xmit_frag = 0x2000;
619 pkt.u.bind_ack.max_recv_frag = 0x2000;
620 /* we need to send a non zero assoc_group_id here to make longhorn happy, it also matches samba3 */
621 pkt.u.bind_ack.assoc_group_id = 0x12345678;
623 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
624 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
626 pkt.u.bind_ack.secondary_address = "";
628 pkt.u.bind_ack.num_results = 1;
629 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
630 if (!pkt.u.bind_ack.ctx_list) {
631 return NT_STATUS_NO_MEMORY;
633 pkt.u.bind_ack.ctx_list[0].result = result;
634 pkt.u.bind_ack.ctx_list[0].reason = reason;
635 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
636 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
638 status = dcesrv_auth_bind_ack(call, &pkt);
639 if (!NT_STATUS_IS_OK(status)) {
640 return dcesrv_bind_nak(call, 0);
644 status = iface->bind(call, iface);
645 if (!NT_STATUS_IS_OK(status)) {
646 char *uuid_str = GUID_string(call, &uuid);
647 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
648 uuid_str, if_version, nt_errstr(status)));
649 talloc_free(uuid_str);
650 return dcesrv_bind_nak(call, 0);
654 rep = talloc(call, struct data_blob_list_item);
656 return NT_STATUS_NO_MEMORY;
659 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
660 if (!NT_STATUS_IS_OK(status)) {
664 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
666 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
667 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
674 handle a auth3 request
676 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
678 /* handle the auth3 in the auth code */
679 if (!dcesrv_auth_auth3(call)) {
680 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
685 /* we don't send a reply to a auth3 request, except by a
692 handle a bind request
694 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
696 uint32_t if_version, transfer_syntax_version;
697 struct dcesrv_connection_context *context;
698 const struct dcesrv_interface *iface;
699 struct GUID uuid, *transfer_syntax_uuid;
702 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
703 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
705 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
706 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
707 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
708 ndr_transfer_syntax.if_version != transfer_syntax_version) {
709 /* we only do NDR encoded dcerpc */
710 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
713 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
715 char *uuid_str = GUID_string(call, &uuid);
716 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
717 talloc_free(uuid_str);
718 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
721 /* add this context to the list of available context_ids */
722 context = talloc(call->conn, struct dcesrv_connection_context);
723 if (context == NULL) {
724 return NT_STATUS_NO_MEMORY;
726 context->conn = call->conn;
727 context->iface = iface;
728 context->context_id = context_id;
729 context->private = NULL;
730 context->handles = NULL;
731 DLIST_ADD(call->conn->contexts, context);
732 call->context = context;
735 status = iface->bind(call, iface);
736 if (!NT_STATUS_IS_OK(status)) {
746 handle a alter context request
748 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
750 struct ncacn_packet pkt;
751 struct data_blob_list_item *rep;
753 uint32_t result=0, reason=0;
756 /* handle any authentication that is being requested */
757 if (!dcesrv_auth_alter(call)) {
758 /* TODO: work out the right reject code */
759 result = DCERPC_BIND_PROVIDER_REJECT;
760 reason = DCERPC_BIND_REASON_ASYNTAX;
763 context_id = call->pkt.u.alter.ctx_list[0].context_id;
765 /* see if they are asking for a new interface */
767 dcesrv_find_context(call->conn, context_id) == NULL) {
768 status = dcesrv_alter_new_context(call, context_id);
769 if (!NT_STATUS_IS_OK(status)) {
770 result = DCERPC_BIND_PROVIDER_REJECT;
771 reason = DCERPC_BIND_REASON_ASYNTAX;
775 /* setup a alter_resp */
776 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
778 pkt.call_id = call->pkt.call_id;
779 pkt.ptype = DCERPC_PKT_ALTER_RESP;
780 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
781 pkt.u.alter_resp.max_xmit_frag = 0x2000;
782 pkt.u.alter_resp.max_recv_frag = 0x2000;
783 pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
784 pkt.u.alter_resp.num_results = 1;
785 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
786 if (!pkt.u.alter_resp.ctx_list) {
787 return NT_STATUS_NO_MEMORY;
789 pkt.u.alter_resp.ctx_list[0].result = result;
790 pkt.u.alter_resp.ctx_list[0].reason = reason;
791 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
792 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
793 pkt.u.alter_resp.secondary_address = "";
795 status = dcesrv_auth_alter_ack(call, &pkt);
796 if (!NT_STATUS_IS_OK(status)) {
797 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
798 || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
799 || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
800 || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
801 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
803 return dcesrv_fault(call, 0);
806 rep = talloc(call, struct data_blob_list_item);
808 return NT_STATUS_NO_MEMORY;
811 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
812 if (!NT_STATUS_IS_OK(status)) {
816 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
818 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
819 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
825 handle a dcerpc request packet
827 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
829 struct ndr_pull *pull;
831 struct dcesrv_connection_context *context;
833 /* if authenticated, and the mech we use can't do async replies, don't use them... */
834 if (call->conn->auth_state.gensec_security &&
835 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
836 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
839 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
840 if (context == NULL) {
841 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
844 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call,
845 lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
846 NT_STATUS_HAVE_NO_MEMORY(pull);
848 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
850 call->context = context;
851 call->ndr_pull = pull;
853 if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
854 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
857 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
858 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
861 /* unravel the NDR for the packet */
862 status = context->iface->ndr_pull(call, call, pull, &call->r);
863 if (!NT_STATUS_IS_OK(status)) {
864 return dcesrv_fault(call, call->fault_code);
867 if (pull->offset != pull->data_size) {
868 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
869 pull->data_size - pull->offset));
870 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
873 /* call the dispatch function */
874 status = context->iface->dispatch(call, call, call->r);
875 if (!NT_STATUS_IS_OK(status)) {
876 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
877 context->iface->name,
878 call->pkt.u.request.opnum,
879 dcerpc_errstr(pull, call->fault_code)));
880 return dcesrv_fault(call, call->fault_code);
883 /* add the call to the pending list */
884 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
886 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
890 return dcesrv_reply(call);
893 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
895 struct ndr_push *push;
898 uint32_t total_length, chunk_size;
899 struct dcesrv_connection_context *context = call->context;
901 /* call the reply function */
902 status = context->iface->reply(call, call, call->r);
903 if (!NT_STATUS_IS_OK(status)) {
904 return dcesrv_fault(call, call->fault_code);
907 /* form the reply NDR */
908 push = ndr_push_init_ctx(call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
909 NT_STATUS_HAVE_NO_MEMORY(push);
911 /* carry over the pointer count to the reply in case we are
912 using full pointer. See NDR specification for full
914 push->ptr_count = call->ndr_pull->ptr_count;
916 if (lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
917 push->flags |= LIBNDR_FLAG_BIGENDIAN;
920 status = context->iface->ndr_push(call, call, push, call->r);
921 if (!NT_STATUS_IS_OK(status)) {
922 return dcesrv_fault(call, call->fault_code);
925 stub = ndr_push_blob(push);
927 total_length = stub.length;
929 /* we can write a full max_recv_frag size, minus the dcerpc
930 request header size */
931 chunk_size = call->conn->cli_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
935 struct data_blob_list_item *rep;
936 struct ncacn_packet pkt;
937 const uint32_t overhead = (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
939 rep = talloc(call, struct data_blob_list_item);
940 NT_STATUS_HAVE_NO_MEMORY(rep);
942 length = MIN(chunk_size, stub.length);
944 /* form the dcerpc response packet */
945 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
947 pkt.call_id = call->pkt.call_id;
948 pkt.ptype = DCERPC_PKT_RESPONSE;
950 if (stub.length == total_length) {
951 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
953 if (length == stub.length) {
954 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
956 pkt.u.response.alloc_hint = stub.length;
957 pkt.u.response.context_id = call->pkt.u.request.context_id;
958 pkt.u.response.cancel_count = 0;
959 pkt.u.response.stub_and_verifier.data = stub.data;
960 pkt.u.response.stub_and_verifier.length = length;
962 if (!dcesrv_auth_response(call, &rep->blob, &pkt)) {
963 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
966 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
968 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
971 stub.length -= length;
972 } while (stub.length != 0);
974 /* move the call from the pending to the finished calls list */
975 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
977 if (call->conn->call_list && call->conn->call_list->replies) {
978 if (call->conn->transport.report_output_data) {
979 call->conn->transport.report_output_data(call->conn);
986 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
988 if (!conn->transport.get_my_addr) {
992 return conn->transport.get_my_addr(conn, mem_ctx);
995 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
997 if (!conn->transport.get_peer_addr) {
1001 return conn->transport.get_peer_addr(conn, mem_ctx);
1005 work out if we have a full packet yet
1007 static bool dce_full_packet(const DATA_BLOB *data)
1009 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
1012 if (dcerpc_get_frag_length(data) > data->length) {
1019 we might have consumed only part of our input - advance past that part
1021 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
1025 if (dce_conn->partial_input.length == offset) {
1026 data_blob_free(&dce_conn->partial_input);
1030 blob = dce_conn->partial_input;
1031 dce_conn->partial_input = data_blob(blob.data + offset,
1032 blob.length - offset);
1033 data_blob_free(&blob);
1037 remove the call from the right list when freed
1039 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1041 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1046 process some input to a dcerpc endpoint server.
1048 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
1050 struct ndr_pull *ndr;
1051 enum ndr_err_code ndr_err;
1053 struct dcesrv_call_state *call;
1056 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1058 talloc_free(dce_conn->partial_input.data);
1059 return NT_STATUS_NO_MEMORY;
1061 call->conn = dce_conn;
1062 call->event_ctx = dce_conn->event_ctx;
1063 call->msg_ctx = dce_conn->msg_ctx;
1064 call->state_flags = call->conn->state_flags;
1065 call->time = timeval_current();
1066 call->list = DCESRV_LIST_NONE;
1068 talloc_set_destructor(call, dcesrv_call_dequeue);
1070 blob = dce_conn->partial_input;
1071 blob.length = dcerpc_get_frag_length(&blob);
1073 ndr = ndr_pull_init_blob(&blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
1075 talloc_free(dce_conn->partial_input.data);
1077 return NT_STATUS_NO_MEMORY;
1080 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
1081 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
1084 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
1085 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1086 talloc_free(dce_conn->partial_input.data);
1088 return ndr_map_error2ntstatus(ndr_err);
1091 /* we have to check the signing here, before combining the
1093 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1094 !dcesrv_auth_request(call, &blob)) {
1095 dce_partial_advance(dce_conn, blob.length);
1096 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1099 dce_partial_advance(dce_conn, blob.length);
1101 /* see if this is a continued packet */
1102 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1103 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1104 struct dcesrv_call_state *call2 = call;
1105 uint32_t alloc_size;
1107 /* we only allow fragmented requests, no other packet types */
1108 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1109 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1112 /* this is a continuation of an existing call - find the call then
1113 tack it on the end */
1114 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1116 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1119 if (call->pkt.ptype != call2->pkt.ptype) {
1120 /* trying to play silly buggers are we? */
1121 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1124 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1125 call2->pkt.u.request.stub_and_verifier.length;
1126 if (call->pkt.u.request.alloc_hint > alloc_size) {
1127 alloc_size = call->pkt.u.request.alloc_hint;
1130 call->pkt.u.request.stub_and_verifier.data =
1131 talloc_realloc(call,
1132 call->pkt.u.request.stub_and_verifier.data,
1133 uint8_t, alloc_size);
1134 if (!call->pkt.u.request.stub_and_verifier.data) {
1135 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1137 memcpy(call->pkt.u.request.stub_and_verifier.data +
1138 call->pkt.u.request.stub_and_verifier.length,
1139 call2->pkt.u.request.stub_and_verifier.data,
1140 call2->pkt.u.request.stub_and_verifier.length);
1141 call->pkt.u.request.stub_and_verifier.length +=
1142 call2->pkt.u.request.stub_and_verifier.length;
1144 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1149 /* this may not be the last pdu in the chain - if its isn't then
1150 just put it on the incoming_fragmented_call_list and wait for the rest */
1151 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1152 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1153 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1154 return NT_STATUS_OK;
1157 /* This removes any fragments we may have had stashed away */
1158 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1160 switch (call->pkt.ptype) {
1161 case DCERPC_PKT_BIND:
1162 status = dcesrv_bind(call);
1164 case DCERPC_PKT_AUTH3:
1165 status = dcesrv_auth3(call);
1167 case DCERPC_PKT_ALTER:
1168 status = dcesrv_alter(call);
1170 case DCERPC_PKT_REQUEST:
1171 status = dcesrv_request(call);
1174 status = NT_STATUS_INVALID_PARAMETER;
1178 /* if we are going to be sending a reply then add
1179 it to the list of pending calls. We add it to the end to keep the call
1180 list in the order we will answer */
1181 if (!NT_STATUS_IS_OK(status)) {
1190 provide some input to a dcerpc endpoint server. This passes data
1191 from a dcerpc client into the server
1193 _PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1197 dce_conn->partial_input.data = talloc_realloc(dce_conn,
1198 dce_conn->partial_input.data,
1200 dce_conn->partial_input.length + data->length);
1201 if (!dce_conn->partial_input.data) {
1202 return NT_STATUS_NO_MEMORY;
1204 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1205 data->data, data->length);
1206 dce_conn->partial_input.length += data->length;
1208 while (dce_full_packet(&dce_conn->partial_input)) {
1209 status = dcesrv_input_process(dce_conn);
1210 if (!NT_STATUS_IS_OK(status)) {
1215 return NT_STATUS_OK;
1219 retrieve some output from a dcerpc server
1220 The caller supplies a function that will be called to do the
1223 The first argument to write_fn() will be 'private', the second will
1224 be a pointer to a buffer containing the data to be sent and the 3rd
1225 will be a pointer to a size_t variable that will be set to the
1226 number of bytes that are consumed from the output.
1228 from the current fragment
1230 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
1232 NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1235 struct dcesrv_call_state *call;
1236 struct data_blob_list_item *rep;
1239 call = dce_conn->call_list;
1240 if (!call || !call->replies) {
1241 if (dce_conn->pending_call_list) {
1242 /* TODO: we need to say act async here
1243 * as we know we have pending requests
1244 * which will be finished at a time
1246 return NT_STATUS_FOOBAR;
1248 return NT_STATUS_FOOBAR;
1250 rep = call->replies;
1252 status = write_fn(private_data, &rep->blob, &nwritten);
1253 NT_STATUS_IS_ERR_RETURN(status);
1255 rep->blob.length -= nwritten;
1256 rep->blob.data += nwritten;
1258 if (rep->blob.length == 0) {
1259 /* we're done with this section of the call */
1260 DLIST_REMOVE(call->replies, rep);
1263 if (call->replies == NULL) {
1264 /* we're done with the whole call */
1265 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1272 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1273 struct loadparm_context *lp_ctx,
1274 const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1277 struct dcesrv_context *dce_ctx;
1280 if (!endpoint_servers) {
1281 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1282 return NT_STATUS_INTERNAL_ERROR;
1285 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1286 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1287 dce_ctx->endpoint_list = NULL;
1288 dce_ctx->lp_ctx = lp_ctx;
1290 for (i=0;endpoint_servers[i];i++) {
1291 const struct dcesrv_endpoint_server *ep_server;
1293 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1295 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1296 return NT_STATUS_INTERNAL_ERROR;
1299 status = ep_server->init_server(dce_ctx, ep_server);
1300 if (!NT_STATUS_IS_OK(status)) {
1301 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1302 nt_errstr(status)));
1307 *_dce_ctx = dce_ctx;
1308 return NT_STATUS_OK;
1311 /* the list of currently registered DCERPC endpoint servers.
1313 static struct ep_server {
1314 struct dcesrv_endpoint_server *ep_server;
1315 } *ep_servers = NULL;
1316 static int num_ep_servers;
1319 register a DCERPC endpoint server.
1321 The 'name' can be later used by other backends to find the operations
1322 structure for this backend.
1324 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1326 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1328 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1330 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1331 /* its already registered! */
1332 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1334 return NT_STATUS_OBJECT_NAME_COLLISION;
1337 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1339 smb_panic("out of memory in dcerpc_register");
1342 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1343 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1347 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1350 return NT_STATUS_OK;
1354 return the operations structure for a named backend of the specified type
1356 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1360 for (i=0;i<num_ep_servers;i++) {
1361 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1362 return ep_servers[i].ep_server;
1370 return the DCERPC module version, and the size of some critical types
1371 This can be used by endpoint server modules to either detect compilation errors, or provide
1372 multiple implementations for different smbd compilation options in one module
1374 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1376 static const struct dcesrv_critical_sizes critical_sizes = {
1377 DCERPC_MODULE_VERSION,
1378 sizeof(struct dcesrv_context),
1379 sizeof(struct dcesrv_endpoint),
1380 sizeof(struct dcesrv_endpoint_server),
1381 sizeof(struct dcesrv_interface),
1382 sizeof(struct dcesrv_if_list),
1383 sizeof(struct dcesrv_connection),
1384 sizeof(struct dcesrv_call_state),
1385 sizeof(struct dcesrv_auth),
1386 sizeof(struct dcesrv_handle)
1389 return &critical_sizes;
1393 initialise the dcerpc server context for ncacn_np based services
1395 _PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
1396 struct dcesrv_context **_dce_ctx)
1399 struct dcesrv_context *dce_ctx;
1401 status = dcesrv_init_context(mem_ctx, lp_ctx, lp_dcerpc_endpoint_servers(lp_ctx), &dce_ctx);
1402 NT_STATUS_NOT_OK_RETURN(status);
1404 *_dce_ctx = dce_ctx;
1405 return NT_STATUS_OK;