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 "lib/events/events.h"
30 #include "smbd/service_task.h"
31 #include "smbd/service_stream.h"
32 #include "smbd/service.h"
33 #include "system/filesys.h"
34 #include "libcli/security/security.h"
36 #include "param/param.h"
38 extern const struct dcesrv_interface dcesrv_mgmt_interface;
41 see if two endpoints match
43 static bool endpoints_match(const struct dcerpc_binding *ep1,
44 const struct dcerpc_binding *ep2)
46 if (ep1->transport != ep2->transport) {
50 if (!ep1->endpoint || !ep2->endpoint) {
51 return ep1->endpoint == ep2->endpoint;
54 if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
61 find an endpoint in the dcesrv_context
63 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
64 const struct dcerpc_binding *ep_description)
66 struct dcesrv_endpoint *ep;
67 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
68 if (endpoints_match(ep->ep_description, ep_description)) {
76 find a registered context_id from a bind or alter_context
78 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn,
81 struct dcesrv_connection_context *c;
82 for (c=conn->contexts;c;c=c->next) {
83 if (c->context_id == context_id) return c;
89 see if a uuid and if_version match to an interface
91 static bool interface_match(const struct dcesrv_interface *if1,
92 const struct dcesrv_interface *if2)
94 return (if1->syntax_id.if_version == if2->syntax_id.if_version &&
95 GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
99 find the interface operations on an endpoint
101 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
102 const struct dcesrv_interface *iface)
104 struct dcesrv_if_list *ifl;
105 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
106 if (interface_match(&(ifl->iface), iface)) {
107 return &(ifl->iface);
114 see if a uuid and if_version match to an interface
116 static bool interface_match_by_uuid(const struct dcesrv_interface *iface,
117 const struct GUID *uuid, uint32_t if_version)
119 return (iface->syntax_id.if_version == if_version &&
120 GUID_equal(&iface->syntax_id.uuid, uuid));
124 find the interface operations on an endpoint by uuid
126 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
127 const struct GUID *uuid, uint32_t if_version)
129 struct dcesrv_if_list *ifl;
130 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
131 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
132 return &(ifl->iface);
139 find the earlier parts of a fragmented call awaiting reassembily
141 static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
143 struct dcesrv_call_state *c;
144 for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
145 if (c->pkt.call_id == call_id) {
153 register an interface on an endpoint
155 _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
157 const struct dcesrv_interface *iface,
158 const struct security_descriptor *sd)
160 struct dcesrv_endpoint *ep;
161 struct dcesrv_if_list *ifl;
162 struct dcerpc_binding *binding;
166 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
168 if (NT_STATUS_IS_ERR(status)) {
169 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
173 /* check if this endpoint exists
175 if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
176 ep = talloc(dce_ctx, struct dcesrv_endpoint);
178 return NT_STATUS_NO_MEMORY;
181 ep->ep_description = talloc_reference(ep, binding);
184 /* add mgmt interface */
185 ifl = talloc(dce_ctx, struct dcesrv_if_list);
187 return NT_STATUS_NO_MEMORY;
190 memcpy(&(ifl->iface), &dcesrv_mgmt_interface,
191 sizeof(struct dcesrv_interface));
193 DLIST_ADD(ep->interface_list, ifl);
196 /* see if the interface is already registered on te endpoint */
197 if (find_interface(ep, iface)!=NULL) {
198 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
199 iface->name, ep_name));
200 return NT_STATUS_OBJECT_NAME_COLLISION;
203 /* talloc a new interface list element */
204 ifl = talloc(dce_ctx, struct dcesrv_if_list);
206 return NT_STATUS_NO_MEMORY;
209 /* copy the given interface struct to the one on the endpoints interface list */
210 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
212 /* if we have a security descriptor given,
213 * we should see if we can set it up on the endpoint
216 /* if there's currently no security descriptor given on the endpoint
219 if (ep->sd == NULL) {
220 ep->sd = security_descriptor_copy(dce_ctx, sd);
223 /* if now there's no security descriptor given on the endpoint
224 * something goes wrong, either we failed to copy the security descriptor
225 * or there was already one on the endpoint
227 if (ep->sd != NULL) {
228 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
229 " on endpoint '%s'\n",
230 iface->name, ep_name));
231 if (add_ep) free(ep);
233 return NT_STATUS_OBJECT_NAME_COLLISION;
237 /* finally add the interface on the endpoint */
238 DLIST_ADD(ep->interface_list, ifl);
240 /* if it's a new endpoint add it to the dcesrv_context */
242 DLIST_ADD(dce_ctx->endpoint_list, ep);
245 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
246 iface->name, ep_name));
251 static NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
252 DATA_BLOB *session_key)
254 if (p->auth_state.session_info->session_key.length) {
255 *session_key = p->auth_state.session_info->session_key;
258 return NT_STATUS_NO_USER_SESSION_KEY;
261 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
262 DATA_BLOB *session_key)
264 /* this took quite a few CPU cycles to find ... */
265 session_key->data = discard_const_p(uint8_t, "SystemLibraryDTC");
266 session_key->length = 16;
271 fetch the user session key - may be default (above) or the SMB session key
273 _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
274 DATA_BLOB *session_key)
276 return p->auth_state.session_key(p, session_key);
281 destroy a link to an endpoint
283 static int dcesrv_endpoint_destructor(struct dcesrv_connection *p)
285 while (p->contexts) {
286 struct dcesrv_connection_context *c = p->contexts;
288 DLIST_REMOVE(p->contexts, c);
291 c->iface->unbind(c, c->iface);
300 connect to a dcerpc endpoint
302 NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
304 const struct dcesrv_endpoint *ep,
305 struct auth_session_info *session_info,
306 struct event_context *event_ctx,
307 struct messaging_context *msg_ctx,
308 struct server_id server_id,
309 uint32_t state_flags,
310 struct dcesrv_connection **_p)
312 struct dcesrv_connection *p;
315 return NT_STATUS_ACCESS_DENIED;
318 p = talloc(mem_ctx, struct dcesrv_connection);
319 NT_STATUS_HAVE_NO_MEMORY(p);
321 if (!talloc_reference(p, session_info)) {
323 return NT_STATUS_NO_MEMORY;
326 p->dce_ctx = dce_ctx;
330 p->incoming_fragmented_call_list = NULL;
331 p->pending_call_list = NULL;
332 p->cli_max_recv_frag = 0;
333 p->partial_input = data_blob(NULL, 0);
334 p->auth_state.auth_info = NULL;
335 p->auth_state.gensec_security = NULL;
336 p->auth_state.session_info = session_info;
337 p->auth_state.session_key = dcesrv_generic_session_key;
338 p->event_ctx = event_ctx;
339 p->msg_ctx = msg_ctx;
340 p->server_id = server_id;
341 p->processing = false;
342 p->state_flags = state_flags;
343 ZERO_STRUCT(p->transport);
345 talloc_set_destructor(p, dcesrv_endpoint_destructor);
352 search and connect to a dcerpc endpoint
354 _PUBLIC_ NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
356 const struct dcerpc_binding *ep_description,
357 struct auth_session_info *session_info,
358 struct event_context *event_ctx,
359 struct messaging_context *msg_ctx,
360 struct server_id server_id,
361 uint32_t state_flags,
362 struct dcesrv_connection **dce_conn_p)
365 const struct dcesrv_endpoint *ep;
367 /* make sure this endpoint exists */
368 ep = find_endpoint(dce_ctx, ep_description);
370 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
373 status = dcesrv_endpoint_connect(dce_ctx, mem_ctx, ep, session_info,
374 event_ctx, msg_ctx, server_id,
375 state_flags, dce_conn_p);
376 NT_STATUS_NOT_OK_RETURN(status);
378 (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
380 /* TODO: check security descriptor of the endpoint here
381 * if it's a smb named pipe
382 * if it's failed free dce_conn_p
389 static void dcesrv_init_hdr(struct ncacn_packet *pkt, bool bigendian)
392 pkt->rpc_vers_minor = 0;
396 pkt->drep[0] = DCERPC_DREP_LE;
404 move a call from an existing linked list to the specified list. This
405 prevents bugs where we forget to remove the call from a previous
408 static void dcesrv_call_set_list(struct dcesrv_call_state *call,
409 enum dcesrv_call_list list)
411 switch (call->list) {
412 case DCESRV_LIST_NONE:
414 case DCESRV_LIST_CALL_LIST:
415 DLIST_REMOVE(call->conn->call_list, call);
417 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
418 DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
420 case DCESRV_LIST_PENDING_CALL_LIST:
421 DLIST_REMOVE(call->conn->pending_call_list, call);
426 case DCESRV_LIST_NONE:
428 case DCESRV_LIST_CALL_LIST:
429 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
431 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
432 DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
434 case DCESRV_LIST_PENDING_CALL_LIST:
435 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
441 return a dcerpc fault
443 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
445 struct ncacn_packet pkt;
446 struct data_blob_list_item *rep;
449 /* setup a bind_ack */
450 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
452 pkt.call_id = call->pkt.call_id;
453 pkt.ptype = DCERPC_PKT_FAULT;
454 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
455 pkt.u.fault.alloc_hint = 0;
456 pkt.u.fault.context_id = 0;
457 pkt.u.fault.cancel_count = 0;
458 pkt.u.fault.status = fault_code;
460 rep = talloc(call, struct data_blob_list_item);
462 return NT_STATUS_NO_MEMORY;
465 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
466 if (!NT_STATUS_IS_OK(status)) {
470 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
472 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
473 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
480 return a dcerpc bind_nak
482 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
484 struct ncacn_packet pkt;
485 struct data_blob_list_item *rep;
488 /* setup a bind_nak */
489 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
491 pkt.call_id = call->pkt.call_id;
492 pkt.ptype = DCERPC_PKT_BIND_NAK;
493 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
494 pkt.u.bind_nak.reject_reason = reason;
495 if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
496 pkt.u.bind_nak.versions.v.num_versions = 0;
499 rep = talloc(call, struct data_blob_list_item);
501 return NT_STATUS_NO_MEMORY;
504 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
505 if (!NT_STATUS_IS_OK(status)) {
509 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
511 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
512 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
519 handle a bind request
521 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
523 uint32_t if_version, transfer_syntax_version;
524 struct GUID uuid, *transfer_syntax_uuid;
525 struct ncacn_packet pkt;
526 struct data_blob_list_item *rep;
528 uint32_t result=0, reason=0;
530 const struct dcesrv_interface *iface;
532 if (call->pkt.u.bind.assoc_group_id != 0) {
533 return dcesrv_bind_nak(call, 0);
536 if (call->pkt.u.bind.num_contexts < 1 ||
537 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
538 return dcesrv_bind_nak(call, 0);
541 context_id = call->pkt.u.bind.ctx_list[0].context_id;
543 /* you can't bind twice on one context */
544 if (dcesrv_find_context(call->conn, context_id) != NULL) {
545 return dcesrv_bind_nak(call, 0);
548 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
549 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
551 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
552 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
553 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
554 ndr_transfer_syntax.if_version != transfer_syntax_version) {
555 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
556 /* we only do NDR encoded dcerpc */
557 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
558 talloc_free(uuid_str);
559 return dcesrv_bind_nak(call, 0);
562 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
564 char *uuid_str = GUID_string(call, &uuid);
565 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
566 talloc_free(uuid_str);
568 /* we don't know about that interface */
569 result = DCERPC_BIND_PROVIDER_REJECT;
570 reason = DCERPC_BIND_REASON_ASYNTAX;
574 /* add this context to the list of available context_ids */
575 struct dcesrv_connection_context *context = talloc(call->conn,
576 struct dcesrv_connection_context);
577 if (context == NULL) {
578 return dcesrv_bind_nak(call, 0);
580 context->conn = call->conn;
581 context->iface = iface;
582 context->context_id = context_id;
583 context->private = NULL;
584 context->handles = NULL;
585 DLIST_ADD(call->conn->contexts, context);
586 call->context = context;
589 if (call->conn->cli_max_recv_frag == 0) {
590 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
593 /* handle any authentication that is being requested */
594 if (!dcesrv_auth_bind(call)) {
595 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
598 /* setup a bind_ack */
599 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
601 pkt.call_id = call->pkt.call_id;
602 pkt.ptype = DCERPC_PKT_BIND_ACK;
603 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
604 pkt.u.bind_ack.max_xmit_frag = 0x2000;
605 pkt.u.bind_ack.max_recv_frag = 0x2000;
606 /* we need to send a non zero assoc_group_id here to make longhorn happy, it also matches samba3 */
607 pkt.u.bind_ack.assoc_group_id = 0x12345678;
609 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
610 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
612 pkt.u.bind_ack.secondary_address = "";
614 pkt.u.bind_ack.num_results = 1;
615 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
616 if (!pkt.u.bind_ack.ctx_list) {
617 return NT_STATUS_NO_MEMORY;
619 pkt.u.bind_ack.ctx_list[0].result = result;
620 pkt.u.bind_ack.ctx_list[0].reason = reason;
621 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
622 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
624 status = dcesrv_auth_bind_ack(call, &pkt);
625 if (!NT_STATUS_IS_OK(status)) {
626 return dcesrv_bind_nak(call, 0);
630 status = iface->bind(call, iface);
631 if (!NT_STATUS_IS_OK(status)) {
632 char *uuid_str = GUID_string(call, &uuid);
633 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
634 uuid_str, if_version, nt_errstr(status)));
635 talloc_free(uuid_str);
636 return dcesrv_bind_nak(call, 0);
640 rep = talloc(call, struct data_blob_list_item);
642 return NT_STATUS_NO_MEMORY;
645 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
646 if (!NT_STATUS_IS_OK(status)) {
650 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
652 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
653 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
660 handle a auth3 request
662 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
664 /* handle the auth3 in the auth code */
665 if (!dcesrv_auth_auth3(call)) {
666 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
671 /* we don't send a reply to a auth3 request, except by a
678 handle a bind request
680 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
682 uint32_t if_version, transfer_syntax_version;
683 struct dcesrv_connection_context *context;
684 const struct dcesrv_interface *iface;
685 struct GUID uuid, *transfer_syntax_uuid;
687 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
688 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
690 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
691 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
692 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
693 ndr_transfer_syntax.if_version != transfer_syntax_version) {
694 /* we only do NDR encoded dcerpc */
695 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
698 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
700 char *uuid_str = GUID_string(call, &uuid);
701 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
702 talloc_free(uuid_str);
703 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
706 /* add this context to the list of available context_ids */
707 context = talloc(call->conn, struct dcesrv_connection_context);
708 if (context == NULL) {
709 return NT_STATUS_NO_MEMORY;
711 context->conn = call->conn;
712 context->iface = iface;
713 context->context_id = context_id;
714 context->private = NULL;
715 context->handles = NULL;
716 DLIST_ADD(call->conn->contexts, context);
717 call->context = context;
724 handle a alter context request
726 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
728 struct ncacn_packet pkt;
729 struct data_blob_list_item *rep;
731 uint32_t result=0, reason=0;
734 /* handle any authentication that is being requested */
735 if (!dcesrv_auth_alter(call)) {
736 /* TODO: work out the right reject code */
737 result = DCERPC_BIND_PROVIDER_REJECT;
738 reason = DCERPC_BIND_REASON_ASYNTAX;
741 context_id = call->pkt.u.alter.ctx_list[0].context_id;
743 /* see if they are asking for a new interface */
745 dcesrv_find_context(call->conn, context_id) == NULL) {
746 status = dcesrv_alter_new_context(call, context_id);
747 if (!NT_STATUS_IS_OK(status)) {
748 result = DCERPC_BIND_PROVIDER_REJECT;
749 reason = DCERPC_BIND_REASON_ASYNTAX;
753 /* setup a alter_resp */
754 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
756 pkt.call_id = call->pkt.call_id;
757 pkt.ptype = DCERPC_PKT_ALTER_RESP;
758 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
759 pkt.u.alter_resp.max_xmit_frag = 0x2000;
760 pkt.u.alter_resp.max_recv_frag = 0x2000;
761 pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
762 pkt.u.alter_resp.num_results = 1;
763 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
764 if (!pkt.u.alter_resp.ctx_list) {
765 return NT_STATUS_NO_MEMORY;
767 pkt.u.alter_resp.ctx_list[0].result = result;
768 pkt.u.alter_resp.ctx_list[0].reason = reason;
769 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
770 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
771 pkt.u.alter_resp.secondary_address = "";
773 status = dcesrv_auth_alter_ack(call, &pkt);
774 if (!NT_STATUS_IS_OK(status)) {
775 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
776 || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
777 || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
778 || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
779 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
781 return dcesrv_fault(call, 0);
784 rep = talloc(call, struct data_blob_list_item);
786 return NT_STATUS_NO_MEMORY;
789 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
790 if (!NT_STATUS_IS_OK(status)) {
794 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
796 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
797 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
803 handle a dcerpc request packet
805 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
807 struct ndr_pull *pull;
809 struct dcesrv_connection_context *context;
811 /* if authenticated, and the mech we use can't do async replies, don't use them... */
812 if (call->conn->auth_state.gensec_security &&
813 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
814 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
817 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
818 if (context == NULL) {
819 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
822 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call,
823 lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
824 NT_STATUS_HAVE_NO_MEMORY(pull);
826 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
828 call->context = context;
829 call->ndr_pull = pull;
831 if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
832 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
835 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
836 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
839 /* unravel the NDR for the packet */
840 status = context->iface->ndr_pull(call, call, pull, &call->r);
841 if (!NT_STATUS_IS_OK(status)) {
842 return dcesrv_fault(call, call->fault_code);
845 if (pull->offset != pull->data_size) {
846 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
847 pull->data_size - pull->offset));
848 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
851 /* call the dispatch function */
852 status = context->iface->dispatch(call, call, call->r);
853 if (!NT_STATUS_IS_OK(status)) {
854 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
855 context->iface->name,
856 call->pkt.u.request.opnum,
857 dcerpc_errstr(pull, call->fault_code)));
858 return dcesrv_fault(call, call->fault_code);
861 /* add the call to the pending list */
862 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
864 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
868 return dcesrv_reply(call);
871 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
873 struct ndr_push *push;
876 uint32_t total_length;
877 struct dcesrv_connection_context *context = call->context;
879 /* call the reply function */
880 status = context->iface->reply(call, call, call->r);
881 if (!NT_STATUS_IS_OK(status)) {
882 return dcesrv_fault(call, call->fault_code);
885 /* form the reply NDR */
886 push = ndr_push_init_ctx(call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
887 NT_STATUS_HAVE_NO_MEMORY(push);
889 /* carry over the pointer count to the reply in case we are
890 using full pointer. See NDR specification for full
892 push->ptr_count = call->ndr_pull->ptr_count;
894 if (lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
895 push->flags |= LIBNDR_FLAG_BIGENDIAN;
898 status = context->iface->ndr_push(call, call, push, call->r);
899 if (!NT_STATUS_IS_OK(status)) {
900 return dcesrv_fault(call, call->fault_code);
903 stub = ndr_push_blob(push);
905 total_length = stub.length;
909 struct data_blob_list_item *rep;
910 struct ncacn_packet pkt;
912 rep = talloc(call, struct data_blob_list_item);
913 NT_STATUS_HAVE_NO_MEMORY(rep);
915 length = stub.length;
916 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
917 /* the 32 is to cope with signing data */
918 length = call->conn->cli_max_recv_frag -
919 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
922 /* form the dcerpc response packet */
923 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
925 pkt.call_id = call->pkt.call_id;
926 pkt.ptype = DCERPC_PKT_RESPONSE;
928 if (stub.length == total_length) {
929 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
931 if (length == stub.length) {
932 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
934 pkt.u.response.alloc_hint = stub.length;
935 pkt.u.response.context_id = call->pkt.u.request.context_id;
936 pkt.u.response.cancel_count = 0;
937 pkt.u.response.stub_and_verifier.data = stub.data;
938 pkt.u.response.stub_and_verifier.length = length;
940 if (!dcesrv_auth_response(call, &rep->blob, &pkt)) {
941 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
944 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
946 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
949 stub.length -= length;
950 } while (stub.length != 0);
952 /* move the call from the pending to the finished calls list */
953 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
955 if (call->conn->call_list && call->conn->call_list->replies) {
956 if (call->conn->transport.report_output_data) {
957 call->conn->transport.report_output_data(call->conn);
964 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
966 if (!conn->transport.get_my_addr) {
970 return conn->transport.get_my_addr(conn, mem_ctx);
973 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
975 if (!conn->transport.get_peer_addr) {
979 return conn->transport.get_peer_addr(conn, mem_ctx);
983 work out if we have a full packet yet
985 static bool dce_full_packet(const DATA_BLOB *data)
987 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
990 if (dcerpc_get_frag_length(data) > data->length) {
997 we might have consumed only part of our input - advance past that part
999 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
1003 if (dce_conn->partial_input.length == offset) {
1004 data_blob_free(&dce_conn->partial_input);
1008 blob = dce_conn->partial_input;
1009 dce_conn->partial_input = data_blob(blob.data + offset,
1010 blob.length - offset);
1011 data_blob_free(&blob);
1015 remove the call from the right list when freed
1017 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1019 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1024 process some input to a dcerpc endpoint server.
1026 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
1028 struct ndr_pull *ndr;
1029 enum ndr_err_code ndr_err;
1031 struct dcesrv_call_state *call;
1034 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1036 talloc_free(dce_conn->partial_input.data);
1037 return NT_STATUS_NO_MEMORY;
1039 call->conn = dce_conn;
1040 call->event_ctx = dce_conn->event_ctx;
1041 call->msg_ctx = dce_conn->msg_ctx;
1042 call->state_flags = call->conn->state_flags;
1043 call->time = timeval_current();
1044 call->list = DCESRV_LIST_NONE;
1046 talloc_set_destructor(call, dcesrv_call_dequeue);
1048 blob = dce_conn->partial_input;
1049 blob.length = dcerpc_get_frag_length(&blob);
1051 ndr = ndr_pull_init_blob(&blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
1053 talloc_free(dce_conn->partial_input.data);
1055 return NT_STATUS_NO_MEMORY;
1058 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
1059 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
1062 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
1063 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1064 talloc_free(dce_conn->partial_input.data);
1066 return ndr_map_error2ntstatus(ndr_err);
1069 /* we have to check the signing here, before combining the
1071 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1072 !dcesrv_auth_request(call, &blob)) {
1073 dce_partial_advance(dce_conn, blob.length);
1074 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1077 dce_partial_advance(dce_conn, blob.length);
1079 /* see if this is a continued packet */
1080 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1081 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1082 struct dcesrv_call_state *call2 = call;
1083 uint32_t alloc_size;
1085 /* we only allow fragmented requests, no other packet types */
1086 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1087 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1090 /* this is a continuation of an existing call - find the call then
1091 tack it on the end */
1092 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1094 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1097 if (call->pkt.ptype != call2->pkt.ptype) {
1098 /* trying to play silly buggers are we? */
1099 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1102 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1103 call2->pkt.u.request.stub_and_verifier.length;
1104 if (call->pkt.u.request.alloc_hint > alloc_size) {
1105 alloc_size = call->pkt.u.request.alloc_hint;
1108 call->pkt.u.request.stub_and_verifier.data =
1109 talloc_realloc(call,
1110 call->pkt.u.request.stub_and_verifier.data,
1111 uint8_t, alloc_size);
1112 if (!call->pkt.u.request.stub_and_verifier.data) {
1113 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1115 memcpy(call->pkt.u.request.stub_and_verifier.data +
1116 call->pkt.u.request.stub_and_verifier.length,
1117 call2->pkt.u.request.stub_and_verifier.data,
1118 call2->pkt.u.request.stub_and_verifier.length);
1119 call->pkt.u.request.stub_and_verifier.length +=
1120 call2->pkt.u.request.stub_and_verifier.length;
1122 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1127 /* this may not be the last pdu in the chain - if its isn't then
1128 just put it on the incoming_fragmented_call_list and wait for the rest */
1129 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1130 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1131 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1132 return NT_STATUS_OK;
1135 /* This removes any fragments we may have had stashed away */
1136 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1138 switch (call->pkt.ptype) {
1139 case DCERPC_PKT_BIND:
1140 status = dcesrv_bind(call);
1142 case DCERPC_PKT_AUTH3:
1143 status = dcesrv_auth3(call);
1145 case DCERPC_PKT_ALTER:
1146 status = dcesrv_alter(call);
1148 case DCERPC_PKT_REQUEST:
1149 status = dcesrv_request(call);
1152 status = NT_STATUS_INVALID_PARAMETER;
1156 /* if we are going to be sending a reply then add
1157 it to the list of pending calls. We add it to the end to keep the call
1158 list in the order we will answer */
1159 if (!NT_STATUS_IS_OK(status)) {
1168 provide some input to a dcerpc endpoint server. This passes data
1169 from a dcerpc client into the server
1171 _PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1175 dce_conn->partial_input.data = talloc_realloc(dce_conn,
1176 dce_conn->partial_input.data,
1178 dce_conn->partial_input.length + data->length);
1179 if (!dce_conn->partial_input.data) {
1180 return NT_STATUS_NO_MEMORY;
1182 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1183 data->data, data->length);
1184 dce_conn->partial_input.length += data->length;
1186 while (dce_full_packet(&dce_conn->partial_input)) {
1187 status = dcesrv_input_process(dce_conn);
1188 if (!NT_STATUS_IS_OK(status)) {
1193 return NT_STATUS_OK;
1197 retrieve some output from a dcerpc server
1198 The caller supplies a function that will be called to do the
1201 The first argument to write_fn() will be 'private', the second will
1202 be a pointer to a buffer containing the data to be sent and the 3rd
1203 will be a pointer to a size_t variable that will be set to the
1204 number of bytes that are consumed from the output.
1206 from the current fragment
1208 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
1210 NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1213 struct dcesrv_call_state *call;
1214 struct data_blob_list_item *rep;
1217 call = dce_conn->call_list;
1218 if (!call || !call->replies) {
1219 if (dce_conn->pending_call_list) {
1220 /* TODO: we need to say act async here
1221 * as we know we have pending requests
1222 * which will be finished at a time
1224 return NT_STATUS_FOOBAR;
1226 return NT_STATUS_FOOBAR;
1228 rep = call->replies;
1230 status = write_fn(private_data, &rep->blob, &nwritten);
1231 NT_STATUS_IS_ERR_RETURN(status);
1233 rep->blob.length -= nwritten;
1234 rep->blob.data += nwritten;
1236 if (rep->blob.length == 0) {
1237 /* we're done with this section of the call */
1238 DLIST_REMOVE(call->replies, rep);
1241 if (call->replies == NULL) {
1242 /* we're done with the whole call */
1243 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1250 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1251 struct loadparm_context *lp_ctx,
1252 const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1255 struct dcesrv_context *dce_ctx;
1258 if (!endpoint_servers) {
1259 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1260 return NT_STATUS_INTERNAL_ERROR;
1263 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1264 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1265 dce_ctx->endpoint_list = NULL;
1266 dce_ctx->lp_ctx = lp_ctx;
1268 for (i=0;endpoint_servers[i];i++) {
1269 const struct dcesrv_endpoint_server *ep_server;
1271 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1273 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1274 return NT_STATUS_INTERNAL_ERROR;
1277 status = ep_server->init_server(dce_ctx, ep_server);
1278 if (!NT_STATUS_IS_OK(status)) {
1279 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1280 nt_errstr(status)));
1285 *_dce_ctx = dce_ctx;
1286 return NT_STATUS_OK;
1289 /* the list of currently registered DCERPC endpoint servers.
1291 static struct ep_server {
1292 struct dcesrv_endpoint_server *ep_server;
1293 } *ep_servers = NULL;
1294 static int num_ep_servers;
1297 register a DCERPC endpoint server.
1299 The 'name' can be later used by other backends to find the operations
1300 structure for this backend.
1302 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1304 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1306 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1308 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1309 /* its already registered! */
1310 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1312 return NT_STATUS_OBJECT_NAME_COLLISION;
1315 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1317 smb_panic("out of memory in dcerpc_register");
1320 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1321 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1325 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1328 return NT_STATUS_OK;
1332 return the operations structure for a named backend of the specified type
1334 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1338 for (i=0;i<num_ep_servers;i++) {
1339 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1340 return ep_servers[i].ep_server;
1348 return the DCERPC module version, and the size of some critical types
1349 This can be used by endpoint server modules to either detect compilation errors, or provide
1350 multiple implementations for different smbd compilation options in one module
1352 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1354 static const struct dcesrv_critical_sizes critical_sizes = {
1355 DCERPC_MODULE_VERSION,
1356 sizeof(struct dcesrv_context),
1357 sizeof(struct dcesrv_endpoint),
1358 sizeof(struct dcesrv_endpoint_server),
1359 sizeof(struct dcesrv_interface),
1360 sizeof(struct dcesrv_if_list),
1361 sizeof(struct dcesrv_connection),
1362 sizeof(struct dcesrv_call_state),
1363 sizeof(struct dcesrv_auth),
1364 sizeof(struct dcesrv_handle)
1367 return &critical_sizes;
1371 initialise the dcerpc server context for ncacn_np based services
1373 _PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
1374 struct dcesrv_context **_dce_ctx)
1377 struct dcesrv_context *dce_ctx;
1379 status = dcesrv_init_context(mem_ctx, lp_ctx, lp_dcerpc_endpoint_servers(lp_ctx), &dce_ctx);
1380 NT_STATUS_NOT_OK_RETURN(status);
1382 *_dce_ctx = dce_ctx;
1383 return NT_STATUS_OK;