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"
35 #include "param/param.h"
37 extern const struct dcesrv_interface dcesrv_mgmt_interface;
40 see if two endpoints match
42 static bool endpoints_match(const struct dcerpc_binding *ep1,
43 const struct dcerpc_binding *ep2)
45 if (ep1->transport != ep2->transport) {
49 if (!ep1->endpoint || !ep2->endpoint) {
50 return ep1->endpoint == ep2->endpoint;
53 if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
60 find an endpoint in the dcesrv_context
62 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
63 const struct dcerpc_binding *ep_description)
65 struct dcesrv_endpoint *ep;
66 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
67 if (endpoints_match(ep->ep_description, ep_description)) {
75 find a registered context_id from a bind or alter_context
77 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn,
80 struct dcesrv_connection_context *c;
81 for (c=conn->contexts;c;c=c->next) {
82 if (c->context_id == context_id) return c;
88 see if a uuid and if_version match to an interface
90 static bool interface_match(const struct dcesrv_interface *if1,
91 const struct dcesrv_interface *if2)
93 return (if1->syntax_id.if_version == if2->syntax_id.if_version &&
94 GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
98 find the interface operations on an endpoint
100 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
101 const struct dcesrv_interface *iface)
103 struct dcesrv_if_list *ifl;
104 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
105 if (interface_match(&(ifl->iface), iface)) {
106 return &(ifl->iface);
113 see if a uuid and if_version match to an interface
115 static bool interface_match_by_uuid(const struct dcesrv_interface *iface,
116 const struct GUID *uuid, uint32_t if_version)
118 return (iface->syntax_id.if_version == if_version &&
119 GUID_equal(&iface->syntax_id.uuid, uuid));
123 find the interface operations on an endpoint by uuid
125 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
126 const struct GUID *uuid, uint32_t if_version)
128 struct dcesrv_if_list *ifl;
129 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
130 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
131 return &(ifl->iface);
138 find the earlier parts of a fragmented call awaiting reassembily
140 static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
142 struct dcesrv_call_state *c;
143 for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
144 if (c->pkt.call_id == call_id) {
152 register an interface on an endpoint
154 _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
156 const struct dcesrv_interface *iface,
157 const struct security_descriptor *sd)
159 struct dcesrv_endpoint *ep;
160 struct dcesrv_if_list *ifl;
161 struct dcerpc_binding *binding;
165 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
167 if (NT_STATUS_IS_ERR(status)) {
168 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
172 /* check if this endpoint exists
174 if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
175 ep = talloc(dce_ctx, struct dcesrv_endpoint);
177 return NT_STATUS_NO_MEMORY;
180 ep->ep_description = talloc_reference(ep, binding);
183 /* add mgmt interface */
184 ifl = talloc(dce_ctx, struct dcesrv_if_list);
186 return NT_STATUS_NO_MEMORY;
189 memcpy(&(ifl->iface), &dcesrv_mgmt_interface,
190 sizeof(struct dcesrv_interface));
192 DLIST_ADD(ep->interface_list, ifl);
195 /* see if the interface is already registered on te endpoint */
196 if (find_interface(ep, iface)!=NULL) {
197 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
198 iface->name, ep_name));
199 return NT_STATUS_OBJECT_NAME_COLLISION;
202 /* talloc a new interface list element */
203 ifl = talloc(dce_ctx, struct dcesrv_if_list);
205 return NT_STATUS_NO_MEMORY;
208 /* copy the given interface struct to the one on the endpoints interface list */
209 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
211 /* if we have a security descriptor given,
212 * we should see if we can set it up on the endpoint
215 /* if there's currently no security descriptor given on the endpoint
218 if (ep->sd == NULL) {
219 ep->sd = security_descriptor_copy(dce_ctx, sd);
222 /* if now there's no security descriptor given on the endpoint
223 * something goes wrong, either we failed to copy the security descriptor
224 * or there was already one on the endpoint
226 if (ep->sd != NULL) {
227 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
228 " on endpoint '%s'\n",
229 iface->name, ep_name));
230 if (add_ep) free(ep);
232 return NT_STATUS_OBJECT_NAME_COLLISION;
236 /* finally add the interface on the endpoint */
237 DLIST_ADD(ep->interface_list, ifl);
239 /* if it's a new endpoint add it to the dcesrv_context */
241 DLIST_ADD(dce_ctx->endpoint_list, ep);
244 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
245 iface->name, ep_name));
250 static NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
251 DATA_BLOB *session_key)
253 if (p->auth_state.session_info->session_key.length) {
254 *session_key = p->auth_state.session_info->session_key;
257 return NT_STATUS_NO_USER_SESSION_KEY;
260 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
261 DATA_BLOB *session_key)
263 /* this took quite a few CPU cycles to find ... */
264 session_key->data = discard_const_p(uint8_t, "SystemLibraryDTC");
265 session_key->length = 16;
270 fetch the user session key - may be default (above) or the SMB session key
272 _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
273 DATA_BLOB *session_key)
275 return p->auth_state.session_key(p, session_key);
280 destroy a link to an endpoint
282 static int dcesrv_endpoint_destructor(struct dcesrv_connection *p)
284 while (p->contexts) {
285 struct dcesrv_connection_context *c = p->contexts;
287 DLIST_REMOVE(p->contexts, c);
290 c->iface->unbind(c, c->iface);
299 connect to a dcerpc endpoint
301 NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
303 const struct dcesrv_endpoint *ep,
304 struct auth_session_info *session_info,
305 struct event_context *event_ctx,
306 struct messaging_context *msg_ctx,
307 struct server_id server_id,
308 uint32_t state_flags,
309 struct dcesrv_connection **_p)
311 struct dcesrv_connection *p;
314 return NT_STATUS_ACCESS_DENIED;
317 p = talloc(mem_ctx, struct dcesrv_connection);
318 NT_STATUS_HAVE_NO_MEMORY(p);
320 if (!talloc_reference(p, session_info)) {
322 return NT_STATUS_NO_MEMORY;
325 p->dce_ctx = dce_ctx;
329 p->incoming_fragmented_call_list = NULL;
330 p->pending_call_list = NULL;
331 p->cli_max_recv_frag = 0;
332 p->partial_input = data_blob(NULL, 0);
333 p->auth_state.auth_info = NULL;
334 p->auth_state.gensec_security = NULL;
335 p->auth_state.session_info = session_info;
336 p->auth_state.session_key = dcesrv_generic_session_key;
337 p->event_ctx = event_ctx;
338 p->msg_ctx = msg_ctx;
339 p->server_id = server_id;
340 p->processing = false;
341 p->state_flags = state_flags;
342 ZERO_STRUCT(p->transport);
344 talloc_set_destructor(p, dcesrv_endpoint_destructor);
351 search and connect to a dcerpc endpoint
353 _PUBLIC_ NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
355 const struct dcerpc_binding *ep_description,
356 struct auth_session_info *session_info,
357 struct event_context *event_ctx,
358 struct messaging_context *msg_ctx,
359 struct server_id server_id,
360 uint32_t state_flags,
361 struct dcesrv_connection **dce_conn_p)
364 const struct dcesrv_endpoint *ep;
366 /* make sure this endpoint exists */
367 ep = find_endpoint(dce_ctx, ep_description);
369 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
372 status = dcesrv_endpoint_connect(dce_ctx, mem_ctx, ep, session_info,
373 event_ctx, msg_ctx, server_id,
374 state_flags, dce_conn_p);
375 NT_STATUS_NOT_OK_RETURN(status);
377 (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
379 /* TODO: check security descriptor of the endpoint here
380 * if it's a smb named pipe
381 * if it's failed free dce_conn_p
388 static void dcesrv_init_hdr(struct ncacn_packet *pkt, bool bigendian)
391 pkt->rpc_vers_minor = 0;
395 pkt->drep[0] = DCERPC_DREP_LE;
403 move a call from an existing linked list to the specified list. This
404 prevents bugs where we forget to remove the call from a previous
407 static void dcesrv_call_set_list(struct dcesrv_call_state *call,
408 enum dcesrv_call_list list)
410 switch (call->list) {
411 case DCESRV_LIST_NONE:
413 case DCESRV_LIST_CALL_LIST:
414 DLIST_REMOVE(call->conn->call_list, call);
416 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
417 DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
419 case DCESRV_LIST_PENDING_CALL_LIST:
420 DLIST_REMOVE(call->conn->pending_call_list, call);
425 case DCESRV_LIST_NONE:
427 case DCESRV_LIST_CALL_LIST:
428 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
430 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
431 DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
433 case DCESRV_LIST_PENDING_CALL_LIST:
434 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
440 return a dcerpc fault
442 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
444 struct ncacn_packet pkt;
445 struct data_blob_list_item *rep;
448 /* setup a bind_ack */
449 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
451 pkt.call_id = call->pkt.call_id;
452 pkt.ptype = DCERPC_PKT_FAULT;
453 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
454 pkt.u.fault.alloc_hint = 0;
455 pkt.u.fault.context_id = 0;
456 pkt.u.fault.cancel_count = 0;
457 pkt.u.fault.status = fault_code;
459 rep = talloc(call, struct data_blob_list_item);
461 return NT_STATUS_NO_MEMORY;
464 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
465 if (!NT_STATUS_IS_OK(status)) {
469 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
471 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
472 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
479 return a dcerpc bind_nak
481 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
483 struct ncacn_packet pkt;
484 struct data_blob_list_item *rep;
487 /* setup a bind_nak */
488 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
490 pkt.call_id = call->pkt.call_id;
491 pkt.ptype = DCERPC_PKT_BIND_NAK;
492 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
493 pkt.u.bind_nak.reject_reason = reason;
494 if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
495 pkt.u.bind_nak.versions.v.num_versions = 0;
498 rep = talloc(call, struct data_blob_list_item);
500 return NT_STATUS_NO_MEMORY;
503 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
504 if (!NT_STATUS_IS_OK(status)) {
508 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
510 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
511 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
518 handle a bind request
520 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
522 uint32_t if_version, transfer_syntax_version;
523 struct GUID uuid, *transfer_syntax_uuid;
524 struct ncacn_packet pkt;
525 struct data_blob_list_item *rep;
527 uint32_t result=0, reason=0;
529 const struct dcesrv_interface *iface;
531 if (call->pkt.u.bind.assoc_group_id != 0) {
532 return dcesrv_bind_nak(call, 0);
535 if (call->pkt.u.bind.num_contexts < 1 ||
536 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
537 return dcesrv_bind_nak(call, 0);
540 context_id = call->pkt.u.bind.ctx_list[0].context_id;
542 /* you can't bind twice on one context */
543 if (dcesrv_find_context(call->conn, context_id) != NULL) {
544 return dcesrv_bind_nak(call, 0);
547 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
548 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
550 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
551 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
552 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
553 ndr_transfer_syntax.if_version != transfer_syntax_version) {
554 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
555 /* we only do NDR encoded dcerpc */
556 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
557 talloc_free(uuid_str);
558 return dcesrv_bind_nak(call, 0);
561 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
563 char *uuid_str = GUID_string(call, &uuid);
564 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
565 talloc_free(uuid_str);
567 /* we don't know about that interface */
568 result = DCERPC_BIND_PROVIDER_REJECT;
569 reason = DCERPC_BIND_REASON_ASYNTAX;
573 /* add this context to the list of available context_ids */
574 struct dcesrv_connection_context *context = talloc(call->conn,
575 struct dcesrv_connection_context);
576 if (context == NULL) {
577 return dcesrv_bind_nak(call, 0);
579 context->conn = call->conn;
580 context->iface = iface;
581 context->context_id = context_id;
582 context->private = NULL;
583 context->handles = NULL;
584 DLIST_ADD(call->conn->contexts, context);
585 call->context = context;
588 if (call->conn->cli_max_recv_frag == 0) {
589 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
592 /* handle any authentication that is being requested */
593 if (!dcesrv_auth_bind(call)) {
594 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
597 /* setup a bind_ack */
598 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
600 pkt.call_id = call->pkt.call_id;
601 pkt.ptype = DCERPC_PKT_BIND_ACK;
602 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
603 pkt.u.bind_ack.max_xmit_frag = 0x2000;
604 pkt.u.bind_ack.max_recv_frag = 0x2000;
605 /* we need to send a non zero assoc_group_id here to make longhorn happy, it also matches samba3 */
606 pkt.u.bind_ack.assoc_group_id = 0x12345678;
608 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
609 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
611 pkt.u.bind_ack.secondary_address = "";
613 pkt.u.bind_ack.num_results = 1;
614 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
615 if (!pkt.u.bind_ack.ctx_list) {
616 return NT_STATUS_NO_MEMORY;
618 pkt.u.bind_ack.ctx_list[0].result = result;
619 pkt.u.bind_ack.ctx_list[0].reason = reason;
620 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
621 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
623 status = dcesrv_auth_bind_ack(call, &pkt);
624 if (!NT_STATUS_IS_OK(status)) {
625 return dcesrv_bind_nak(call, 0);
629 status = iface->bind(call, iface);
630 if (!NT_STATUS_IS_OK(status)) {
631 char *uuid_str = GUID_string(call, &uuid);
632 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
633 uuid_str, if_version, nt_errstr(status)));
634 talloc_free(uuid_str);
635 return dcesrv_bind_nak(call, 0);
639 rep = talloc(call, struct data_blob_list_item);
641 return NT_STATUS_NO_MEMORY;
644 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
645 if (!NT_STATUS_IS_OK(status)) {
649 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
651 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
652 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
659 handle a auth3 request
661 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
663 /* handle the auth3 in the auth code */
664 if (!dcesrv_auth_auth3(call)) {
665 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
670 /* we don't send a reply to a auth3 request, except by a
677 handle a bind request
679 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
681 uint32_t if_version, transfer_syntax_version;
682 struct dcesrv_connection_context *context;
683 const struct dcesrv_interface *iface;
684 struct GUID uuid, *transfer_syntax_uuid;
686 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
687 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
689 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
690 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
691 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
692 ndr_transfer_syntax.if_version != transfer_syntax_version) {
693 /* we only do NDR encoded dcerpc */
694 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
697 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
699 char *uuid_str = GUID_string(call, &uuid);
700 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
701 talloc_free(uuid_str);
702 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
705 /* add this context to the list of available context_ids */
706 context = talloc(call->conn, struct dcesrv_connection_context);
707 if (context == NULL) {
708 return NT_STATUS_NO_MEMORY;
710 context->conn = call->conn;
711 context->iface = iface;
712 context->context_id = context_id;
713 context->private = NULL;
714 context->handles = NULL;
715 DLIST_ADD(call->conn->contexts, context);
716 call->context = context;
723 handle a alter context request
725 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
727 struct ncacn_packet pkt;
728 struct data_blob_list_item *rep;
730 uint32_t result=0, reason=0;
733 /* handle any authentication that is being requested */
734 if (!dcesrv_auth_alter(call)) {
735 /* TODO: work out the right reject code */
736 result = DCERPC_BIND_PROVIDER_REJECT;
737 reason = DCERPC_BIND_REASON_ASYNTAX;
740 context_id = call->pkt.u.alter.ctx_list[0].context_id;
742 /* see if they are asking for a new interface */
744 dcesrv_find_context(call->conn, context_id) == NULL) {
745 status = dcesrv_alter_new_context(call, context_id);
746 if (!NT_STATUS_IS_OK(status)) {
747 result = DCERPC_BIND_PROVIDER_REJECT;
748 reason = DCERPC_BIND_REASON_ASYNTAX;
752 /* setup a alter_resp */
753 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
755 pkt.call_id = call->pkt.call_id;
756 pkt.ptype = DCERPC_PKT_ALTER_RESP;
757 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
758 pkt.u.alter_resp.max_xmit_frag = 0x2000;
759 pkt.u.alter_resp.max_recv_frag = 0x2000;
760 pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
761 pkt.u.alter_resp.num_results = 1;
762 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
763 if (!pkt.u.alter_resp.ctx_list) {
764 return NT_STATUS_NO_MEMORY;
766 pkt.u.alter_resp.ctx_list[0].result = result;
767 pkt.u.alter_resp.ctx_list[0].reason = reason;
768 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
769 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
770 pkt.u.alter_resp.secondary_address = "";
772 status = dcesrv_auth_alter_ack(call, &pkt);
773 if (!NT_STATUS_IS_OK(status)) {
774 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
775 || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
776 || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
777 || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
778 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
780 return dcesrv_fault(call, 0);
783 rep = talloc(call, struct data_blob_list_item);
785 return NT_STATUS_NO_MEMORY;
788 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
789 if (!NT_STATUS_IS_OK(status)) {
793 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
795 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
796 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
802 handle a dcerpc request packet
804 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
806 struct ndr_pull *pull;
808 struct dcesrv_connection_context *context;
810 /* if authenticated, and the mech we use can't do async replies, don't use them... */
811 if (call->conn->auth_state.gensec_security &&
812 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
813 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
816 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
817 if (context == NULL) {
818 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
821 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call,
822 lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
823 NT_STATUS_HAVE_NO_MEMORY(pull);
825 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
827 call->context = context;
828 call->ndr_pull = pull;
830 if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
831 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
834 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
835 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
838 /* unravel the NDR for the packet */
839 status = context->iface->ndr_pull(call, call, pull, &call->r);
840 if (!NT_STATUS_IS_OK(status)) {
841 return dcesrv_fault(call, call->fault_code);
844 if (pull->offset != pull->data_size) {
845 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
846 pull->data_size - pull->offset));
847 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
850 /* call the dispatch function */
851 status = context->iface->dispatch(call, call, call->r);
852 if (!NT_STATUS_IS_OK(status)) {
853 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
854 context->iface->name,
855 call->pkt.u.request.opnum,
856 dcerpc_errstr(pull, call->fault_code)));
857 return dcesrv_fault(call, call->fault_code);
860 /* add the call to the pending list */
861 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
863 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
867 return dcesrv_reply(call);
870 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
872 struct ndr_push *push;
875 uint32_t total_length;
876 struct dcesrv_connection_context *context = call->context;
878 /* call the reply function */
879 status = context->iface->reply(call, call, call->r);
880 if (!NT_STATUS_IS_OK(status)) {
881 return dcesrv_fault(call, call->fault_code);
884 /* form the reply NDR */
885 push = ndr_push_init_ctx(call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
886 NT_STATUS_HAVE_NO_MEMORY(push);
888 /* carry over the pointer count to the reply in case we are
889 using full pointer. See NDR specification for full
891 push->ptr_count = call->ndr_pull->ptr_count;
893 if (lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
894 push->flags |= LIBNDR_FLAG_BIGENDIAN;
897 status = context->iface->ndr_push(call, call, push, call->r);
898 if (!NT_STATUS_IS_OK(status)) {
899 return dcesrv_fault(call, call->fault_code);
902 stub = ndr_push_blob(push);
904 total_length = stub.length;
908 struct data_blob_list_item *rep;
909 struct ncacn_packet pkt;
911 rep = talloc(call, struct data_blob_list_item);
912 NT_STATUS_HAVE_NO_MEMORY(rep);
914 length = stub.length;
915 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
916 /* the 32 is to cope with signing data */
917 length = call->conn->cli_max_recv_frag -
918 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
921 /* form the dcerpc response packet */
922 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
924 pkt.call_id = call->pkt.call_id;
925 pkt.ptype = DCERPC_PKT_RESPONSE;
927 if (stub.length == total_length) {
928 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
930 if (length == stub.length) {
931 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
933 pkt.u.response.alloc_hint = stub.length;
934 pkt.u.response.context_id = call->pkt.u.request.context_id;
935 pkt.u.response.cancel_count = 0;
936 pkt.u.response.stub_and_verifier.data = stub.data;
937 pkt.u.response.stub_and_verifier.length = length;
939 if (!dcesrv_auth_response(call, &rep->blob, &pkt)) {
940 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
943 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
945 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
948 stub.length -= length;
949 } while (stub.length != 0);
951 /* move the call from the pending to the finished calls list */
952 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
954 if (call->conn->call_list && call->conn->call_list->replies) {
955 if (call->conn->transport.report_output_data) {
956 call->conn->transport.report_output_data(call->conn);
963 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
965 if (!conn->transport.get_my_addr) {
969 return conn->transport.get_my_addr(conn, mem_ctx);
972 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
974 if (!conn->transport.get_peer_addr) {
978 return conn->transport.get_peer_addr(conn, mem_ctx);
982 work out if we have a full packet yet
984 static bool dce_full_packet(const DATA_BLOB *data)
986 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
989 if (dcerpc_get_frag_length(data) > data->length) {
996 we might have consumed only part of our input - advance past that part
998 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
1002 if (dce_conn->partial_input.length == offset) {
1003 data_blob_free(&dce_conn->partial_input);
1007 blob = dce_conn->partial_input;
1008 dce_conn->partial_input = data_blob(blob.data + offset,
1009 blob.length - offset);
1010 data_blob_free(&blob);
1014 remove the call from the right list when freed
1016 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1018 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1023 process some input to a dcerpc endpoint server.
1025 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
1027 struct ndr_pull *ndr;
1028 enum ndr_err_code ndr_err;
1030 struct dcesrv_call_state *call;
1033 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1035 talloc_free(dce_conn->partial_input.data);
1036 return NT_STATUS_NO_MEMORY;
1038 call->conn = dce_conn;
1039 call->event_ctx = dce_conn->event_ctx;
1040 call->msg_ctx = dce_conn->msg_ctx;
1041 call->state_flags = call->conn->state_flags;
1042 call->time = timeval_current();
1043 call->list = DCESRV_LIST_NONE;
1045 talloc_set_destructor(call, dcesrv_call_dequeue);
1047 blob = dce_conn->partial_input;
1048 blob.length = dcerpc_get_frag_length(&blob);
1050 ndr = ndr_pull_init_blob(&blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
1052 talloc_free(dce_conn->partial_input.data);
1054 return NT_STATUS_NO_MEMORY;
1057 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
1058 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
1061 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
1062 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1063 talloc_free(dce_conn->partial_input.data);
1065 return ndr_map_error2ntstatus(ndr_err);
1068 /* we have to check the signing here, before combining the
1070 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1071 !dcesrv_auth_request(call, &blob)) {
1072 dce_partial_advance(dce_conn, blob.length);
1073 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1076 dce_partial_advance(dce_conn, blob.length);
1078 /* see if this is a continued packet */
1079 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1080 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1081 struct dcesrv_call_state *call2 = call;
1082 uint32_t alloc_size;
1084 /* we only allow fragmented requests, no other packet types */
1085 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1086 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1089 /* this is a continuation of an existing call - find the call then
1090 tack it on the end */
1091 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1093 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1096 if (call->pkt.ptype != call2->pkt.ptype) {
1097 /* trying to play silly buggers are we? */
1098 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1101 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1102 call2->pkt.u.request.stub_and_verifier.length;
1103 if (call->pkt.u.request.alloc_hint > alloc_size) {
1104 alloc_size = call->pkt.u.request.alloc_hint;
1107 call->pkt.u.request.stub_and_verifier.data =
1108 talloc_realloc(call,
1109 call->pkt.u.request.stub_and_verifier.data,
1110 uint8_t, alloc_size);
1111 if (!call->pkt.u.request.stub_and_verifier.data) {
1112 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1114 memcpy(call->pkt.u.request.stub_and_verifier.data +
1115 call->pkt.u.request.stub_and_verifier.length,
1116 call2->pkt.u.request.stub_and_verifier.data,
1117 call2->pkt.u.request.stub_and_verifier.length);
1118 call->pkt.u.request.stub_and_verifier.length +=
1119 call2->pkt.u.request.stub_and_verifier.length;
1121 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1126 /* this may not be the last pdu in the chain - if its isn't then
1127 just put it on the incoming_fragmented_call_list and wait for the rest */
1128 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1129 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1130 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1131 return NT_STATUS_OK;
1134 /* This removes any fragments we may have had stashed away */
1135 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1137 switch (call->pkt.ptype) {
1138 case DCERPC_PKT_BIND:
1139 status = dcesrv_bind(call);
1141 case DCERPC_PKT_AUTH3:
1142 status = dcesrv_auth3(call);
1144 case DCERPC_PKT_ALTER:
1145 status = dcesrv_alter(call);
1147 case DCERPC_PKT_REQUEST:
1148 status = dcesrv_request(call);
1151 status = NT_STATUS_INVALID_PARAMETER;
1155 /* if we are going to be sending a reply then add
1156 it to the list of pending calls. We add it to the end to keep the call
1157 list in the order we will answer */
1158 if (!NT_STATUS_IS_OK(status)) {
1167 provide some input to a dcerpc endpoint server. This passes data
1168 from a dcerpc client into the server
1170 _PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1174 dce_conn->partial_input.data = talloc_realloc(dce_conn,
1175 dce_conn->partial_input.data,
1177 dce_conn->partial_input.length + data->length);
1178 if (!dce_conn->partial_input.data) {
1179 return NT_STATUS_NO_MEMORY;
1181 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1182 data->data, data->length);
1183 dce_conn->partial_input.length += data->length;
1185 while (dce_full_packet(&dce_conn->partial_input)) {
1186 status = dcesrv_input_process(dce_conn);
1187 if (!NT_STATUS_IS_OK(status)) {
1192 return NT_STATUS_OK;
1196 retrieve some output from a dcerpc server
1197 The caller supplies a function that will be called to do the
1200 The first argument to write_fn() will be 'private', the second will
1201 be a pointer to a buffer containing the data to be sent and the 3rd
1202 will be a pointer to a size_t variable that will be set to the
1203 number of bytes that are consumed from the output.
1205 from the current fragment
1207 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
1209 NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1212 struct dcesrv_call_state *call;
1213 struct data_blob_list_item *rep;
1216 call = dce_conn->call_list;
1217 if (!call || !call->replies) {
1218 if (dce_conn->pending_call_list) {
1219 /* TODO: we need to say act async here
1220 * as we know we have pending requests
1221 * which will be finished at a time
1223 return NT_STATUS_FOOBAR;
1225 return NT_STATUS_FOOBAR;
1227 rep = call->replies;
1229 status = write_fn(private_data, &rep->blob, &nwritten);
1230 NT_STATUS_IS_ERR_RETURN(status);
1232 rep->blob.length -= nwritten;
1233 rep->blob.data += nwritten;
1235 if (rep->blob.length == 0) {
1236 /* we're done with this section of the call */
1237 DLIST_REMOVE(call->replies, rep);
1240 if (call->replies == NULL) {
1241 /* we're done with the whole call */
1242 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1249 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1250 struct loadparm_context *lp_ctx,
1251 const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1254 struct dcesrv_context *dce_ctx;
1257 if (!endpoint_servers) {
1258 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1259 return NT_STATUS_INTERNAL_ERROR;
1262 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1263 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1264 dce_ctx->endpoint_list = NULL;
1265 dce_ctx->lp_ctx = lp_ctx;
1267 for (i=0;endpoint_servers[i];i++) {
1268 const struct dcesrv_endpoint_server *ep_server;
1270 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1272 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1273 return NT_STATUS_INTERNAL_ERROR;
1276 status = ep_server->init_server(dce_ctx, ep_server);
1277 if (!NT_STATUS_IS_OK(status)) {
1278 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1279 nt_errstr(status)));
1284 *_dce_ctx = dce_ctx;
1285 return NT_STATUS_OK;
1288 /* the list of currently registered DCERPC endpoint servers.
1290 static struct ep_server {
1291 struct dcesrv_endpoint_server *ep_server;
1292 } *ep_servers = NULL;
1293 static int num_ep_servers;
1296 register a DCERPC endpoint server.
1298 The 'name' can be later used by other backends to find the operations
1299 structure for this backend.
1301 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1303 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1305 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1307 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1308 /* its already registered! */
1309 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1311 return NT_STATUS_OBJECT_NAME_COLLISION;
1314 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1316 smb_panic("out of memory in dcerpc_register");
1319 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1320 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1324 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1327 return NT_STATUS_OK;
1331 return the operations structure for a named backend of the specified type
1333 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1337 for (i=0;i<num_ep_servers;i++) {
1338 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1339 return ep_servers[i].ep_server;
1347 return the DCERPC module version, and the size of some critical types
1348 This can be used by endpoint server modules to either detect compilation errors, or provide
1349 multiple implementations for different smbd compilation options in one module
1351 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1353 static const struct dcesrv_critical_sizes critical_sizes = {
1354 DCERPC_MODULE_VERSION,
1355 sizeof(struct dcesrv_context),
1356 sizeof(struct dcesrv_endpoint),
1357 sizeof(struct dcesrv_endpoint_server),
1358 sizeof(struct dcesrv_interface),
1359 sizeof(struct dcesrv_if_list),
1360 sizeof(struct dcesrv_connection),
1361 sizeof(struct dcesrv_call_state),
1362 sizeof(struct dcesrv_auth),
1363 sizeof(struct dcesrv_handle)
1366 return &critical_sizes;
1370 initialise the dcerpc server context for ncacn_np based services
1372 _PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
1373 struct dcesrv_context **_dce_ctx)
1376 struct dcesrv_context *dce_ctx;
1378 status = dcesrv_init_context(mem_ctx, lp_ctx, lp_dcerpc_endpoint_servers(lp_ctx), &dce_ctx);
1379 NT_STATUS_NOT_OK_RETURN(status);
1381 *_dce_ctx = dce_ctx;
1382 return NT_STATUS_OK;