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 _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
275 DATA_BLOB *session_key)
277 return p->auth_state.session_key(p, session_key);
282 destroy a link to an endpoint
284 static int dcesrv_endpoint_destructor(struct dcesrv_connection *p)
286 while (p->contexts) {
287 struct dcesrv_connection_context *c = p->contexts;
289 DLIST_REMOVE(p->contexts, c);
292 c->iface->unbind(c, c->iface);
301 connect to a dcerpc endpoint
303 _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
305 const struct dcesrv_endpoint *ep,
306 struct auth_session_info *session_info,
307 struct event_context *event_ctx,
308 struct messaging_context *msg_ctx,
309 struct server_id server_id,
310 uint32_t state_flags,
311 struct dcesrv_connection **_p)
313 struct dcesrv_connection *p;
316 return NT_STATUS_ACCESS_DENIED;
319 p = talloc(mem_ctx, struct dcesrv_connection);
320 NT_STATUS_HAVE_NO_MEMORY(p);
322 if (!talloc_reference(p, session_info)) {
324 return NT_STATUS_NO_MEMORY;
327 p->dce_ctx = dce_ctx;
331 p->incoming_fragmented_call_list = NULL;
332 p->pending_call_list = NULL;
333 p->cli_max_recv_frag = 0;
334 p->partial_input = data_blob(NULL, 0);
335 p->auth_state.auth_info = NULL;
336 p->auth_state.gensec_security = NULL;
337 p->auth_state.session_info = session_info;
338 p->auth_state.session_key = dcesrv_generic_session_key;
339 p->event_ctx = event_ctx;
340 p->msg_ctx = msg_ctx;
341 p->server_id = server_id;
342 p->processing = false;
343 p->state_flags = state_flags;
344 ZERO_STRUCT(p->transport);
346 talloc_set_destructor(p, dcesrv_endpoint_destructor);
353 search and connect to a dcerpc endpoint
355 _PUBLIC_ NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
357 const struct dcerpc_binding *ep_description,
358 struct auth_session_info *session_info,
359 struct event_context *event_ctx,
360 struct messaging_context *msg_ctx,
361 struct server_id server_id,
362 uint32_t state_flags,
363 struct dcesrv_connection **dce_conn_p)
366 const struct dcesrv_endpoint *ep;
368 /* make sure this endpoint exists */
369 ep = find_endpoint(dce_ctx, ep_description);
371 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
374 status = dcesrv_endpoint_connect(dce_ctx, mem_ctx, ep, session_info,
375 event_ctx, msg_ctx, server_id,
376 state_flags, dce_conn_p);
377 NT_STATUS_NOT_OK_RETURN(status);
379 (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
381 /* TODO: check security descriptor of the endpoint here
382 * if it's a smb named pipe
383 * if it's failed free dce_conn_p
390 static void dcesrv_init_hdr(struct ncacn_packet *pkt, bool bigendian)
393 pkt->rpc_vers_minor = 0;
397 pkt->drep[0] = DCERPC_DREP_LE;
405 move a call from an existing linked list to the specified list. This
406 prevents bugs where we forget to remove the call from a previous
409 static void dcesrv_call_set_list(struct dcesrv_call_state *call,
410 enum dcesrv_call_list list)
412 switch (call->list) {
413 case DCESRV_LIST_NONE:
415 case DCESRV_LIST_CALL_LIST:
416 DLIST_REMOVE(call->conn->call_list, call);
418 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
419 DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
421 case DCESRV_LIST_PENDING_CALL_LIST:
422 DLIST_REMOVE(call->conn->pending_call_list, call);
427 case DCESRV_LIST_NONE:
429 case DCESRV_LIST_CALL_LIST:
430 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
432 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
433 DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
435 case DCESRV_LIST_PENDING_CALL_LIST:
436 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
442 return a dcerpc fault
444 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
446 struct ncacn_packet pkt;
447 struct data_blob_list_item *rep;
451 /* setup a bind_ack */
452 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
454 pkt.call_id = call->pkt.call_id;
455 pkt.ptype = DCERPC_PKT_FAULT;
456 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
457 pkt.u.fault.alloc_hint = 0;
458 pkt.u.fault.context_id = 0;
459 pkt.u.fault.cancel_count = 0;
460 pkt.u.fault.status = fault_code;
463 pkt.u.fault._pad = data_blob_const(zeros, sizeof(zeros));
465 rep = talloc(call, struct data_blob_list_item);
467 return NT_STATUS_NO_MEMORY;
470 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
471 if (!NT_STATUS_IS_OK(status)) {
475 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
477 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
478 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
485 return a dcerpc bind_nak
487 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
489 struct ncacn_packet pkt;
490 struct data_blob_list_item *rep;
493 /* setup a bind_nak */
494 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
496 pkt.call_id = call->pkt.call_id;
497 pkt.ptype = DCERPC_PKT_BIND_NAK;
498 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
499 pkt.u.bind_nak.reject_reason = reason;
500 if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
501 pkt.u.bind_nak.versions.v.num_versions = 0;
504 rep = talloc(call, struct data_blob_list_item);
506 return NT_STATUS_NO_MEMORY;
509 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
510 if (!NT_STATUS_IS_OK(status)) {
514 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
516 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
517 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
524 handle a bind request
526 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
528 uint32_t if_version, transfer_syntax_version;
529 struct GUID uuid, *transfer_syntax_uuid;
530 struct ncacn_packet pkt;
531 struct data_blob_list_item *rep;
533 uint32_t result=0, reason=0;
535 const struct dcesrv_interface *iface;
538 /* It is not safe to enable this check - windows clients
539 * (WinXP in particular) will use it for NETLOGON calls, for
540 * the subsequent SCHANNEL bind. It turns out that NETLOGON
541 * calls include no policy handles, so it is safe there. Let
542 * the failure occour on the attempt to reuse a poilcy handle,
543 * rather than here */
545 /* Association groups allow policy handles to be shared across
546 * multiple client connections. We don't implement this yet. */
547 if (call->pkt.u.bind.assoc_group_id != 0) {
548 return dcesrv_bind_nak(call, 0);
552 if (call->pkt.u.bind.num_contexts < 1 ||
553 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
554 return dcesrv_bind_nak(call, 0);
557 context_id = call->pkt.u.bind.ctx_list[0].context_id;
559 /* you can't bind twice on one context */
560 if (dcesrv_find_context(call->conn, context_id) != NULL) {
561 return dcesrv_bind_nak(call, 0);
564 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
565 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
567 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
568 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
569 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
570 ndr_transfer_syntax.if_version != transfer_syntax_version) {
571 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
572 /* we only do NDR encoded dcerpc */
573 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
574 talloc_free(uuid_str);
575 return dcesrv_bind_nak(call, 0);
578 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
580 char *uuid_str = GUID_string(call, &uuid);
581 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
582 talloc_free(uuid_str);
584 /* we don't know about that interface */
585 result = DCERPC_BIND_PROVIDER_REJECT;
586 reason = DCERPC_BIND_REASON_ASYNTAX;
590 /* add this context to the list of available context_ids */
591 struct dcesrv_connection_context *context = talloc(call->conn,
592 struct dcesrv_connection_context);
593 if (context == NULL) {
594 return dcesrv_bind_nak(call, 0);
596 context->conn = call->conn;
597 context->iface = iface;
598 context->context_id = context_id;
599 context->private = NULL;
600 context->handles = NULL;
601 DLIST_ADD(call->conn->contexts, context);
602 call->context = context;
605 if (call->conn->cli_max_recv_frag == 0) {
606 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
609 /* handle any authentication that is being requested */
610 if (!dcesrv_auth_bind(call)) {
611 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
614 /* setup a bind_ack */
615 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
617 pkt.call_id = call->pkt.call_id;
618 pkt.ptype = DCERPC_PKT_BIND_ACK;
619 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
620 pkt.u.bind_ack.max_xmit_frag = 0x2000;
621 pkt.u.bind_ack.max_recv_frag = 0x2000;
622 /* we need to send a non zero assoc_group_id here to make longhorn happy, it also matches samba3 */
623 pkt.u.bind_ack.assoc_group_id = 0x12345678;
625 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
626 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
628 pkt.u.bind_ack.secondary_address = "";
630 pkt.u.bind_ack.num_results = 1;
631 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
632 if (!pkt.u.bind_ack.ctx_list) {
633 return NT_STATUS_NO_MEMORY;
635 pkt.u.bind_ack.ctx_list[0].result = result;
636 pkt.u.bind_ack.ctx_list[0].reason = reason;
637 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
638 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
640 status = dcesrv_auth_bind_ack(call, &pkt);
641 if (!NT_STATUS_IS_OK(status)) {
642 return dcesrv_bind_nak(call, 0);
646 status = iface->bind(call, iface);
647 if (!NT_STATUS_IS_OK(status)) {
648 char *uuid_str = GUID_string(call, &uuid);
649 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
650 uuid_str, if_version, nt_errstr(status)));
651 talloc_free(uuid_str);
652 return dcesrv_bind_nak(call, 0);
656 rep = talloc(call, struct data_blob_list_item);
658 return NT_STATUS_NO_MEMORY;
661 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
662 if (!NT_STATUS_IS_OK(status)) {
666 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
668 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
669 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
676 handle a auth3 request
678 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
680 /* handle the auth3 in the auth code */
681 if (!dcesrv_auth_auth3(call)) {
682 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
687 /* we don't send a reply to a auth3 request, except by a
694 handle a bind request
696 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
698 uint32_t if_version, transfer_syntax_version;
699 struct dcesrv_connection_context *context;
700 const struct dcesrv_interface *iface;
701 struct GUID uuid, *transfer_syntax_uuid;
704 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
705 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
707 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
708 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
709 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
710 ndr_transfer_syntax.if_version != transfer_syntax_version) {
711 /* we only do NDR encoded dcerpc */
712 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
715 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
717 char *uuid_str = GUID_string(call, &uuid);
718 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
719 talloc_free(uuid_str);
720 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
723 /* add this context to the list of available context_ids */
724 context = talloc(call->conn, struct dcesrv_connection_context);
725 if (context == NULL) {
726 return NT_STATUS_NO_MEMORY;
728 context->conn = call->conn;
729 context->iface = iface;
730 context->context_id = context_id;
731 context->private = NULL;
732 context->handles = NULL;
733 DLIST_ADD(call->conn->contexts, context);
734 call->context = context;
737 status = iface->bind(call, iface);
738 if (!NT_STATUS_IS_OK(status)) {
748 handle a alter context request
750 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
752 struct ncacn_packet pkt;
753 struct data_blob_list_item *rep;
755 uint32_t result=0, reason=0;
758 /* handle any authentication that is being requested */
759 if (!dcesrv_auth_alter(call)) {
760 /* TODO: work out the right reject code */
761 result = DCERPC_BIND_PROVIDER_REJECT;
762 reason = DCERPC_BIND_REASON_ASYNTAX;
765 context_id = call->pkt.u.alter.ctx_list[0].context_id;
767 /* see if they are asking for a new interface */
769 dcesrv_find_context(call->conn, context_id) == NULL) {
770 status = dcesrv_alter_new_context(call, context_id);
771 if (!NT_STATUS_IS_OK(status)) {
772 result = DCERPC_BIND_PROVIDER_REJECT;
773 reason = DCERPC_BIND_REASON_ASYNTAX;
777 /* setup a alter_resp */
778 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
780 pkt.call_id = call->pkt.call_id;
781 pkt.ptype = DCERPC_PKT_ALTER_RESP;
782 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
783 pkt.u.alter_resp.max_xmit_frag = 0x2000;
784 pkt.u.alter_resp.max_recv_frag = 0x2000;
785 pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
786 pkt.u.alter_resp.num_results = 1;
787 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
788 if (!pkt.u.alter_resp.ctx_list) {
789 return NT_STATUS_NO_MEMORY;
791 pkt.u.alter_resp.ctx_list[0].result = result;
792 pkt.u.alter_resp.ctx_list[0].reason = reason;
793 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
794 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
795 pkt.u.alter_resp.secondary_address = "";
797 status = dcesrv_auth_alter_ack(call, &pkt);
798 if (!NT_STATUS_IS_OK(status)) {
799 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
800 || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
801 || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
802 || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
803 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
805 return dcesrv_fault(call, 0);
808 rep = talloc(call, struct data_blob_list_item);
810 return NT_STATUS_NO_MEMORY;
813 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
814 if (!NT_STATUS_IS_OK(status)) {
818 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
820 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
821 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
827 handle a dcerpc request packet
829 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
831 struct ndr_pull *pull;
833 struct dcesrv_connection_context *context;
835 /* if authenticated, and the mech we use can't do async replies, don't use them... */
836 if (call->conn->auth_state.gensec_security &&
837 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
838 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
841 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
842 if (context == NULL) {
843 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
846 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call,
847 lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
848 NT_STATUS_HAVE_NO_MEMORY(pull);
850 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
852 call->context = context;
853 call->ndr_pull = pull;
855 if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
856 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
859 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
860 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
863 /* unravel the NDR for the packet */
864 status = context->iface->ndr_pull(call, call, pull, &call->r);
865 if (!NT_STATUS_IS_OK(status)) {
866 return dcesrv_fault(call, call->fault_code);
869 if (pull->offset != pull->data_size) {
870 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
871 pull->data_size - pull->offset));
872 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
875 /* call the dispatch function */
876 status = context->iface->dispatch(call, call, call->r);
877 if (!NT_STATUS_IS_OK(status)) {
878 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
879 context->iface->name,
880 call->pkt.u.request.opnum,
881 dcerpc_errstr(pull, call->fault_code)));
882 return dcesrv_fault(call, call->fault_code);
885 /* add the call to the pending list */
886 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
888 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
892 return dcesrv_reply(call);
895 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
897 struct ndr_push *push;
900 uint32_t total_length, chunk_size;
901 struct dcesrv_connection_context *context = call->context;
903 /* call the reply function */
904 status = context->iface->reply(call, call, call->r);
905 if (!NT_STATUS_IS_OK(status)) {
906 return dcesrv_fault(call, call->fault_code);
909 /* form the reply NDR */
910 push = ndr_push_init_ctx(call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
911 NT_STATUS_HAVE_NO_MEMORY(push);
913 /* carry over the pointer count to the reply in case we are
914 using full pointer. See NDR specification for full
916 push->ptr_count = call->ndr_pull->ptr_count;
918 if (lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
919 push->flags |= LIBNDR_FLAG_BIGENDIAN;
922 status = context->iface->ndr_push(call, call, push, call->r);
923 if (!NT_STATUS_IS_OK(status)) {
924 return dcesrv_fault(call, call->fault_code);
927 stub = ndr_push_blob(push);
929 total_length = stub.length;
931 /* we can write a full max_recv_frag size, minus the dcerpc
932 request header size */
933 chunk_size = call->conn->cli_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
937 struct data_blob_list_item *rep;
938 struct ncacn_packet pkt;
939 const uint32_t overhead = (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
941 rep = talloc(call, struct data_blob_list_item);
942 NT_STATUS_HAVE_NO_MEMORY(rep);
944 length = MIN(chunk_size, stub.length);
946 /* form the dcerpc response packet */
947 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
949 pkt.call_id = call->pkt.call_id;
950 pkt.ptype = DCERPC_PKT_RESPONSE;
952 if (stub.length == total_length) {
953 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
955 if (length == stub.length) {
956 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
958 pkt.u.response.alloc_hint = stub.length;
959 pkt.u.response.context_id = call->pkt.u.request.context_id;
960 pkt.u.response.cancel_count = 0;
961 pkt.u.response.stub_and_verifier.data = stub.data;
962 pkt.u.response.stub_and_verifier.length = length;
964 if (!dcesrv_auth_response(call, &rep->blob, &pkt)) {
965 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
968 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
970 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
973 stub.length -= length;
974 } while (stub.length != 0);
976 /* move the call from the pending to the finished calls list */
977 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
979 if (call->conn->call_list && call->conn->call_list->replies) {
980 if (call->conn->transport.report_output_data) {
981 call->conn->transport.report_output_data(call->conn);
988 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
990 if (!conn->transport.get_my_addr) {
994 return conn->transport.get_my_addr(conn, mem_ctx);
997 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
999 if (!conn->transport.get_peer_addr) {
1003 return conn->transport.get_peer_addr(conn, mem_ctx);
1007 work out if we have a full packet yet
1009 static bool dce_full_packet(const DATA_BLOB *data)
1011 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
1014 if (dcerpc_get_frag_length(data) > data->length) {
1021 we might have consumed only part of our input - advance past that part
1023 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
1027 if (dce_conn->partial_input.length == offset) {
1028 data_blob_free(&dce_conn->partial_input);
1032 blob = dce_conn->partial_input;
1033 dce_conn->partial_input = data_blob(blob.data + offset,
1034 blob.length - offset);
1035 data_blob_free(&blob);
1039 remove the call from the right list when freed
1041 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1043 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1048 process some input to a dcerpc endpoint server.
1050 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
1052 struct ndr_pull *ndr;
1053 enum ndr_err_code ndr_err;
1055 struct dcesrv_call_state *call;
1058 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1060 talloc_free(dce_conn->partial_input.data);
1061 return NT_STATUS_NO_MEMORY;
1063 call->conn = dce_conn;
1064 call->event_ctx = dce_conn->event_ctx;
1065 call->msg_ctx = dce_conn->msg_ctx;
1066 call->state_flags = call->conn->state_flags;
1067 call->time = timeval_current();
1068 call->list = DCESRV_LIST_NONE;
1070 talloc_set_destructor(call, dcesrv_call_dequeue);
1072 blob = dce_conn->partial_input;
1073 blob.length = dcerpc_get_frag_length(&blob);
1075 ndr = ndr_pull_init_blob(&blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
1077 talloc_free(dce_conn->partial_input.data);
1079 return NT_STATUS_NO_MEMORY;
1082 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
1083 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
1086 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
1087 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1088 talloc_free(dce_conn->partial_input.data);
1090 return ndr_map_error2ntstatus(ndr_err);
1093 /* we have to check the signing here, before combining the
1095 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1096 !dcesrv_auth_request(call, &blob)) {
1097 dce_partial_advance(dce_conn, blob.length);
1098 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1101 dce_partial_advance(dce_conn, blob.length);
1103 /* see if this is a continued packet */
1104 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1105 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1106 struct dcesrv_call_state *call2 = call;
1107 uint32_t alloc_size;
1109 /* we only allow fragmented requests, no other packet types */
1110 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1111 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1114 /* this is a continuation of an existing call - find the call then
1115 tack it on the end */
1116 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1118 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1121 if (call->pkt.ptype != call2->pkt.ptype) {
1122 /* trying to play silly buggers are we? */
1123 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1126 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1127 call2->pkt.u.request.stub_and_verifier.length;
1128 if (call->pkt.u.request.alloc_hint > alloc_size) {
1129 alloc_size = call->pkt.u.request.alloc_hint;
1132 call->pkt.u.request.stub_and_verifier.data =
1133 talloc_realloc(call,
1134 call->pkt.u.request.stub_and_verifier.data,
1135 uint8_t, alloc_size);
1136 if (!call->pkt.u.request.stub_and_verifier.data) {
1137 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1139 memcpy(call->pkt.u.request.stub_and_verifier.data +
1140 call->pkt.u.request.stub_and_verifier.length,
1141 call2->pkt.u.request.stub_and_verifier.data,
1142 call2->pkt.u.request.stub_and_verifier.length);
1143 call->pkt.u.request.stub_and_verifier.length +=
1144 call2->pkt.u.request.stub_and_verifier.length;
1146 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1151 /* this may not be the last pdu in the chain - if its isn't then
1152 just put it on the incoming_fragmented_call_list and wait for the rest */
1153 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1154 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1155 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1156 return NT_STATUS_OK;
1159 /* This removes any fragments we may have had stashed away */
1160 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1162 switch (call->pkt.ptype) {
1163 case DCERPC_PKT_BIND:
1164 status = dcesrv_bind(call);
1166 case DCERPC_PKT_AUTH3:
1167 status = dcesrv_auth3(call);
1169 case DCERPC_PKT_ALTER:
1170 status = dcesrv_alter(call);
1172 case DCERPC_PKT_REQUEST:
1173 status = dcesrv_request(call);
1176 status = NT_STATUS_INVALID_PARAMETER;
1180 /* if we are going to be sending a reply then add
1181 it to the list of pending calls. We add it to the end to keep the call
1182 list in the order we will answer */
1183 if (!NT_STATUS_IS_OK(status)) {
1192 provide some input to a dcerpc endpoint server. This passes data
1193 from a dcerpc client into the server
1195 _PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1199 dce_conn->partial_input.data = talloc_realloc(dce_conn,
1200 dce_conn->partial_input.data,
1202 dce_conn->partial_input.length + data->length);
1203 if (!dce_conn->partial_input.data) {
1204 return NT_STATUS_NO_MEMORY;
1206 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1207 data->data, data->length);
1208 dce_conn->partial_input.length += data->length;
1210 while (dce_full_packet(&dce_conn->partial_input)) {
1211 status = dcesrv_input_process(dce_conn);
1212 if (!NT_STATUS_IS_OK(status)) {
1217 return NT_STATUS_OK;
1221 retrieve some output from a dcerpc server
1222 The caller supplies a function that will be called to do the
1225 The first argument to write_fn() will be 'private', the second will
1226 be a pointer to a buffer containing the data to be sent and the 3rd
1227 will be a pointer to a size_t variable that will be set to the
1228 number of bytes that are consumed from the output.
1230 from the current fragment
1232 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
1234 NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1237 struct dcesrv_call_state *call;
1238 struct data_blob_list_item *rep;
1241 call = dce_conn->call_list;
1242 if (!call || !call->replies) {
1243 if (dce_conn->pending_call_list) {
1244 /* TODO: we need to say act async here
1245 * as we know we have pending requests
1246 * which will be finished at a time
1248 return NT_STATUS_FOOBAR;
1250 return NT_STATUS_FOOBAR;
1252 rep = call->replies;
1254 status = write_fn(private_data, &rep->blob, &nwritten);
1255 NT_STATUS_IS_ERR_RETURN(status);
1257 rep->blob.length -= nwritten;
1258 rep->blob.data += nwritten;
1260 if (rep->blob.length == 0) {
1261 /* we're done with this section of the call */
1262 DLIST_REMOVE(call->replies, rep);
1265 if (call->replies == NULL) {
1266 /* we're done with the whole call */
1267 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1274 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1275 struct loadparm_context *lp_ctx,
1276 const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1279 struct dcesrv_context *dce_ctx;
1282 if (!endpoint_servers) {
1283 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1284 return NT_STATUS_INTERNAL_ERROR;
1287 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1288 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1289 dce_ctx->endpoint_list = NULL;
1290 dce_ctx->lp_ctx = lp_ctx;
1292 for (i=0;endpoint_servers[i];i++) {
1293 const struct dcesrv_endpoint_server *ep_server;
1295 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1297 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1298 return NT_STATUS_INTERNAL_ERROR;
1301 status = ep_server->init_server(dce_ctx, ep_server);
1302 if (!NT_STATUS_IS_OK(status)) {
1303 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1304 nt_errstr(status)));
1309 *_dce_ctx = dce_ctx;
1310 return NT_STATUS_OK;
1313 /* the list of currently registered DCERPC endpoint servers.
1315 static struct ep_server {
1316 struct dcesrv_endpoint_server *ep_server;
1317 } *ep_servers = NULL;
1318 static int num_ep_servers;
1321 register a DCERPC endpoint server.
1323 The 'name' can be later used by other backends to find the operations
1324 structure for this backend.
1326 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1328 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1330 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1332 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1333 /* its already registered! */
1334 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1336 return NT_STATUS_OBJECT_NAME_COLLISION;
1339 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1341 smb_panic("out of memory in dcerpc_register");
1344 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1345 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1349 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1352 return NT_STATUS_OK;
1356 return the operations structure for a named backend of the specified type
1358 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1362 for (i=0;i<num_ep_servers;i++) {
1363 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1364 return ep_servers[i].ep_server;
1372 return the DCERPC module version, and the size of some critical types
1373 This can be used by endpoint server modules to either detect compilation errors, or provide
1374 multiple implementations for different smbd compilation options in one module
1376 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1378 static const struct dcesrv_critical_sizes critical_sizes = {
1379 DCERPC_MODULE_VERSION,
1380 sizeof(struct dcesrv_context),
1381 sizeof(struct dcesrv_endpoint),
1382 sizeof(struct dcesrv_endpoint_server),
1383 sizeof(struct dcesrv_interface),
1384 sizeof(struct dcesrv_if_list),
1385 sizeof(struct dcesrv_connection),
1386 sizeof(struct dcesrv_call_state),
1387 sizeof(struct dcesrv_auth),
1388 sizeof(struct dcesrv_handle)
1391 return &critical_sizes;
1395 initialise the dcerpc server context for ncacn_np based services
1397 _PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
1398 struct dcesrv_context **_dce_ctx)
1401 struct dcesrv_context *dce_ctx;
1403 status = dcesrv_init_context(mem_ctx, lp_ctx, lp_dcerpc_endpoint_servers(lp_ctx), &dce_ctx);
1404 NT_STATUS_NOT_OK_RETURN(status);
1406 *_dce_ctx = dce_ctx;
1407 return NT_STATUS_OK;