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, &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, &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, &pkt,
646 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, &pkt,
791 call->conn->auth_state.auth_info);
792 if (!NT_STATUS_IS_OK(status)) {
796 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
798 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
799 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
805 handle a dcerpc request packet
807 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
809 struct ndr_pull *pull;
811 struct dcesrv_connection_context *context;
813 /* if authenticated, and the mech we use can't do async replies, don't use them... */
814 if (call->conn->auth_state.gensec_security &&
815 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
816 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
819 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
820 if (context == NULL) {
821 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
824 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call,
825 lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
826 NT_STATUS_HAVE_NO_MEMORY(pull);
828 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
830 call->context = context;
831 call->ndr_pull = pull;
833 if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
834 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
837 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
838 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
841 /* unravel the NDR for the packet */
842 status = context->iface->ndr_pull(call, call, pull, &call->r);
843 if (!NT_STATUS_IS_OK(status)) {
844 return dcesrv_fault(call, call->fault_code);
847 if (pull->offset != pull->data_size) {
848 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
849 pull->data_size - pull->offset));
850 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
853 /* call the dispatch function */
854 status = context->iface->dispatch(call, call, call->r);
855 if (!NT_STATUS_IS_OK(status)) {
856 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
857 context->iface->name,
858 call->pkt.u.request.opnum,
859 dcerpc_errstr(pull, call->fault_code)));
860 return dcesrv_fault(call, call->fault_code);
863 /* add the call to the pending list */
864 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
866 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
870 return dcesrv_reply(call);
873 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
875 struct ndr_push *push;
878 uint32_t total_length;
879 struct dcesrv_connection_context *context = call->context;
881 /* call the reply function */
882 status = context->iface->reply(call, call, call->r);
883 if (!NT_STATUS_IS_OK(status)) {
884 return dcesrv_fault(call, call->fault_code);
887 /* form the reply NDR */
888 push = ndr_push_init_ctx(call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
889 NT_STATUS_HAVE_NO_MEMORY(push);
891 /* carry over the pointer count to the reply in case we are
892 using full pointer. See NDR specification for full
894 push->ptr_count = call->ndr_pull->ptr_count;
896 if (lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
897 push->flags |= LIBNDR_FLAG_BIGENDIAN;
900 status = context->iface->ndr_push(call, call, push, call->r);
901 if (!NT_STATUS_IS_OK(status)) {
902 return dcesrv_fault(call, call->fault_code);
905 stub = ndr_push_blob(push);
907 total_length = stub.length;
911 struct data_blob_list_item *rep;
912 struct ncacn_packet pkt;
914 rep = talloc(call, struct data_blob_list_item);
915 NT_STATUS_HAVE_NO_MEMORY(rep);
917 length = stub.length;
918 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
919 /* the 32 is to cope with signing data */
920 length = call->conn->cli_max_recv_frag -
921 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
924 /* form the dcerpc response packet */
925 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
927 pkt.call_id = call->pkt.call_id;
928 pkt.ptype = DCERPC_PKT_RESPONSE;
930 if (stub.length == total_length) {
931 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
933 if (length == stub.length) {
934 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
936 pkt.u.response.alloc_hint = stub.length;
937 pkt.u.response.context_id = call->pkt.u.request.context_id;
938 pkt.u.response.cancel_count = 0;
939 pkt.u.response.stub_and_verifier.data = stub.data;
940 pkt.u.response.stub_and_verifier.length = length;
942 if (!dcesrv_auth_response(call, &rep->blob, &pkt)) {
943 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
946 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
948 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
951 stub.length -= length;
952 } while (stub.length != 0);
954 /* move the call from the pending to the finished calls list */
955 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
957 if (call->conn->call_list && call->conn->call_list->replies) {
958 if (call->conn->transport.report_output_data) {
959 call->conn->transport.report_output_data(call->conn);
966 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
968 if (!conn->transport.get_my_addr) {
972 return conn->transport.get_my_addr(conn, mem_ctx);
975 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
977 if (!conn->transport.get_peer_addr) {
981 return conn->transport.get_peer_addr(conn, mem_ctx);
985 work out if we have a full packet yet
987 static bool dce_full_packet(const DATA_BLOB *data)
989 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
992 if (dcerpc_get_frag_length(data) > data->length) {
999 we might have consumed only part of our input - advance past that part
1001 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
1005 if (dce_conn->partial_input.length == offset) {
1006 data_blob_free(&dce_conn->partial_input);
1010 blob = dce_conn->partial_input;
1011 dce_conn->partial_input = data_blob(blob.data + offset,
1012 blob.length - offset);
1013 data_blob_free(&blob);
1017 remove the call from the right list when freed
1019 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1021 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1026 process some input to a dcerpc endpoint server.
1028 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
1030 struct ndr_pull *ndr;
1031 enum ndr_err_code ndr_err;
1033 struct dcesrv_call_state *call;
1036 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1038 talloc_free(dce_conn->partial_input.data);
1039 return NT_STATUS_NO_MEMORY;
1041 call->conn = dce_conn;
1042 call->event_ctx = dce_conn->event_ctx;
1043 call->msg_ctx = dce_conn->msg_ctx;
1044 call->state_flags = call->conn->state_flags;
1045 call->time = timeval_current();
1046 call->list = DCESRV_LIST_NONE;
1048 talloc_set_destructor(call, dcesrv_call_dequeue);
1050 blob = dce_conn->partial_input;
1051 blob.length = dcerpc_get_frag_length(&blob);
1053 ndr = ndr_pull_init_blob(&blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
1055 talloc_free(dce_conn->partial_input.data);
1057 return NT_STATUS_NO_MEMORY;
1060 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
1061 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
1064 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
1065 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1066 talloc_free(dce_conn->partial_input.data);
1068 return ndr_map_error2ntstatus(ndr_err);
1071 /* we have to check the signing here, before combining the
1073 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1074 !dcesrv_auth_request(call, &blob)) {
1075 dce_partial_advance(dce_conn, blob.length);
1076 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1079 dce_partial_advance(dce_conn, blob.length);
1081 /* see if this is a continued packet */
1082 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1083 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1084 struct dcesrv_call_state *call2 = call;
1085 uint32_t alloc_size;
1087 /* we only allow fragmented requests, no other packet types */
1088 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1089 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1092 /* this is a continuation of an existing call - find the call then
1093 tack it on the end */
1094 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1096 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1099 if (call->pkt.ptype != call2->pkt.ptype) {
1100 /* trying to play silly buggers are we? */
1101 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1104 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1105 call2->pkt.u.request.stub_and_verifier.length;
1106 if (call->pkt.u.request.alloc_hint > alloc_size) {
1107 alloc_size = call->pkt.u.request.alloc_hint;
1110 call->pkt.u.request.stub_and_verifier.data =
1111 talloc_realloc(call,
1112 call->pkt.u.request.stub_and_verifier.data,
1113 uint8_t, alloc_size);
1114 if (!call->pkt.u.request.stub_and_verifier.data) {
1115 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1117 memcpy(call->pkt.u.request.stub_and_verifier.data +
1118 call->pkt.u.request.stub_and_verifier.length,
1119 call2->pkt.u.request.stub_and_verifier.data,
1120 call2->pkt.u.request.stub_and_verifier.length);
1121 call->pkt.u.request.stub_and_verifier.length +=
1122 call2->pkt.u.request.stub_and_verifier.length;
1124 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1129 /* this may not be the last pdu in the chain - if its isn't then
1130 just put it on the incoming_fragmented_call_list and wait for the rest */
1131 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1132 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1133 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1134 return NT_STATUS_OK;
1137 /* This removes any fragments we may have had stashed away */
1138 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1140 switch (call->pkt.ptype) {
1141 case DCERPC_PKT_BIND:
1142 status = dcesrv_bind(call);
1144 case DCERPC_PKT_AUTH3:
1145 status = dcesrv_auth3(call);
1147 case DCERPC_PKT_ALTER:
1148 status = dcesrv_alter(call);
1150 case DCERPC_PKT_REQUEST:
1151 status = dcesrv_request(call);
1154 status = NT_STATUS_INVALID_PARAMETER;
1158 /* if we are going to be sending a reply then add
1159 it to the list of pending calls. We add it to the end to keep the call
1160 list in the order we will answer */
1161 if (!NT_STATUS_IS_OK(status)) {
1170 provide some input to a dcerpc endpoint server. This passes data
1171 from a dcerpc client into the server
1173 _PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1177 dce_conn->partial_input.data = talloc_realloc(dce_conn,
1178 dce_conn->partial_input.data,
1180 dce_conn->partial_input.length + data->length);
1181 if (!dce_conn->partial_input.data) {
1182 return NT_STATUS_NO_MEMORY;
1184 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1185 data->data, data->length);
1186 dce_conn->partial_input.length += data->length;
1188 while (dce_full_packet(&dce_conn->partial_input)) {
1189 status = dcesrv_input_process(dce_conn);
1190 if (!NT_STATUS_IS_OK(status)) {
1195 return NT_STATUS_OK;
1199 retrieve some output from a dcerpc server
1200 The caller supplies a function that will be called to do the
1203 The first argument to write_fn() will be 'private', the second will
1204 be a pointer to a buffer containing the data to be sent and the 3rd
1205 will be a pointer to a size_t variable that will be set to the
1206 number of bytes that are consumed from the output.
1208 from the current fragment
1210 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
1212 NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1215 struct dcesrv_call_state *call;
1216 struct data_blob_list_item *rep;
1219 call = dce_conn->call_list;
1220 if (!call || !call->replies) {
1221 if (dce_conn->pending_call_list) {
1222 /* TODO: we need to say act async here
1223 * as we know we have pending requests
1224 * which will be finished at a time
1226 return NT_STATUS_FOOBAR;
1228 return NT_STATUS_FOOBAR;
1230 rep = call->replies;
1232 status = write_fn(private_data, &rep->blob, &nwritten);
1233 NT_STATUS_IS_ERR_RETURN(status);
1235 rep->blob.length -= nwritten;
1236 rep->blob.data += nwritten;
1238 if (rep->blob.length == 0) {
1239 /* we're done with this section of the call */
1240 DLIST_REMOVE(call->replies, rep);
1243 if (call->replies == NULL) {
1244 /* we're done with the whole call */
1245 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1252 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1253 struct loadparm_context *lp_ctx,
1254 const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1257 struct dcesrv_context *dce_ctx;
1260 if (!endpoint_servers) {
1261 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1262 return NT_STATUS_INTERNAL_ERROR;
1265 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1266 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1267 dce_ctx->endpoint_list = NULL;
1268 dce_ctx->lp_ctx = lp_ctx;
1270 for (i=0;endpoint_servers[i];i++) {
1271 const struct dcesrv_endpoint_server *ep_server;
1273 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1275 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1276 return NT_STATUS_INTERNAL_ERROR;
1279 status = ep_server->init_server(dce_ctx, ep_server);
1280 if (!NT_STATUS_IS_OK(status)) {
1281 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1282 nt_errstr(status)));
1287 *_dce_ctx = dce_ctx;
1288 return NT_STATUS_OK;
1291 /* the list of currently registered DCERPC endpoint servers.
1293 static struct ep_server {
1294 struct dcesrv_endpoint_server *ep_server;
1295 } *ep_servers = NULL;
1296 static int num_ep_servers;
1299 register a DCERPC endpoint server.
1301 The 'name' can be later used by other backends to find the operations
1302 structure for this backend.
1304 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1306 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1308 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1310 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1311 /* its already registered! */
1312 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1314 return NT_STATUS_OBJECT_NAME_COLLISION;
1317 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1319 smb_panic("out of memory in dcerpc_register");
1322 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1323 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1327 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1330 return NT_STATUS_OK;
1334 return the operations structure for a named backend of the specified type
1336 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1340 for (i=0;i<num_ep_servers;i++) {
1341 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1342 return ep_servers[i].ep_server;
1350 return the DCERPC module version, and the size of some critical types
1351 This can be used by endpoint server modules to either detect compilation errors, or provide
1352 multiple implementations for different smbd compilation options in one module
1354 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1356 static const struct dcesrv_critical_sizes critical_sizes = {
1357 DCERPC_MODULE_VERSION,
1358 sizeof(struct dcesrv_context),
1359 sizeof(struct dcesrv_endpoint),
1360 sizeof(struct dcesrv_endpoint_server),
1361 sizeof(struct dcesrv_interface),
1362 sizeof(struct dcesrv_if_list),
1363 sizeof(struct dcesrv_connection),
1364 sizeof(struct dcesrv_call_state),
1365 sizeof(struct dcesrv_auth),
1366 sizeof(struct dcesrv_handle)
1369 return &critical_sizes;
1373 initialise the dcerpc server context for ncacn_np based services
1375 _PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
1376 struct dcesrv_context **_dce_ctx)
1379 struct dcesrv_context *dce_ctx;
1381 status = dcesrv_init_context(mem_ctx, lp_ctx, lp_dcerpc_endpoint_servers(lp_ctx), &dce_ctx);
1382 NT_STATUS_NOT_OK_RETURN(status);
1384 *_dce_ctx = dce_ctx;
1385 return NT_STATUS_OK;