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;
537 if (call->pkt.u.bind.assoc_group_id != 0) {
538 return dcesrv_bind_nak(call, 0);
541 if (call->pkt.u.bind.num_contexts < 1 ||
542 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
543 return dcesrv_bind_nak(call, 0);
546 context_id = call->pkt.u.bind.ctx_list[0].context_id;
548 /* you can't bind twice on one context */
549 if (dcesrv_find_context(call->conn, context_id) != NULL) {
550 return dcesrv_bind_nak(call, 0);
553 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
554 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
556 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
557 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
558 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
559 ndr_transfer_syntax.if_version != transfer_syntax_version) {
560 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
561 /* we only do NDR encoded dcerpc */
562 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
563 talloc_free(uuid_str);
564 return dcesrv_bind_nak(call, 0);
567 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
569 char *uuid_str = GUID_string(call, &uuid);
570 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
571 talloc_free(uuid_str);
573 /* we don't know about that interface */
574 result = DCERPC_BIND_PROVIDER_REJECT;
575 reason = DCERPC_BIND_REASON_ASYNTAX;
579 /* add this context to the list of available context_ids */
580 struct dcesrv_connection_context *context = talloc(call->conn,
581 struct dcesrv_connection_context);
582 if (context == NULL) {
583 return dcesrv_bind_nak(call, 0);
585 context->conn = call->conn;
586 context->iface = iface;
587 context->context_id = context_id;
588 context->private = NULL;
589 context->handles = NULL;
590 DLIST_ADD(call->conn->contexts, context);
591 call->context = context;
594 if (call->conn->cli_max_recv_frag == 0) {
595 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
598 /* handle any authentication that is being requested */
599 if (!dcesrv_auth_bind(call)) {
600 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
603 /* setup a bind_ack */
604 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
606 pkt.call_id = call->pkt.call_id;
607 pkt.ptype = DCERPC_PKT_BIND_ACK;
608 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
609 pkt.u.bind_ack.max_xmit_frag = 0x2000;
610 pkt.u.bind_ack.max_recv_frag = 0x2000;
611 /* we need to send a non zero assoc_group_id here to make longhorn happy, it also matches samba3 */
612 pkt.u.bind_ack.assoc_group_id = 0x12345678;
614 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
615 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
617 pkt.u.bind_ack.secondary_address = "";
619 pkt.u.bind_ack.num_results = 1;
620 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
621 if (!pkt.u.bind_ack.ctx_list) {
622 return NT_STATUS_NO_MEMORY;
624 pkt.u.bind_ack.ctx_list[0].result = result;
625 pkt.u.bind_ack.ctx_list[0].reason = reason;
626 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
627 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
629 status = dcesrv_auth_bind_ack(call, &pkt);
630 if (!NT_STATUS_IS_OK(status)) {
631 return dcesrv_bind_nak(call, 0);
635 status = iface->bind(call, iface);
636 if (!NT_STATUS_IS_OK(status)) {
637 char *uuid_str = GUID_string(call, &uuid);
638 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
639 uuid_str, if_version, nt_errstr(status)));
640 talloc_free(uuid_str);
641 return dcesrv_bind_nak(call, 0);
645 rep = talloc(call, struct data_blob_list_item);
647 return NT_STATUS_NO_MEMORY;
650 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
651 if (!NT_STATUS_IS_OK(status)) {
655 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
657 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
658 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
665 handle a auth3 request
667 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
669 /* handle the auth3 in the auth code */
670 if (!dcesrv_auth_auth3(call)) {
671 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
676 /* we don't send a reply to a auth3 request, except by a
683 handle a bind request
685 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
687 uint32_t if_version, transfer_syntax_version;
688 struct dcesrv_connection_context *context;
689 const struct dcesrv_interface *iface;
690 struct GUID uuid, *transfer_syntax_uuid;
693 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
694 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
696 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
697 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
698 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
699 ndr_transfer_syntax.if_version != transfer_syntax_version) {
700 /* we only do NDR encoded dcerpc */
701 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
704 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
706 char *uuid_str = GUID_string(call, &uuid);
707 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
708 talloc_free(uuid_str);
709 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
712 /* add this context to the list of available context_ids */
713 context = talloc(call->conn, struct dcesrv_connection_context);
714 if (context == NULL) {
715 return NT_STATUS_NO_MEMORY;
717 context->conn = call->conn;
718 context->iface = iface;
719 context->context_id = context_id;
720 context->private = NULL;
721 context->handles = NULL;
722 DLIST_ADD(call->conn->contexts, context);
723 call->context = context;
726 status = iface->bind(call, iface);
727 if (!NT_STATUS_IS_OK(status)) {
737 handle a alter context request
739 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
741 struct ncacn_packet pkt;
742 struct data_blob_list_item *rep;
744 uint32_t result=0, reason=0;
747 /* handle any authentication that is being requested */
748 if (!dcesrv_auth_alter(call)) {
749 /* TODO: work out the right reject code */
750 result = DCERPC_BIND_PROVIDER_REJECT;
751 reason = DCERPC_BIND_REASON_ASYNTAX;
754 context_id = call->pkt.u.alter.ctx_list[0].context_id;
756 /* see if they are asking for a new interface */
758 dcesrv_find_context(call->conn, context_id) == NULL) {
759 status = dcesrv_alter_new_context(call, context_id);
760 if (!NT_STATUS_IS_OK(status)) {
761 result = DCERPC_BIND_PROVIDER_REJECT;
762 reason = DCERPC_BIND_REASON_ASYNTAX;
766 /* setup a alter_resp */
767 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
769 pkt.call_id = call->pkt.call_id;
770 pkt.ptype = DCERPC_PKT_ALTER_RESP;
771 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
772 pkt.u.alter_resp.max_xmit_frag = 0x2000;
773 pkt.u.alter_resp.max_recv_frag = 0x2000;
774 pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
775 pkt.u.alter_resp.num_results = 1;
776 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
777 if (!pkt.u.alter_resp.ctx_list) {
778 return NT_STATUS_NO_MEMORY;
780 pkt.u.alter_resp.ctx_list[0].result = result;
781 pkt.u.alter_resp.ctx_list[0].reason = reason;
782 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
783 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
784 pkt.u.alter_resp.secondary_address = "";
786 status = dcesrv_auth_alter_ack(call, &pkt);
787 if (!NT_STATUS_IS_OK(status)) {
788 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
789 || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
790 || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
791 || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
792 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
794 return dcesrv_fault(call, 0);
797 rep = talloc(call, struct data_blob_list_item);
799 return NT_STATUS_NO_MEMORY;
802 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
803 if (!NT_STATUS_IS_OK(status)) {
807 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
809 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
810 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
816 handle a dcerpc request packet
818 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
820 struct ndr_pull *pull;
822 struct dcesrv_connection_context *context;
824 /* if authenticated, and the mech we use can't do async replies, don't use them... */
825 if (call->conn->auth_state.gensec_security &&
826 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
827 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
830 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
831 if (context == NULL) {
832 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
835 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call,
836 lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
837 NT_STATUS_HAVE_NO_MEMORY(pull);
839 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
841 call->context = context;
842 call->ndr_pull = pull;
844 if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
845 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
848 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
849 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
852 /* unravel the NDR for the packet */
853 status = context->iface->ndr_pull(call, call, pull, &call->r);
854 if (!NT_STATUS_IS_OK(status)) {
855 return dcesrv_fault(call, call->fault_code);
858 if (pull->offset != pull->data_size) {
859 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
860 pull->data_size - pull->offset));
861 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
864 /* call the dispatch function */
865 status = context->iface->dispatch(call, call, call->r);
866 if (!NT_STATUS_IS_OK(status)) {
867 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
868 context->iface->name,
869 call->pkt.u.request.opnum,
870 dcerpc_errstr(pull, call->fault_code)));
871 return dcesrv_fault(call, call->fault_code);
874 /* add the call to the pending list */
875 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
877 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
881 return dcesrv_reply(call);
884 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
886 struct ndr_push *push;
889 uint32_t total_length;
890 struct dcesrv_connection_context *context = call->context;
892 /* call the reply function */
893 status = context->iface->reply(call, call, call->r);
894 if (!NT_STATUS_IS_OK(status)) {
895 return dcesrv_fault(call, call->fault_code);
898 /* form the reply NDR */
899 push = ndr_push_init_ctx(call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
900 NT_STATUS_HAVE_NO_MEMORY(push);
902 /* carry over the pointer count to the reply in case we are
903 using full pointer. See NDR specification for full
905 push->ptr_count = call->ndr_pull->ptr_count;
907 if (lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
908 push->flags |= LIBNDR_FLAG_BIGENDIAN;
911 status = context->iface->ndr_push(call, call, push, call->r);
912 if (!NT_STATUS_IS_OK(status)) {
913 return dcesrv_fault(call, call->fault_code);
916 stub = ndr_push_blob(push);
918 total_length = stub.length;
922 struct data_blob_list_item *rep;
923 struct ncacn_packet pkt;
925 rep = talloc(call, struct data_blob_list_item);
926 NT_STATUS_HAVE_NO_MEMORY(rep);
928 length = stub.length;
929 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
930 /* the 32 is to cope with signing data */
931 length = call->conn->cli_max_recv_frag -
932 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
935 /* form the dcerpc response packet */
936 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
938 pkt.call_id = call->pkt.call_id;
939 pkt.ptype = DCERPC_PKT_RESPONSE;
941 if (stub.length == total_length) {
942 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
944 if (length == stub.length) {
945 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
947 pkt.u.response.alloc_hint = stub.length;
948 pkt.u.response.context_id = call->pkt.u.request.context_id;
949 pkt.u.response.cancel_count = 0;
950 pkt.u.response.stub_and_verifier.data = stub.data;
951 pkt.u.response.stub_and_verifier.length = length;
953 if (!dcesrv_auth_response(call, &rep->blob, &pkt)) {
954 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
957 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
959 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
962 stub.length -= length;
963 } while (stub.length != 0);
965 /* move the call from the pending to the finished calls list */
966 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
968 if (call->conn->call_list && call->conn->call_list->replies) {
969 if (call->conn->transport.report_output_data) {
970 call->conn->transport.report_output_data(call->conn);
977 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
979 if (!conn->transport.get_my_addr) {
983 return conn->transport.get_my_addr(conn, mem_ctx);
986 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
988 if (!conn->transport.get_peer_addr) {
992 return conn->transport.get_peer_addr(conn, mem_ctx);
996 work out if we have a full packet yet
998 static bool dce_full_packet(const DATA_BLOB *data)
1000 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
1003 if (dcerpc_get_frag_length(data) > data->length) {
1010 we might have consumed only part of our input - advance past that part
1012 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
1016 if (dce_conn->partial_input.length == offset) {
1017 data_blob_free(&dce_conn->partial_input);
1021 blob = dce_conn->partial_input;
1022 dce_conn->partial_input = data_blob(blob.data + offset,
1023 blob.length - offset);
1024 data_blob_free(&blob);
1028 remove the call from the right list when freed
1030 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1032 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1037 process some input to a dcerpc endpoint server.
1039 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
1041 struct ndr_pull *ndr;
1042 enum ndr_err_code ndr_err;
1044 struct dcesrv_call_state *call;
1047 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1049 talloc_free(dce_conn->partial_input.data);
1050 return NT_STATUS_NO_MEMORY;
1052 call->conn = dce_conn;
1053 call->event_ctx = dce_conn->event_ctx;
1054 call->msg_ctx = dce_conn->msg_ctx;
1055 call->state_flags = call->conn->state_flags;
1056 call->time = timeval_current();
1057 call->list = DCESRV_LIST_NONE;
1059 talloc_set_destructor(call, dcesrv_call_dequeue);
1061 blob = dce_conn->partial_input;
1062 blob.length = dcerpc_get_frag_length(&blob);
1064 ndr = ndr_pull_init_blob(&blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
1066 talloc_free(dce_conn->partial_input.data);
1068 return NT_STATUS_NO_MEMORY;
1071 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
1072 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
1075 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
1076 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1077 talloc_free(dce_conn->partial_input.data);
1079 return ndr_map_error2ntstatus(ndr_err);
1082 /* we have to check the signing here, before combining the
1084 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1085 !dcesrv_auth_request(call, &blob)) {
1086 dce_partial_advance(dce_conn, blob.length);
1087 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1090 dce_partial_advance(dce_conn, blob.length);
1092 /* see if this is a continued packet */
1093 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1094 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1095 struct dcesrv_call_state *call2 = call;
1096 uint32_t alloc_size;
1098 /* we only allow fragmented requests, no other packet types */
1099 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1100 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1103 /* this is a continuation of an existing call - find the call then
1104 tack it on the end */
1105 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1107 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1110 if (call->pkt.ptype != call2->pkt.ptype) {
1111 /* trying to play silly buggers are we? */
1112 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1115 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1116 call2->pkt.u.request.stub_and_verifier.length;
1117 if (call->pkt.u.request.alloc_hint > alloc_size) {
1118 alloc_size = call->pkt.u.request.alloc_hint;
1121 call->pkt.u.request.stub_and_verifier.data =
1122 talloc_realloc(call,
1123 call->pkt.u.request.stub_and_verifier.data,
1124 uint8_t, alloc_size);
1125 if (!call->pkt.u.request.stub_and_verifier.data) {
1126 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1128 memcpy(call->pkt.u.request.stub_and_verifier.data +
1129 call->pkt.u.request.stub_and_verifier.length,
1130 call2->pkt.u.request.stub_and_verifier.data,
1131 call2->pkt.u.request.stub_and_verifier.length);
1132 call->pkt.u.request.stub_and_verifier.length +=
1133 call2->pkt.u.request.stub_and_verifier.length;
1135 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1140 /* this may not be the last pdu in the chain - if its isn't then
1141 just put it on the incoming_fragmented_call_list and wait for the rest */
1142 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1143 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1144 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1145 return NT_STATUS_OK;
1148 /* This removes any fragments we may have had stashed away */
1149 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1151 switch (call->pkt.ptype) {
1152 case DCERPC_PKT_BIND:
1153 status = dcesrv_bind(call);
1155 case DCERPC_PKT_AUTH3:
1156 status = dcesrv_auth3(call);
1158 case DCERPC_PKT_ALTER:
1159 status = dcesrv_alter(call);
1161 case DCERPC_PKT_REQUEST:
1162 status = dcesrv_request(call);
1165 status = NT_STATUS_INVALID_PARAMETER;
1169 /* if we are going to be sending a reply then add
1170 it to the list of pending calls. We add it to the end to keep the call
1171 list in the order we will answer */
1172 if (!NT_STATUS_IS_OK(status)) {
1181 provide some input to a dcerpc endpoint server. This passes data
1182 from a dcerpc client into the server
1184 _PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1188 dce_conn->partial_input.data = talloc_realloc(dce_conn,
1189 dce_conn->partial_input.data,
1191 dce_conn->partial_input.length + data->length);
1192 if (!dce_conn->partial_input.data) {
1193 return NT_STATUS_NO_MEMORY;
1195 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1196 data->data, data->length);
1197 dce_conn->partial_input.length += data->length;
1199 while (dce_full_packet(&dce_conn->partial_input)) {
1200 status = dcesrv_input_process(dce_conn);
1201 if (!NT_STATUS_IS_OK(status)) {
1206 return NT_STATUS_OK;
1210 retrieve some output from a dcerpc server
1211 The caller supplies a function that will be called to do the
1214 The first argument to write_fn() will be 'private', the second will
1215 be a pointer to a buffer containing the data to be sent and the 3rd
1216 will be a pointer to a size_t variable that will be set to the
1217 number of bytes that are consumed from the output.
1219 from the current fragment
1221 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
1223 NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1226 struct dcesrv_call_state *call;
1227 struct data_blob_list_item *rep;
1230 call = dce_conn->call_list;
1231 if (!call || !call->replies) {
1232 if (dce_conn->pending_call_list) {
1233 /* TODO: we need to say act async here
1234 * as we know we have pending requests
1235 * which will be finished at a time
1237 return NT_STATUS_FOOBAR;
1239 return NT_STATUS_FOOBAR;
1241 rep = call->replies;
1243 status = write_fn(private_data, &rep->blob, &nwritten);
1244 NT_STATUS_IS_ERR_RETURN(status);
1246 rep->blob.length -= nwritten;
1247 rep->blob.data += nwritten;
1249 if (rep->blob.length == 0) {
1250 /* we're done with this section of the call */
1251 DLIST_REMOVE(call->replies, rep);
1254 if (call->replies == NULL) {
1255 /* we're done with the whole call */
1256 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1263 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1264 struct loadparm_context *lp_ctx,
1265 const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1268 struct dcesrv_context *dce_ctx;
1271 if (!endpoint_servers) {
1272 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1273 return NT_STATUS_INTERNAL_ERROR;
1276 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1277 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1278 dce_ctx->endpoint_list = NULL;
1279 dce_ctx->lp_ctx = lp_ctx;
1281 for (i=0;endpoint_servers[i];i++) {
1282 const struct dcesrv_endpoint_server *ep_server;
1284 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1286 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1287 return NT_STATUS_INTERNAL_ERROR;
1290 status = ep_server->init_server(dce_ctx, ep_server);
1291 if (!NT_STATUS_IS_OK(status)) {
1292 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1293 nt_errstr(status)));
1298 *_dce_ctx = dce_ctx;
1299 return NT_STATUS_OK;
1302 /* the list of currently registered DCERPC endpoint servers.
1304 static struct ep_server {
1305 struct dcesrv_endpoint_server *ep_server;
1306 } *ep_servers = NULL;
1307 static int num_ep_servers;
1310 register a DCERPC endpoint server.
1312 The 'name' can be later used by other backends to find the operations
1313 structure for this backend.
1315 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1317 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1319 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1321 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1322 /* its already registered! */
1323 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1325 return NT_STATUS_OBJECT_NAME_COLLISION;
1328 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1330 smb_panic("out of memory in dcerpc_register");
1333 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1334 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1338 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1341 return NT_STATUS_OK;
1345 return the operations structure for a named backend of the specified type
1347 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1351 for (i=0;i<num_ep_servers;i++) {
1352 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1353 return ep_servers[i].ep_server;
1361 return the DCERPC module version, and the size of some critical types
1362 This can be used by endpoint server modules to either detect compilation errors, or provide
1363 multiple implementations for different smbd compilation options in one module
1365 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1367 static const struct dcesrv_critical_sizes critical_sizes = {
1368 DCERPC_MODULE_VERSION,
1369 sizeof(struct dcesrv_context),
1370 sizeof(struct dcesrv_endpoint),
1371 sizeof(struct dcesrv_endpoint_server),
1372 sizeof(struct dcesrv_interface),
1373 sizeof(struct dcesrv_if_list),
1374 sizeof(struct dcesrv_connection),
1375 sizeof(struct dcesrv_call_state),
1376 sizeof(struct dcesrv_auth),
1377 sizeof(struct dcesrv_handle)
1380 return &critical_sizes;
1384 initialise the dcerpc server context for ncacn_np based services
1386 _PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
1387 struct dcesrv_context **_dce_ctx)
1390 struct dcesrv_context *dce_ctx;
1392 status = dcesrv_init_context(mem_ctx, lp_ctx, lp_dcerpc_endpoint_servers(lp_ctx), &dce_ctx);
1393 NT_STATUS_NOT_OK_RETURN(status);
1395 *_dce_ctx = dce_ctx;
1396 return NT_STATUS_OK;