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"
38 #include "param/param.h"
40 extern const struct dcesrv_interface dcesrv_mgmt_interface;
43 see if two endpoints match
45 static bool endpoints_match(const struct dcerpc_binding *ep1,
46 const struct dcerpc_binding *ep2)
48 if (ep1->transport != ep2->transport) {
52 if (!ep1->endpoint || !ep2->endpoint) {
53 return ep1->endpoint == ep2->endpoint;
56 if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
63 find an endpoint in the dcesrv_context
65 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
66 const struct dcerpc_binding *ep_description)
68 struct dcesrv_endpoint *ep;
69 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
70 if (endpoints_match(ep->ep_description, ep_description)) {
78 find a registered context_id from a bind or alter_context
80 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn,
83 struct dcesrv_connection_context *c;
84 for (c=conn->contexts;c;c=c->next) {
85 if (c->context_id == context_id) return c;
91 see if a uuid and if_version match to an interface
93 static bool interface_match(const struct dcesrv_interface *if1,
94 const struct dcesrv_interface *if2)
96 return (if1->syntax_id.if_version == if2->syntax_id.if_version &&
97 GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
101 find the interface operations on an endpoint
103 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
104 const struct dcesrv_interface *iface)
106 struct dcesrv_if_list *ifl;
107 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
108 if (interface_match(&(ifl->iface), iface)) {
109 return &(ifl->iface);
116 see if a uuid and if_version match to an interface
118 static bool interface_match_by_uuid(const struct dcesrv_interface *iface,
119 const struct GUID *uuid, uint32_t if_version)
121 return (iface->syntax_id.if_version == if_version &&
122 GUID_equal(&iface->syntax_id.uuid, uuid));
126 find the interface operations on an endpoint by uuid
128 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
129 const struct GUID *uuid, uint32_t if_version)
131 struct dcesrv_if_list *ifl;
132 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
133 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
134 return &(ifl->iface);
141 find the earlier parts of a fragmented call awaiting reassembily
143 static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
145 struct dcesrv_call_state *c;
146 for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
147 if (c->pkt.call_id == call_id) {
155 register an interface on an endpoint
157 _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
159 const struct dcesrv_interface *iface,
160 const struct security_descriptor *sd)
162 struct dcesrv_endpoint *ep;
163 struct dcesrv_if_list *ifl;
164 struct dcerpc_binding *binding;
168 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
170 if (NT_STATUS_IS_ERR(status)) {
171 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
175 /* check if this endpoint exists
177 if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
178 ep = talloc(dce_ctx, struct dcesrv_endpoint);
180 return NT_STATUS_NO_MEMORY;
183 ep->ep_description = talloc_reference(ep, binding);
186 /* add mgmt interface */
187 ifl = talloc(dce_ctx, struct dcesrv_if_list);
189 return NT_STATUS_NO_MEMORY;
192 memcpy(&(ifl->iface), &dcesrv_mgmt_interface,
193 sizeof(struct dcesrv_interface));
195 DLIST_ADD(ep->interface_list, ifl);
198 /* see if the interface is already registered on te endpoint */
199 if (find_interface(ep, iface)!=NULL) {
200 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
201 iface->name, ep_name));
202 return NT_STATUS_OBJECT_NAME_COLLISION;
205 /* talloc a new interface list element */
206 ifl = talloc(dce_ctx, struct dcesrv_if_list);
208 return NT_STATUS_NO_MEMORY;
211 /* copy the given interface struct to the one on the endpoints interface list */
212 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
214 /* if we have a security descriptor given,
215 * we should see if we can set it up on the endpoint
218 /* if there's currently no security descriptor given on the endpoint
221 if (ep->sd == NULL) {
222 ep->sd = security_descriptor_copy(dce_ctx, sd);
225 /* if now there's no security descriptor given on the endpoint
226 * something goes wrong, either we failed to copy the security descriptor
227 * or there was already one on the endpoint
229 if (ep->sd != NULL) {
230 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
231 " on endpoint '%s'\n",
232 iface->name, ep_name));
233 if (add_ep) free(ep);
235 return NT_STATUS_OBJECT_NAME_COLLISION;
239 /* finally add the interface on the endpoint */
240 DLIST_ADD(ep->interface_list, ifl);
242 /* if it's a new endpoint add it to the dcesrv_context */
244 DLIST_ADD(dce_ctx->endpoint_list, ep);
247 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
248 iface->name, ep_name));
253 static NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
254 DATA_BLOB *session_key)
256 if (p->auth_state.session_info->session_key.length) {
257 *session_key = p->auth_state.session_info->session_key;
260 return NT_STATUS_NO_USER_SESSION_KEY;
263 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
264 DATA_BLOB *session_key)
266 /* this took quite a few CPU cycles to find ... */
267 session_key->data = discard_const_p(uint8_t, "SystemLibraryDTC");
268 session_key->length = 16;
273 fetch the user session key - may be default (above) or the SMB session key
275 _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
276 DATA_BLOB *session_key)
278 return p->auth_state.session_key(p, session_key);
283 destroy a link to an endpoint
285 static int dcesrv_endpoint_destructor(struct dcesrv_connection *p)
287 while (p->contexts) {
288 struct dcesrv_connection_context *c = p->contexts;
290 DLIST_REMOVE(p->contexts, c);
293 c->iface->unbind(c, c->iface);
302 connect to a dcerpc endpoint
304 _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
306 const struct dcesrv_endpoint *ep,
307 struct auth_session_info *session_info,
308 struct event_context *event_ctx,
309 struct messaging_context *msg_ctx,
310 struct server_id server_id,
311 uint32_t state_flags,
312 struct dcesrv_connection **_p)
314 struct dcesrv_connection *p;
317 return NT_STATUS_ACCESS_DENIED;
320 p = talloc(mem_ctx, struct dcesrv_connection);
321 NT_STATUS_HAVE_NO_MEMORY(p);
323 if (!talloc_reference(p, session_info)) {
325 return NT_STATUS_NO_MEMORY;
328 p->dce_ctx = dce_ctx;
332 p->incoming_fragmented_call_list = NULL;
333 p->pending_call_list = NULL;
334 p->cli_max_recv_frag = 0;
335 p->partial_input = data_blob(NULL, 0);
336 p->auth_state.auth_info = NULL;
337 p->auth_state.gensec_security = NULL;
338 p->auth_state.session_info = session_info;
339 p->auth_state.session_key = dcesrv_generic_session_key;
340 p->event_ctx = event_ctx;
341 p->msg_ctx = msg_ctx;
342 p->server_id = server_id;
343 p->processing = false;
344 p->state_flags = state_flags;
345 ZERO_STRUCT(p->transport);
347 talloc_set_destructor(p, dcesrv_endpoint_destructor);
354 search and connect to a dcerpc endpoint
356 _PUBLIC_ NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
358 const struct dcerpc_binding *ep_description,
359 struct auth_session_info *session_info,
360 struct event_context *event_ctx,
361 struct messaging_context *msg_ctx,
362 struct server_id server_id,
363 uint32_t state_flags,
364 struct dcesrv_connection **dce_conn_p)
367 const struct dcesrv_endpoint *ep;
369 /* make sure this endpoint exists */
370 ep = find_endpoint(dce_ctx, ep_description);
372 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
375 status = dcesrv_endpoint_connect(dce_ctx, mem_ctx, ep, session_info,
376 event_ctx, msg_ctx, server_id,
377 state_flags, dce_conn_p);
378 NT_STATUS_NOT_OK_RETURN(status);
380 (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
382 /* TODO: check security descriptor of the endpoint here
383 * if it's a smb named pipe
384 * if it's failed free dce_conn_p
391 static void dcesrv_init_hdr(struct ncacn_packet *pkt, bool bigendian)
394 pkt->rpc_vers_minor = 0;
398 pkt->drep[0] = DCERPC_DREP_LE;
406 move a call from an existing linked list to the specified list. This
407 prevents bugs where we forget to remove the call from a previous
410 static void dcesrv_call_set_list(struct dcesrv_call_state *call,
411 enum dcesrv_call_list list)
413 switch (call->list) {
414 case DCESRV_LIST_NONE:
416 case DCESRV_LIST_CALL_LIST:
417 DLIST_REMOVE(call->conn->call_list, call);
419 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
420 DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
422 case DCESRV_LIST_PENDING_CALL_LIST:
423 DLIST_REMOVE(call->conn->pending_call_list, call);
428 case DCESRV_LIST_NONE:
430 case DCESRV_LIST_CALL_LIST:
431 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
433 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
434 DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
436 case DCESRV_LIST_PENDING_CALL_LIST:
437 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
443 return a dcerpc fault
445 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
447 struct ncacn_packet pkt;
448 struct data_blob_list_item *rep;
451 /* setup a bind_ack */
452 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
454 pkt.call_id = call->pkt.call_id;
455 pkt.ptype = DCERPC_PKT_FAULT;
456 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
457 pkt.u.fault.alloc_hint = 0;
458 pkt.u.fault.context_id = 0;
459 pkt.u.fault.cancel_count = 0;
460 pkt.u.fault.status = fault_code;
462 rep = talloc(call, struct data_blob_list_item);
464 return NT_STATUS_NO_MEMORY;
467 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
468 if (!NT_STATUS_IS_OK(status)) {
472 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
474 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
475 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
482 return a dcerpc bind_nak
484 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
486 struct ncacn_packet pkt;
487 struct data_blob_list_item *rep;
490 /* setup a bind_nak */
491 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
493 pkt.call_id = call->pkt.call_id;
494 pkt.ptype = DCERPC_PKT_BIND_NAK;
495 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
496 pkt.u.bind_nak.reject_reason = reason;
497 if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
498 pkt.u.bind_nak.versions.v.num_versions = 0;
501 rep = talloc(call, struct data_blob_list_item);
503 return NT_STATUS_NO_MEMORY;
506 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
507 if (!NT_STATUS_IS_OK(status)) {
511 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
513 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
514 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
521 handle a bind request
523 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
525 uint32_t if_version, transfer_syntax_version;
526 struct GUID uuid, *transfer_syntax_uuid;
527 struct ncacn_packet pkt;
528 struct data_blob_list_item *rep;
530 uint32_t result=0, reason=0;
532 const struct dcesrv_interface *iface;
534 if (call->pkt.u.bind.assoc_group_id != 0) {
535 return dcesrv_bind_nak(call, 0);
538 if (call->pkt.u.bind.num_contexts < 1 ||
539 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
540 return dcesrv_bind_nak(call, 0);
543 context_id = call->pkt.u.bind.ctx_list[0].context_id;
545 /* you can't bind twice on one context */
546 if (dcesrv_find_context(call->conn, context_id) != NULL) {
547 return dcesrv_bind_nak(call, 0);
550 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
551 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
553 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
554 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
555 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
556 ndr_transfer_syntax.if_version != transfer_syntax_version) {
557 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
558 /* we only do NDR encoded dcerpc */
559 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
560 talloc_free(uuid_str);
561 return dcesrv_bind_nak(call, 0);
564 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
566 char *uuid_str = GUID_string(call, &uuid);
567 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
568 talloc_free(uuid_str);
570 /* we don't know about that interface */
571 result = DCERPC_BIND_PROVIDER_REJECT;
572 reason = DCERPC_BIND_REASON_ASYNTAX;
576 /* add this context to the list of available context_ids */
577 struct dcesrv_connection_context *context = talloc(call->conn,
578 struct dcesrv_connection_context);
579 if (context == NULL) {
580 return dcesrv_bind_nak(call, 0);
582 context->conn = call->conn;
583 context->iface = iface;
584 context->context_id = context_id;
585 context->private = NULL;
586 context->handles = NULL;
587 DLIST_ADD(call->conn->contexts, context);
588 call->context = context;
591 if (call->conn->cli_max_recv_frag == 0) {
592 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
595 /* handle any authentication that is being requested */
596 if (!dcesrv_auth_bind(call)) {
597 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
600 /* setup a bind_ack */
601 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
603 pkt.call_id = call->pkt.call_id;
604 pkt.ptype = DCERPC_PKT_BIND_ACK;
605 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
606 pkt.u.bind_ack.max_xmit_frag = 0x2000;
607 pkt.u.bind_ack.max_recv_frag = 0x2000;
608 /* we need to send a non zero assoc_group_id here to make longhorn happy, it also matches samba3 */
609 pkt.u.bind_ack.assoc_group_id = 0x12345678;
611 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
612 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
614 pkt.u.bind_ack.secondary_address = "";
616 pkt.u.bind_ack.num_results = 1;
617 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
618 if (!pkt.u.bind_ack.ctx_list) {
619 return NT_STATUS_NO_MEMORY;
621 pkt.u.bind_ack.ctx_list[0].result = result;
622 pkt.u.bind_ack.ctx_list[0].reason = reason;
623 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
624 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
626 status = dcesrv_auth_bind_ack(call, &pkt);
627 if (!NT_STATUS_IS_OK(status)) {
628 return dcesrv_bind_nak(call, 0);
632 status = iface->bind(call, iface);
633 if (!NT_STATUS_IS_OK(status)) {
634 char *uuid_str = GUID_string(call, &uuid);
635 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
636 uuid_str, if_version, nt_errstr(status)));
637 talloc_free(uuid_str);
638 return dcesrv_bind_nak(call, 0);
642 rep = talloc(call, struct data_blob_list_item);
644 return NT_STATUS_NO_MEMORY;
647 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
648 if (!NT_STATUS_IS_OK(status)) {
652 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
654 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
655 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
662 handle a auth3 request
664 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
666 /* handle the auth3 in the auth code */
667 if (!dcesrv_auth_auth3(call)) {
668 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
673 /* we don't send a reply to a auth3 request, except by a
680 handle a bind request
682 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
684 uint32_t if_version, transfer_syntax_version;
685 struct dcesrv_connection_context *context;
686 const struct dcesrv_interface *iface;
687 struct GUID uuid, *transfer_syntax_uuid;
689 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
690 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
692 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
693 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
694 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
695 ndr_transfer_syntax.if_version != transfer_syntax_version) {
696 /* we only do NDR encoded dcerpc */
697 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
700 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
702 char *uuid_str = GUID_string(call, &uuid);
703 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
704 talloc_free(uuid_str);
705 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
708 /* add this context to the list of available context_ids */
709 context = talloc(call->conn, struct dcesrv_connection_context);
710 if (context == NULL) {
711 return NT_STATUS_NO_MEMORY;
713 context->conn = call->conn;
714 context->iface = iface;
715 context->context_id = context_id;
716 context->private = NULL;
717 context->handles = NULL;
718 DLIST_ADD(call->conn->contexts, context);
719 call->context = context;
726 handle a alter context request
728 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
730 struct ncacn_packet pkt;
731 struct data_blob_list_item *rep;
733 uint32_t result=0, reason=0;
736 /* handle any authentication that is being requested */
737 if (!dcesrv_auth_alter(call)) {
738 /* TODO: work out the right reject code */
739 result = DCERPC_BIND_PROVIDER_REJECT;
740 reason = DCERPC_BIND_REASON_ASYNTAX;
743 context_id = call->pkt.u.alter.ctx_list[0].context_id;
745 /* see if they are asking for a new interface */
747 dcesrv_find_context(call->conn, context_id) == NULL) {
748 status = dcesrv_alter_new_context(call, context_id);
749 if (!NT_STATUS_IS_OK(status)) {
750 result = DCERPC_BIND_PROVIDER_REJECT;
751 reason = DCERPC_BIND_REASON_ASYNTAX;
755 /* setup a alter_resp */
756 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
758 pkt.call_id = call->pkt.call_id;
759 pkt.ptype = DCERPC_PKT_ALTER_RESP;
760 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
761 pkt.u.alter_resp.max_xmit_frag = 0x2000;
762 pkt.u.alter_resp.max_recv_frag = 0x2000;
763 pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
764 pkt.u.alter_resp.num_results = 1;
765 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
766 if (!pkt.u.alter_resp.ctx_list) {
767 return NT_STATUS_NO_MEMORY;
769 pkt.u.alter_resp.ctx_list[0].result = result;
770 pkt.u.alter_resp.ctx_list[0].reason = reason;
771 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
772 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
773 pkt.u.alter_resp.secondary_address = "";
775 status = dcesrv_auth_alter_ack(call, &pkt);
776 if (!NT_STATUS_IS_OK(status)) {
777 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
778 || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
779 || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
780 || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
781 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
783 return dcesrv_fault(call, 0);
786 rep = talloc(call, struct data_blob_list_item);
788 return NT_STATUS_NO_MEMORY;
791 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, 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;