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;
450 /* setup a bind_ack */
451 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
453 pkt.call_id = call->pkt.call_id;
454 pkt.ptype = DCERPC_PKT_FAULT;
455 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
456 pkt.u.fault.alloc_hint = 0;
457 pkt.u.fault.context_id = 0;
458 pkt.u.fault.cancel_count = 0;
459 pkt.u.fault.status = fault_code;
461 rep = talloc(call, struct data_blob_list_item);
463 return NT_STATUS_NO_MEMORY;
466 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
467 if (!NT_STATUS_IS_OK(status)) {
471 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
473 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
474 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
481 return a dcerpc bind_nak
483 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
485 struct ncacn_packet pkt;
486 struct data_blob_list_item *rep;
489 /* setup a bind_nak */
490 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
492 pkt.call_id = call->pkt.call_id;
493 pkt.ptype = DCERPC_PKT_BIND_NAK;
494 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
495 pkt.u.bind_nak.reject_reason = reason;
496 if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
497 pkt.u.bind_nak.versions.v.num_versions = 0;
500 rep = talloc(call, struct data_blob_list_item);
502 return NT_STATUS_NO_MEMORY;
505 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
506 if (!NT_STATUS_IS_OK(status)) {
510 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
512 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
513 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
520 handle a bind request
522 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
524 uint32_t if_version, transfer_syntax_version;
525 struct GUID uuid, *transfer_syntax_uuid;
526 struct ncacn_packet pkt;
527 struct data_blob_list_item *rep;
529 uint32_t result=0, reason=0;
531 const struct dcesrv_interface *iface;
533 if (call->pkt.u.bind.assoc_group_id != 0) {
534 return dcesrv_bind_nak(call, 0);
537 if (call->pkt.u.bind.num_contexts < 1 ||
538 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
539 return dcesrv_bind_nak(call, 0);
542 context_id = call->pkt.u.bind.ctx_list[0].context_id;
544 /* you can't bind twice on one context */
545 if (dcesrv_find_context(call->conn, context_id) != NULL) {
546 return dcesrv_bind_nak(call, 0);
549 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
550 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
552 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
553 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
554 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
555 ndr_transfer_syntax.if_version != transfer_syntax_version) {
556 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
557 /* we only do NDR encoded dcerpc */
558 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
559 talloc_free(uuid_str);
560 return dcesrv_bind_nak(call, 0);
563 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
565 char *uuid_str = GUID_string(call, &uuid);
566 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
567 talloc_free(uuid_str);
569 /* we don't know about that interface */
570 result = DCERPC_BIND_PROVIDER_REJECT;
571 reason = DCERPC_BIND_REASON_ASYNTAX;
575 /* add this context to the list of available context_ids */
576 struct dcesrv_connection_context *context = talloc(call->conn,
577 struct dcesrv_connection_context);
578 if (context == NULL) {
579 return dcesrv_bind_nak(call, 0);
581 context->conn = call->conn;
582 context->iface = iface;
583 context->context_id = context_id;
584 context->private = NULL;
585 context->handles = NULL;
586 DLIST_ADD(call->conn->contexts, context);
587 call->context = context;
590 if (call->conn->cli_max_recv_frag == 0) {
591 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
594 /* handle any authentication that is being requested */
595 if (!dcesrv_auth_bind(call)) {
596 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
599 /* setup a bind_ack */
600 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
602 pkt.call_id = call->pkt.call_id;
603 pkt.ptype = DCERPC_PKT_BIND_ACK;
604 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
605 pkt.u.bind_ack.max_xmit_frag = 0x2000;
606 pkt.u.bind_ack.max_recv_frag = 0x2000;
607 /* we need to send a non zero assoc_group_id here to make longhorn happy, it also matches samba3 */
608 pkt.u.bind_ack.assoc_group_id = 0x12345678;
610 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
611 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
613 pkt.u.bind_ack.secondary_address = "";
615 pkt.u.bind_ack.num_results = 1;
616 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
617 if (!pkt.u.bind_ack.ctx_list) {
618 return NT_STATUS_NO_MEMORY;
620 pkt.u.bind_ack.ctx_list[0].result = result;
621 pkt.u.bind_ack.ctx_list[0].reason = reason;
622 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
623 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
625 status = dcesrv_auth_bind_ack(call, &pkt);
626 if (!NT_STATUS_IS_OK(status)) {
627 return dcesrv_bind_nak(call, 0);
631 status = iface->bind(call, iface);
632 if (!NT_STATUS_IS_OK(status)) {
633 char *uuid_str = GUID_string(call, &uuid);
634 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
635 uuid_str, if_version, nt_errstr(status)));
636 talloc_free(uuid_str);
637 return dcesrv_bind_nak(call, 0);
641 rep = talloc(call, struct data_blob_list_item);
643 return NT_STATUS_NO_MEMORY;
646 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
647 if (!NT_STATUS_IS_OK(status)) {
651 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
653 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
654 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
661 handle a auth3 request
663 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
665 /* handle the auth3 in the auth code */
666 if (!dcesrv_auth_auth3(call)) {
667 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
672 /* we don't send a reply to a auth3 request, except by a
679 handle a bind request
681 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
683 uint32_t if_version, transfer_syntax_version;
684 struct dcesrv_connection_context *context;
685 const struct dcesrv_interface *iface;
686 struct GUID uuid, *transfer_syntax_uuid;
688 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
689 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
691 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
692 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
693 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
694 ndr_transfer_syntax.if_version != transfer_syntax_version) {
695 /* we only do NDR encoded dcerpc */
696 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
699 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
701 char *uuid_str = GUID_string(call, &uuid);
702 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
703 talloc_free(uuid_str);
704 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
707 /* add this context to the list of available context_ids */
708 context = talloc(call->conn, struct dcesrv_connection_context);
709 if (context == NULL) {
710 return NT_STATUS_NO_MEMORY;
712 context->conn = call->conn;
713 context->iface = iface;
714 context->context_id = context_id;
715 context->private = NULL;
716 context->handles = NULL;
717 DLIST_ADD(call->conn->contexts, context);
718 call->context = context;
725 handle a alter context request
727 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
729 struct ncacn_packet pkt;
730 struct data_blob_list_item *rep;
732 uint32_t result=0, reason=0;
735 /* handle any authentication that is being requested */
736 if (!dcesrv_auth_alter(call)) {
737 /* TODO: work out the right reject code */
738 result = DCERPC_BIND_PROVIDER_REJECT;
739 reason = DCERPC_BIND_REASON_ASYNTAX;
742 context_id = call->pkt.u.alter.ctx_list[0].context_id;
744 /* see if they are asking for a new interface */
746 dcesrv_find_context(call->conn, context_id) == NULL) {
747 status = dcesrv_alter_new_context(call, context_id);
748 if (!NT_STATUS_IS_OK(status)) {
749 result = DCERPC_BIND_PROVIDER_REJECT;
750 reason = DCERPC_BIND_REASON_ASYNTAX;
754 /* setup a alter_resp */
755 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
757 pkt.call_id = call->pkt.call_id;
758 pkt.ptype = DCERPC_PKT_ALTER_RESP;
759 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
760 pkt.u.alter_resp.max_xmit_frag = 0x2000;
761 pkt.u.alter_resp.max_recv_frag = 0x2000;
762 pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
763 pkt.u.alter_resp.num_results = 1;
764 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
765 if (!pkt.u.alter_resp.ctx_list) {
766 return NT_STATUS_NO_MEMORY;
768 pkt.u.alter_resp.ctx_list[0].result = result;
769 pkt.u.alter_resp.ctx_list[0].reason = reason;
770 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
771 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
772 pkt.u.alter_resp.secondary_address = "";
774 status = dcesrv_auth_alter_ack(call, &pkt);
775 if (!NT_STATUS_IS_OK(status)) {
776 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
777 || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
778 || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
779 || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
780 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
782 return dcesrv_fault(call, 0);
785 rep = talloc(call, struct data_blob_list_item);
787 return NT_STATUS_NO_MEMORY;
790 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
791 if (!NT_STATUS_IS_OK(status)) {
795 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
797 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
798 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
804 handle a dcerpc request packet
806 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
808 struct ndr_pull *pull;
810 struct dcesrv_connection_context *context;
812 /* if authenticated, and the mech we use can't do async replies, don't use them... */
813 if (call->conn->auth_state.gensec_security &&
814 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
815 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
818 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
819 if (context == NULL) {
820 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
823 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call,
824 lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
825 NT_STATUS_HAVE_NO_MEMORY(pull);
827 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
829 call->context = context;
830 call->ndr_pull = pull;
832 if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
833 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
836 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
837 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
840 /* unravel the NDR for the packet */
841 status = context->iface->ndr_pull(call, call, pull, &call->r);
842 if (!NT_STATUS_IS_OK(status)) {
843 return dcesrv_fault(call, call->fault_code);
846 if (pull->offset != pull->data_size) {
847 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
848 pull->data_size - pull->offset));
849 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
852 /* call the dispatch function */
853 status = context->iface->dispatch(call, call, call->r);
854 if (!NT_STATUS_IS_OK(status)) {
855 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
856 context->iface->name,
857 call->pkt.u.request.opnum,
858 dcerpc_errstr(pull, call->fault_code)));
859 return dcesrv_fault(call, call->fault_code);
862 /* add the call to the pending list */
863 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
865 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
869 return dcesrv_reply(call);
872 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
874 struct ndr_push *push;
877 uint32_t total_length;
878 struct dcesrv_connection_context *context = call->context;
880 /* call the reply function */
881 status = context->iface->reply(call, call, call->r);
882 if (!NT_STATUS_IS_OK(status)) {
883 return dcesrv_fault(call, call->fault_code);
886 /* form the reply NDR */
887 push = ndr_push_init_ctx(call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
888 NT_STATUS_HAVE_NO_MEMORY(push);
890 /* carry over the pointer count to the reply in case we are
891 using full pointer. See NDR specification for full
893 push->ptr_count = call->ndr_pull->ptr_count;
895 if (lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
896 push->flags |= LIBNDR_FLAG_BIGENDIAN;
899 status = context->iface->ndr_push(call, call, push, call->r);
900 if (!NT_STATUS_IS_OK(status)) {
901 return dcesrv_fault(call, call->fault_code);
904 stub = ndr_push_blob(push);
906 total_length = stub.length;
910 struct data_blob_list_item *rep;
911 struct ncacn_packet pkt;
913 rep = talloc(call, struct data_blob_list_item);
914 NT_STATUS_HAVE_NO_MEMORY(rep);
916 length = stub.length;
917 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
918 /* the 32 is to cope with signing data */
919 length = call->conn->cli_max_recv_frag -
920 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
923 /* form the dcerpc response packet */
924 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
926 pkt.call_id = call->pkt.call_id;
927 pkt.ptype = DCERPC_PKT_RESPONSE;
929 if (stub.length == total_length) {
930 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
932 if (length == stub.length) {
933 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
935 pkt.u.response.alloc_hint = stub.length;
936 pkt.u.response.context_id = call->pkt.u.request.context_id;
937 pkt.u.response.cancel_count = 0;
938 pkt.u.response.stub_and_verifier.data = stub.data;
939 pkt.u.response.stub_and_verifier.length = length;
941 if (!dcesrv_auth_response(call, &rep->blob, &pkt)) {
942 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
945 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
947 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
950 stub.length -= length;
951 } while (stub.length != 0);
953 /* move the call from the pending to the finished calls list */
954 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
956 if (call->conn->call_list && call->conn->call_list->replies) {
957 if (call->conn->transport.report_output_data) {
958 call->conn->transport.report_output_data(call->conn);
965 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
967 if (!conn->transport.get_my_addr) {
971 return conn->transport.get_my_addr(conn, mem_ctx);
974 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
976 if (!conn->transport.get_peer_addr) {
980 return conn->transport.get_peer_addr(conn, mem_ctx);
984 work out if we have a full packet yet
986 static bool dce_full_packet(const DATA_BLOB *data)
988 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
991 if (dcerpc_get_frag_length(data) > data->length) {
998 we might have consumed only part of our input - advance past that part
1000 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
1004 if (dce_conn->partial_input.length == offset) {
1005 data_blob_free(&dce_conn->partial_input);
1009 blob = dce_conn->partial_input;
1010 dce_conn->partial_input = data_blob(blob.data + offset,
1011 blob.length - offset);
1012 data_blob_free(&blob);
1016 remove the call from the right list when freed
1018 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1020 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1025 process some input to a dcerpc endpoint server.
1027 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
1029 struct ndr_pull *ndr;
1030 enum ndr_err_code ndr_err;
1032 struct dcesrv_call_state *call;
1035 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1037 talloc_free(dce_conn->partial_input.data);
1038 return NT_STATUS_NO_MEMORY;
1040 call->conn = dce_conn;
1041 call->event_ctx = dce_conn->event_ctx;
1042 call->msg_ctx = dce_conn->msg_ctx;
1043 call->state_flags = call->conn->state_flags;
1044 call->time = timeval_current();
1045 call->list = DCESRV_LIST_NONE;
1047 talloc_set_destructor(call, dcesrv_call_dequeue);
1049 blob = dce_conn->partial_input;
1050 blob.length = dcerpc_get_frag_length(&blob);
1052 ndr = ndr_pull_init_blob(&blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
1054 talloc_free(dce_conn->partial_input.data);
1056 return NT_STATUS_NO_MEMORY;
1059 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
1060 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
1063 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
1064 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1065 talloc_free(dce_conn->partial_input.data);
1067 return ndr_map_error2ntstatus(ndr_err);
1070 /* we have to check the signing here, before combining the
1072 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1073 !dcesrv_auth_request(call, &blob)) {
1074 dce_partial_advance(dce_conn, blob.length);
1075 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1078 dce_partial_advance(dce_conn, blob.length);
1080 /* see if this is a continued packet */
1081 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1082 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1083 struct dcesrv_call_state *call2 = call;
1084 uint32_t alloc_size;
1086 /* we only allow fragmented requests, no other packet types */
1087 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1088 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1091 /* this is a continuation of an existing call - find the call then
1092 tack it on the end */
1093 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1095 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1098 if (call->pkt.ptype != call2->pkt.ptype) {
1099 /* trying to play silly buggers are we? */
1100 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1103 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1104 call2->pkt.u.request.stub_and_verifier.length;
1105 if (call->pkt.u.request.alloc_hint > alloc_size) {
1106 alloc_size = call->pkt.u.request.alloc_hint;
1109 call->pkt.u.request.stub_and_verifier.data =
1110 talloc_realloc(call,
1111 call->pkt.u.request.stub_and_verifier.data,
1112 uint8_t, alloc_size);
1113 if (!call->pkt.u.request.stub_and_verifier.data) {
1114 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1116 memcpy(call->pkt.u.request.stub_and_verifier.data +
1117 call->pkt.u.request.stub_and_verifier.length,
1118 call2->pkt.u.request.stub_and_verifier.data,
1119 call2->pkt.u.request.stub_and_verifier.length);
1120 call->pkt.u.request.stub_and_verifier.length +=
1121 call2->pkt.u.request.stub_and_verifier.length;
1123 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1128 /* this may not be the last pdu in the chain - if its isn't then
1129 just put it on the incoming_fragmented_call_list and wait for the rest */
1130 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1131 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1132 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1133 return NT_STATUS_OK;
1136 /* This removes any fragments we may have had stashed away */
1137 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1139 switch (call->pkt.ptype) {
1140 case DCERPC_PKT_BIND:
1141 status = dcesrv_bind(call);
1143 case DCERPC_PKT_AUTH3:
1144 status = dcesrv_auth3(call);
1146 case DCERPC_PKT_ALTER:
1147 status = dcesrv_alter(call);
1149 case DCERPC_PKT_REQUEST:
1150 status = dcesrv_request(call);
1153 status = NT_STATUS_INVALID_PARAMETER;
1157 /* if we are going to be sending a reply then add
1158 it to the list of pending calls. We add it to the end to keep the call
1159 list in the order we will answer */
1160 if (!NT_STATUS_IS_OK(status)) {
1169 provide some input to a dcerpc endpoint server. This passes data
1170 from a dcerpc client into the server
1172 _PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1176 dce_conn->partial_input.data = talloc_realloc(dce_conn,
1177 dce_conn->partial_input.data,
1179 dce_conn->partial_input.length + data->length);
1180 if (!dce_conn->partial_input.data) {
1181 return NT_STATUS_NO_MEMORY;
1183 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1184 data->data, data->length);
1185 dce_conn->partial_input.length += data->length;
1187 while (dce_full_packet(&dce_conn->partial_input)) {
1188 status = dcesrv_input_process(dce_conn);
1189 if (!NT_STATUS_IS_OK(status)) {
1194 return NT_STATUS_OK;
1198 retrieve some output from a dcerpc server
1199 The caller supplies a function that will be called to do the
1202 The first argument to write_fn() will be 'private', the second will
1203 be a pointer to a buffer containing the data to be sent and the 3rd
1204 will be a pointer to a size_t variable that will be set to the
1205 number of bytes that are consumed from the output.
1207 from the current fragment
1209 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
1211 NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1214 struct dcesrv_call_state *call;
1215 struct data_blob_list_item *rep;
1218 call = dce_conn->call_list;
1219 if (!call || !call->replies) {
1220 if (dce_conn->pending_call_list) {
1221 /* TODO: we need to say act async here
1222 * as we know we have pending requests
1223 * which will be finished at a time
1225 return NT_STATUS_FOOBAR;
1227 return NT_STATUS_FOOBAR;
1229 rep = call->replies;
1231 status = write_fn(private_data, &rep->blob, &nwritten);
1232 NT_STATUS_IS_ERR_RETURN(status);
1234 rep->blob.length -= nwritten;
1235 rep->blob.data += nwritten;
1237 if (rep->blob.length == 0) {
1238 /* we're done with this section of the call */
1239 DLIST_REMOVE(call->replies, rep);
1242 if (call->replies == NULL) {
1243 /* we're done with the whole call */
1244 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1251 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1252 struct loadparm_context *lp_ctx,
1253 const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1256 struct dcesrv_context *dce_ctx;
1259 if (!endpoint_servers) {
1260 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1261 return NT_STATUS_INTERNAL_ERROR;
1264 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1265 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1266 dce_ctx->endpoint_list = NULL;
1267 dce_ctx->lp_ctx = lp_ctx;
1269 for (i=0;endpoint_servers[i];i++) {
1270 const struct dcesrv_endpoint_server *ep_server;
1272 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1274 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1275 return NT_STATUS_INTERNAL_ERROR;
1278 status = ep_server->init_server(dce_ctx, ep_server);
1279 if (!NT_STATUS_IS_OK(status)) {
1280 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1281 nt_errstr(status)));
1286 *_dce_ctx = dce_ctx;
1287 return NT_STATUS_OK;
1290 /* the list of currently registered DCERPC endpoint servers.
1292 static struct ep_server {
1293 struct dcesrv_endpoint_server *ep_server;
1294 } *ep_servers = NULL;
1295 static int num_ep_servers;
1298 register a DCERPC endpoint server.
1300 The 'name' can be later used by other backends to find the operations
1301 structure for this backend.
1303 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1305 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1307 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1309 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1310 /* its already registered! */
1311 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1313 return NT_STATUS_OBJECT_NAME_COLLISION;
1316 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1318 smb_panic("out of memory in dcerpc_register");
1321 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1322 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1326 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1329 return NT_STATUS_OK;
1333 return the operations structure for a named backend of the specified type
1335 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1339 for (i=0;i<num_ep_servers;i++) {
1340 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1341 return ep_servers[i].ep_server;
1349 return the DCERPC module version, and the size of some critical types
1350 This can be used by endpoint server modules to either detect compilation errors, or provide
1351 multiple implementations for different smbd compilation options in one module
1353 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1355 static const struct dcesrv_critical_sizes critical_sizes = {
1356 DCERPC_MODULE_VERSION,
1357 sizeof(struct dcesrv_context),
1358 sizeof(struct dcesrv_endpoint),
1359 sizeof(struct dcesrv_endpoint_server),
1360 sizeof(struct dcesrv_interface),
1361 sizeof(struct dcesrv_if_list),
1362 sizeof(struct dcesrv_connection),
1363 sizeof(struct dcesrv_call_state),
1364 sizeof(struct dcesrv_auth),
1365 sizeof(struct dcesrv_handle)
1368 return &critical_sizes;
1372 initialise the dcerpc server context for ncacn_np based services
1374 _PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
1375 struct dcesrv_context **_dce_ctx)
1378 struct dcesrv_context *dce_ctx;
1380 status = dcesrv_init_context(mem_ctx, lp_ctx, lp_dcerpc_endpoint_servers(lp_ctx), &dce_ctx);
1381 NT_STATUS_NOT_OK_RETURN(status);
1383 *_dce_ctx = dce_ctx;
1384 return NT_STATUS_OK;