2 Unix SMB/CIFS implementation.
4 server side dcerpc core code
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) Stefan (metze) Metzmacher 2004-2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "librpc/gen_ndr/ndr_dcerpc.h"
25 #include "auth/auth.h"
26 #include "auth/gensec/gensec.h"
27 #include "lib/util/dlinklist.h"
28 #include "rpc_server/dcerpc_server.h"
29 #include "rpc_server/dcerpc_server_proto.h"
30 #include "librpc/rpc/dcerpc_proto.h"
31 #include "lib/events/events.h"
32 #include "smbd/service_task.h"
33 #include "smbd/service_stream.h"
34 #include "smbd/service.h"
35 #include "system/filesys.h"
36 #include "libcli/security/security.h"
37 #include "param/param.h"
39 #define SAMBA_ACCOC_GROUP 0x12345678
41 extern const struct dcesrv_interface dcesrv_mgmt_interface;
44 see if two endpoints match
46 static bool endpoints_match(const struct dcerpc_binding *ep1,
47 const struct dcerpc_binding *ep2)
49 if (ep1->transport != ep2->transport) {
53 if (!ep1->endpoint || !ep2->endpoint) {
54 return ep1->endpoint == ep2->endpoint;
57 if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
64 find an endpoint in the dcesrv_context
66 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
67 const struct dcerpc_binding *ep_description)
69 struct dcesrv_endpoint *ep;
70 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
71 if (endpoints_match(ep->ep_description, ep_description)) {
79 find a registered context_id from a bind or alter_context
81 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn,
84 struct dcesrv_connection_context *c;
85 for (c=conn->contexts;c;c=c->next) {
86 if (c->context_id == context_id) return c;
92 see if a uuid and if_version match to an interface
94 static bool interface_match(const struct dcesrv_interface *if1,
95 const struct dcesrv_interface *if2)
97 return (if1->syntax_id.if_version == if2->syntax_id.if_version &&
98 GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
102 find the interface operations on an endpoint
104 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
105 const struct dcesrv_interface *iface)
107 struct dcesrv_if_list *ifl;
108 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
109 if (interface_match(&(ifl->iface), iface)) {
110 return &(ifl->iface);
117 see if a uuid and if_version match to an interface
119 static bool interface_match_by_uuid(const struct dcesrv_interface *iface,
120 const struct GUID *uuid, uint32_t if_version)
122 return (iface->syntax_id.if_version == if_version &&
123 GUID_equal(&iface->syntax_id.uuid, uuid));
127 find the interface operations on an endpoint by uuid
129 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
130 const struct GUID *uuid, uint32_t if_version)
132 struct dcesrv_if_list *ifl;
133 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
134 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
135 return &(ifl->iface);
142 find the earlier parts of a fragmented call awaiting reassembily
144 static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
146 struct dcesrv_call_state *c;
147 for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
148 if (c->pkt.call_id == call_id) {
156 register an interface on an endpoint
158 _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
160 const struct dcesrv_interface *iface,
161 const struct security_descriptor *sd)
163 struct dcesrv_endpoint *ep;
164 struct dcesrv_if_list *ifl;
165 struct dcerpc_binding *binding;
169 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
171 if (NT_STATUS_IS_ERR(status)) {
172 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
176 /* check if this endpoint exists
178 if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
179 ep = talloc(dce_ctx, struct dcesrv_endpoint);
181 return NT_STATUS_NO_MEMORY;
184 ep->ep_description = talloc_reference(ep, binding);
187 /* add mgmt interface */
188 ifl = talloc(dce_ctx, struct dcesrv_if_list);
190 return NT_STATUS_NO_MEMORY;
193 memcpy(&(ifl->iface), &dcesrv_mgmt_interface,
194 sizeof(struct dcesrv_interface));
196 DLIST_ADD(ep->interface_list, ifl);
199 /* see if the interface is already registered on te endpoint */
200 if (find_interface(ep, iface)!=NULL) {
201 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
202 iface->name, ep_name));
203 return NT_STATUS_OBJECT_NAME_COLLISION;
206 /* talloc a new interface list element */
207 ifl = talloc(dce_ctx, struct dcesrv_if_list);
209 return NT_STATUS_NO_MEMORY;
212 /* copy the given interface struct to the one on the endpoints interface list */
213 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
215 /* if we have a security descriptor given,
216 * we should see if we can set it up on the endpoint
219 /* if there's currently no security descriptor given on the endpoint
222 if (ep->sd == NULL) {
223 ep->sd = security_descriptor_copy(dce_ctx, sd);
226 /* if now there's no security descriptor given on the endpoint
227 * something goes wrong, either we failed to copy the security descriptor
228 * or there was already one on the endpoint
230 if (ep->sd != NULL) {
231 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
232 " on endpoint '%s'\n",
233 iface->name, ep_name));
234 if (add_ep) free(ep);
236 return NT_STATUS_OBJECT_NAME_COLLISION;
240 /* finally add the interface on the endpoint */
241 DLIST_ADD(ep->interface_list, ifl);
243 /* if it's a new endpoint add it to the dcesrv_context */
245 DLIST_ADD(dce_ctx->endpoint_list, ep);
248 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
249 iface->name, ep_name));
254 static NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
255 DATA_BLOB *session_key)
257 if (p->auth_state.session_info->session_key.length) {
258 *session_key = p->auth_state.session_info->session_key;
261 return NT_STATUS_NO_USER_SESSION_KEY;
264 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
265 DATA_BLOB *session_key)
267 /* this took quite a few CPU cycles to find ... */
268 session_key->data = discard_const_p(uint8_t, "SystemLibraryDTC");
269 session_key->length = 16;
274 fetch the user session key - may be default (above) or the SMB session key
276 The key is always truncated to 16 bytes
278 _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
279 DATA_BLOB *session_key)
281 NTSTATUS status = p->auth_state.session_key(p, session_key);
282 if (!NT_STATUS_IS_OK(status)) {
286 session_key->length = MIN(session_key->length, 16);
293 destroy a link to an endpoint
295 static int dcesrv_endpoint_destructor(struct dcesrv_connection *p)
297 while (p->contexts) {
298 struct dcesrv_connection_context *c = p->contexts;
300 DLIST_REMOVE(p->contexts, c);
303 c->iface->unbind(c, c->iface);
312 connect to a dcerpc endpoint
314 _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
316 const struct dcesrv_endpoint *ep,
317 struct auth_session_info *session_info,
318 struct event_context *event_ctx,
319 struct messaging_context *msg_ctx,
320 struct server_id server_id,
321 uint32_t state_flags,
322 struct dcesrv_connection **_p)
324 struct dcesrv_connection *p;
327 return NT_STATUS_ACCESS_DENIED;
330 p = talloc(mem_ctx, struct dcesrv_connection);
331 NT_STATUS_HAVE_NO_MEMORY(p);
333 if (!talloc_reference(p, session_info)) {
335 return NT_STATUS_NO_MEMORY;
338 p->dce_ctx = dce_ctx;
342 p->incoming_fragmented_call_list = NULL;
343 p->pending_call_list = NULL;
344 p->cli_max_recv_frag = 0;
345 p->partial_input = data_blob(NULL, 0);
346 p->auth_state.auth_info = NULL;
347 p->auth_state.gensec_security = NULL;
348 p->auth_state.session_info = session_info;
349 p->auth_state.session_key = dcesrv_generic_session_key;
350 p->event_ctx = event_ctx;
351 p->msg_ctx = msg_ctx;
352 p->server_id = server_id;
353 p->processing = false;
354 p->state_flags = state_flags;
355 ZERO_STRUCT(p->transport);
357 talloc_set_destructor(p, dcesrv_endpoint_destructor);
364 search and connect to a dcerpc endpoint
366 _PUBLIC_ NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
368 const struct dcerpc_binding *ep_description,
369 struct auth_session_info *session_info,
370 struct event_context *event_ctx,
371 struct messaging_context *msg_ctx,
372 struct server_id server_id,
373 uint32_t state_flags,
374 struct dcesrv_connection **dce_conn_p)
377 const struct dcesrv_endpoint *ep;
379 /* make sure this endpoint exists */
380 ep = find_endpoint(dce_ctx, ep_description);
382 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
385 status = dcesrv_endpoint_connect(dce_ctx, mem_ctx, ep, session_info,
386 event_ctx, msg_ctx, server_id,
387 state_flags, dce_conn_p);
388 NT_STATUS_NOT_OK_RETURN(status);
390 (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
392 /* TODO: check security descriptor of the endpoint here
393 * if it's a smb named pipe
394 * if it's failed free dce_conn_p
401 static void dcesrv_init_hdr(struct ncacn_packet *pkt, bool bigendian)
404 pkt->rpc_vers_minor = 0;
408 pkt->drep[0] = DCERPC_DREP_LE;
416 move a call from an existing linked list to the specified list. This
417 prevents bugs where we forget to remove the call from a previous
420 static void dcesrv_call_set_list(struct dcesrv_call_state *call,
421 enum dcesrv_call_list list)
423 switch (call->list) {
424 case DCESRV_LIST_NONE:
426 case DCESRV_LIST_CALL_LIST:
427 DLIST_REMOVE(call->conn->call_list, call);
429 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
430 DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
432 case DCESRV_LIST_PENDING_CALL_LIST:
433 DLIST_REMOVE(call->conn->pending_call_list, call);
438 case DCESRV_LIST_NONE:
440 case DCESRV_LIST_CALL_LIST:
441 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
443 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
444 DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
446 case DCESRV_LIST_PENDING_CALL_LIST:
447 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
453 return a dcerpc fault
455 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
457 struct ncacn_packet pkt;
458 struct data_blob_list_item *rep;
462 /* setup a bind_ack */
463 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
465 pkt.call_id = call->pkt.call_id;
466 pkt.ptype = DCERPC_PKT_FAULT;
467 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
468 pkt.u.fault.alloc_hint = 0;
469 pkt.u.fault.context_id = 0;
470 pkt.u.fault.cancel_count = 0;
471 pkt.u.fault.status = fault_code;
474 pkt.u.fault._pad = data_blob_const(zeros, sizeof(zeros));
476 rep = talloc(call, struct data_blob_list_item);
478 return NT_STATUS_NO_MEMORY;
481 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
482 if (!NT_STATUS_IS_OK(status)) {
486 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
488 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
489 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
496 return a dcerpc bind_nak
498 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
500 struct ncacn_packet pkt;
501 struct data_blob_list_item *rep;
504 /* setup a bind_nak */
505 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
507 pkt.call_id = call->pkt.call_id;
508 pkt.ptype = DCERPC_PKT_BIND_NAK;
509 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
510 pkt.u.bind_nak.reject_reason = reason;
511 if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
512 pkt.u.bind_nak.versions.v.num_versions = 0;
515 rep = talloc(call, struct data_blob_list_item);
517 return NT_STATUS_NO_MEMORY;
520 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
521 if (!NT_STATUS_IS_OK(status)) {
525 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
527 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
528 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
535 handle a bind request
537 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
539 uint32_t if_version, transfer_syntax_version;
540 struct GUID uuid, *transfer_syntax_uuid;
541 struct ncacn_packet pkt;
542 struct data_blob_list_item *rep;
544 uint32_t result=0, reason=0;
546 const struct dcesrv_interface *iface;
549 * Association groups allow policy handles to be shared across
550 * multiple client connections. We don't implement this yet.
552 * So we just allow 0 if the client wants to create a new
555 * And we allow the 0x12345678 value, we give away as
556 * assoc_group_id back to the clients
558 if (call->pkt.u.bind.assoc_group_id != 0 &&
559 call->pkt.u.bind.assoc_group_id != SAMBA_ACCOC_GROUP) {
560 return dcesrv_bind_nak(call, 0);
563 if (call->pkt.u.bind.num_contexts < 1 ||
564 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
565 return dcesrv_bind_nak(call, 0);
568 context_id = call->pkt.u.bind.ctx_list[0].context_id;
570 /* you can't bind twice on one context */
571 if (dcesrv_find_context(call->conn, context_id) != NULL) {
572 return dcesrv_bind_nak(call, 0);
575 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
576 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
578 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
579 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
580 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
581 ndr_transfer_syntax.if_version != transfer_syntax_version) {
582 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
583 /* we only do NDR encoded dcerpc */
584 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
585 talloc_free(uuid_str);
586 return dcesrv_bind_nak(call, 0);
589 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
591 char *uuid_str = GUID_string(call, &uuid);
592 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
593 talloc_free(uuid_str);
595 /* we don't know about that interface */
596 result = DCERPC_BIND_PROVIDER_REJECT;
597 reason = DCERPC_BIND_REASON_ASYNTAX;
601 /* add this context to the list of available context_ids */
602 struct dcesrv_connection_context *context = talloc(call->conn,
603 struct dcesrv_connection_context);
604 if (context == NULL) {
605 return dcesrv_bind_nak(call, 0);
607 context->conn = call->conn;
608 context->iface = iface;
609 context->context_id = context_id;
610 context->private = NULL;
611 context->handles = NULL;
612 DLIST_ADD(call->conn->contexts, context);
613 call->context = context;
616 if (call->conn->cli_max_recv_frag == 0) {
617 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
620 /* handle any authentication that is being requested */
621 if (!dcesrv_auth_bind(call)) {
622 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
625 /* setup a bind_ack */
626 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
628 pkt.call_id = call->pkt.call_id;
629 pkt.ptype = DCERPC_PKT_BIND_ACK;
630 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
631 pkt.u.bind_ack.max_xmit_frag = 0x2000;
632 pkt.u.bind_ack.max_recv_frag = 0x2000;
633 /* we need to send a non zero assoc_group_id here to make longhorn happy, it also matches samba3 */
634 pkt.u.bind_ack.assoc_group_id = SAMBA_ACCOC_GROUP;
636 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
637 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
639 pkt.u.bind_ack.secondary_address = "";
641 pkt.u.bind_ack.num_results = 1;
642 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
643 if (!pkt.u.bind_ack.ctx_list) {
644 return NT_STATUS_NO_MEMORY;
646 pkt.u.bind_ack.ctx_list[0].result = result;
647 pkt.u.bind_ack.ctx_list[0].reason = reason;
648 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
649 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
651 status = dcesrv_auth_bind_ack(call, &pkt);
652 if (!NT_STATUS_IS_OK(status)) {
653 return dcesrv_bind_nak(call, 0);
657 status = iface->bind(call, iface);
658 if (!NT_STATUS_IS_OK(status)) {
659 char *uuid_str = GUID_string(call, &uuid);
660 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
661 uuid_str, if_version, nt_errstr(status)));
662 talloc_free(uuid_str);
663 return dcesrv_bind_nak(call, 0);
667 rep = talloc(call, struct data_blob_list_item);
669 return NT_STATUS_NO_MEMORY;
672 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
673 if (!NT_STATUS_IS_OK(status)) {
677 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
679 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
680 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
687 handle a auth3 request
689 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
691 /* handle the auth3 in the auth code */
692 if (!dcesrv_auth_auth3(call)) {
693 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
698 /* we don't send a reply to a auth3 request, except by a
705 handle a bind request
707 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
709 uint32_t if_version, transfer_syntax_version;
710 struct dcesrv_connection_context *context;
711 const struct dcesrv_interface *iface;
712 struct GUID uuid, *transfer_syntax_uuid;
715 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
716 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
718 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
719 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
720 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
721 ndr_transfer_syntax.if_version != transfer_syntax_version) {
722 /* we only do NDR encoded dcerpc */
723 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
726 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
728 char *uuid_str = GUID_string(call, &uuid);
729 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
730 talloc_free(uuid_str);
731 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
734 /* add this context to the list of available context_ids */
735 context = talloc(call->conn, struct dcesrv_connection_context);
736 if (context == NULL) {
737 return NT_STATUS_NO_MEMORY;
739 context->conn = call->conn;
740 context->iface = iface;
741 context->context_id = context_id;
742 context->private = NULL;
743 context->handles = NULL;
744 DLIST_ADD(call->conn->contexts, context);
745 call->context = context;
748 status = iface->bind(call, iface);
749 if (!NT_STATUS_IS_OK(status)) {
759 handle a alter context request
761 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
763 struct ncacn_packet pkt;
764 struct data_blob_list_item *rep;
766 uint32_t result=0, reason=0;
769 /* handle any authentication that is being requested */
770 if (!dcesrv_auth_alter(call)) {
771 /* TODO: work out the right reject code */
772 result = DCERPC_BIND_PROVIDER_REJECT;
773 reason = DCERPC_BIND_REASON_ASYNTAX;
776 context_id = call->pkt.u.alter.ctx_list[0].context_id;
778 /* see if they are asking for a new interface */
780 dcesrv_find_context(call->conn, context_id) == NULL) {
781 status = dcesrv_alter_new_context(call, context_id);
782 if (!NT_STATUS_IS_OK(status)) {
783 result = DCERPC_BIND_PROVIDER_REJECT;
784 reason = DCERPC_BIND_REASON_ASYNTAX;
788 /* setup a alter_resp */
789 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
791 pkt.call_id = call->pkt.call_id;
792 pkt.ptype = DCERPC_PKT_ALTER_RESP;
793 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
794 pkt.u.alter_resp.max_xmit_frag = 0x2000;
795 pkt.u.alter_resp.max_recv_frag = 0x2000;
796 pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
797 pkt.u.alter_resp.num_results = 1;
798 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
799 if (!pkt.u.alter_resp.ctx_list) {
800 return NT_STATUS_NO_MEMORY;
802 pkt.u.alter_resp.ctx_list[0].result = result;
803 pkt.u.alter_resp.ctx_list[0].reason = reason;
804 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
805 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
806 pkt.u.alter_resp.secondary_address = "";
808 status = dcesrv_auth_alter_ack(call, &pkt);
809 if (!NT_STATUS_IS_OK(status)) {
810 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
811 || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
812 || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
813 || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
814 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
816 return dcesrv_fault(call, 0);
819 rep = talloc(call, struct data_blob_list_item);
821 return NT_STATUS_NO_MEMORY;
824 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
825 if (!NT_STATUS_IS_OK(status)) {
829 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
831 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
832 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
838 handle a dcerpc request packet
840 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
842 struct ndr_pull *pull;
844 struct dcesrv_connection_context *context;
846 /* if authenticated, and the mech we use can't do async replies, don't use them... */
847 if (call->conn->auth_state.gensec_security &&
848 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
849 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
852 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
853 if (context == NULL) {
854 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
857 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call,
858 lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
859 NT_STATUS_HAVE_NO_MEMORY(pull);
861 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
863 call->context = context;
864 call->ndr_pull = pull;
866 if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
867 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
870 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
871 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
874 /* unravel the NDR for the packet */
875 status = context->iface->ndr_pull(call, call, pull, &call->r);
876 if (!NT_STATUS_IS_OK(status)) {
877 return dcesrv_fault(call, call->fault_code);
880 if (pull->offset != pull->data_size) {
881 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
882 pull->data_size - pull->offset));
883 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
886 /* call the dispatch function */
887 status = context->iface->dispatch(call, call, call->r);
888 if (!NT_STATUS_IS_OK(status)) {
889 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
890 context->iface->name,
891 call->pkt.u.request.opnum,
892 dcerpc_errstr(pull, call->fault_code)));
893 return dcesrv_fault(call, call->fault_code);
896 /* add the call to the pending list */
897 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
899 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
903 return dcesrv_reply(call);
906 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
908 struct ndr_push *push;
911 uint32_t total_length, chunk_size;
912 struct dcesrv_connection_context *context = call->context;
914 /* call the reply function */
915 status = context->iface->reply(call, call, call->r);
916 if (!NT_STATUS_IS_OK(status)) {
917 return dcesrv_fault(call, call->fault_code);
920 /* form the reply NDR */
921 push = ndr_push_init_ctx(call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
922 NT_STATUS_HAVE_NO_MEMORY(push);
924 /* carry over the pointer count to the reply in case we are
925 using full pointer. See NDR specification for full
927 push->ptr_count = call->ndr_pull->ptr_count;
929 if (lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
930 push->flags |= LIBNDR_FLAG_BIGENDIAN;
933 status = context->iface->ndr_push(call, call, push, call->r);
934 if (!NT_STATUS_IS_OK(status)) {
935 return dcesrv_fault(call, call->fault_code);
938 stub = ndr_push_blob(push);
940 total_length = stub.length;
942 /* we can write a full max_recv_frag size, minus the dcerpc
943 request header size */
944 chunk_size = call->conn->cli_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
948 struct data_blob_list_item *rep;
949 struct ncacn_packet pkt;
951 rep = talloc(call, struct data_blob_list_item);
952 NT_STATUS_HAVE_NO_MEMORY(rep);
954 length = MIN(chunk_size, stub.length);
956 /* form the dcerpc response packet */
957 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
959 pkt.call_id = call->pkt.call_id;
960 pkt.ptype = DCERPC_PKT_RESPONSE;
962 if (stub.length == total_length) {
963 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
965 if (length == stub.length) {
966 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
968 pkt.u.response.alloc_hint = stub.length;
969 pkt.u.response.context_id = call->pkt.u.request.context_id;
970 pkt.u.response.cancel_count = 0;
971 pkt.u.response.stub_and_verifier.data = stub.data;
972 pkt.u.response.stub_and_verifier.length = length;
974 if (!dcesrv_auth_response(call, &rep->blob, &pkt)) {
975 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
978 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
980 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
983 stub.length -= length;
984 } while (stub.length != 0);
986 /* move the call from the pending to the finished calls list */
987 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
989 if (call->conn->call_list && call->conn->call_list->replies) {
990 if (call->conn->transport.report_output_data) {
991 call->conn->transport.report_output_data(call->conn);
998 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1000 if (!conn->transport.get_my_addr) {
1004 return conn->transport.get_my_addr(conn, mem_ctx);
1007 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1009 if (!conn->transport.get_peer_addr) {
1013 return conn->transport.get_peer_addr(conn, mem_ctx);
1017 work out if we have a full packet yet
1019 static bool dce_full_packet(const DATA_BLOB *data)
1021 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
1024 if (dcerpc_get_frag_length(data) > data->length) {
1031 we might have consumed only part of our input - advance past that part
1033 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
1037 if (dce_conn->partial_input.length == offset) {
1038 data_blob_free(&dce_conn->partial_input);
1042 blob = dce_conn->partial_input;
1043 dce_conn->partial_input = data_blob(blob.data + offset,
1044 blob.length - offset);
1045 data_blob_free(&blob);
1049 remove the call from the right list when freed
1051 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1053 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1058 process some input to a dcerpc endpoint server.
1060 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
1062 struct ndr_pull *ndr;
1063 enum ndr_err_code ndr_err;
1065 struct dcesrv_call_state *call;
1068 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1070 talloc_free(dce_conn->partial_input.data);
1071 return NT_STATUS_NO_MEMORY;
1073 call->conn = dce_conn;
1074 call->event_ctx = dce_conn->event_ctx;
1075 call->msg_ctx = dce_conn->msg_ctx;
1076 call->state_flags = call->conn->state_flags;
1077 call->time = timeval_current();
1078 call->list = DCESRV_LIST_NONE;
1080 talloc_set_destructor(call, dcesrv_call_dequeue);
1082 blob = dce_conn->partial_input;
1083 blob.length = dcerpc_get_frag_length(&blob);
1085 ndr = ndr_pull_init_blob(&blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
1087 talloc_free(dce_conn->partial_input.data);
1089 return NT_STATUS_NO_MEMORY;
1092 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
1093 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
1096 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
1097 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1098 talloc_free(dce_conn->partial_input.data);
1100 return ndr_map_error2ntstatus(ndr_err);
1103 /* we have to check the signing here, before combining the
1105 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1106 !dcesrv_auth_request(call, &blob)) {
1107 dce_partial_advance(dce_conn, blob.length);
1108 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1111 dce_partial_advance(dce_conn, blob.length);
1113 /* see if this is a continued packet */
1114 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1115 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1116 struct dcesrv_call_state *call2 = call;
1117 uint32_t alloc_size;
1119 /* we only allow fragmented requests, no other packet types */
1120 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1121 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1124 /* this is a continuation of an existing call - find the call then
1125 tack it on the end */
1126 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1128 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1131 if (call->pkt.ptype != call2->pkt.ptype) {
1132 /* trying to play silly buggers are we? */
1133 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1136 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1137 call2->pkt.u.request.stub_and_verifier.length;
1138 if (call->pkt.u.request.alloc_hint > alloc_size) {
1139 alloc_size = call->pkt.u.request.alloc_hint;
1142 call->pkt.u.request.stub_and_verifier.data =
1143 talloc_realloc(call,
1144 call->pkt.u.request.stub_and_verifier.data,
1145 uint8_t, alloc_size);
1146 if (!call->pkt.u.request.stub_and_verifier.data) {
1147 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1149 memcpy(call->pkt.u.request.stub_and_verifier.data +
1150 call->pkt.u.request.stub_and_verifier.length,
1151 call2->pkt.u.request.stub_and_verifier.data,
1152 call2->pkt.u.request.stub_and_verifier.length);
1153 call->pkt.u.request.stub_and_verifier.length +=
1154 call2->pkt.u.request.stub_and_verifier.length;
1156 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1161 /* this may not be the last pdu in the chain - if its isn't then
1162 just put it on the incoming_fragmented_call_list and wait for the rest */
1163 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1164 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1165 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1166 return NT_STATUS_OK;
1169 /* This removes any fragments we may have had stashed away */
1170 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1172 switch (call->pkt.ptype) {
1173 case DCERPC_PKT_BIND:
1174 status = dcesrv_bind(call);
1176 case DCERPC_PKT_AUTH3:
1177 status = dcesrv_auth3(call);
1179 case DCERPC_PKT_ALTER:
1180 status = dcesrv_alter(call);
1182 case DCERPC_PKT_REQUEST:
1183 status = dcesrv_request(call);
1186 status = NT_STATUS_INVALID_PARAMETER;
1190 /* if we are going to be sending a reply then add
1191 it to the list of pending calls. We add it to the end to keep the call
1192 list in the order we will answer */
1193 if (!NT_STATUS_IS_OK(status)) {
1202 provide some input to a dcerpc endpoint server. This passes data
1203 from a dcerpc client into the server
1205 _PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1209 dce_conn->partial_input.data = talloc_realloc(dce_conn,
1210 dce_conn->partial_input.data,
1212 dce_conn->partial_input.length + data->length);
1213 if (!dce_conn->partial_input.data) {
1214 return NT_STATUS_NO_MEMORY;
1216 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1217 data->data, data->length);
1218 dce_conn->partial_input.length += data->length;
1220 while (dce_full_packet(&dce_conn->partial_input)) {
1221 status = dcesrv_input_process(dce_conn);
1222 if (!NT_STATUS_IS_OK(status)) {
1227 return NT_STATUS_OK;
1231 retrieve some output from a dcerpc server
1232 The caller supplies a function that will be called to do the
1235 The first argument to write_fn() will be 'private', the second will
1236 be a pointer to a buffer containing the data to be sent and the 3rd
1237 will be a pointer to a size_t variable that will be set to the
1238 number of bytes that are consumed from the output.
1240 from the current fragment
1242 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
1244 NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1247 struct dcesrv_call_state *call;
1248 struct data_blob_list_item *rep;
1251 call = dce_conn->call_list;
1252 if (!call || !call->replies) {
1253 if (dce_conn->pending_call_list) {
1254 /* TODO: we need to say act async here
1255 * as we know we have pending requests
1256 * which will be finished at a time
1258 return NT_STATUS_FOOBAR;
1260 return NT_STATUS_FOOBAR;
1262 rep = call->replies;
1264 status = write_fn(private_data, &rep->blob, &nwritten);
1265 NT_STATUS_IS_ERR_RETURN(status);
1267 rep->blob.length -= nwritten;
1268 rep->blob.data += nwritten;
1270 if (rep->blob.length == 0) {
1271 /* we're done with this section of the call */
1272 DLIST_REMOVE(call->replies, rep);
1275 if (call->replies == NULL) {
1276 /* we're done with the whole call */
1277 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1284 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1285 struct loadparm_context *lp_ctx,
1286 const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1289 struct dcesrv_context *dce_ctx;
1292 if (!endpoint_servers) {
1293 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1294 return NT_STATUS_INTERNAL_ERROR;
1297 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1298 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1299 dce_ctx->endpoint_list = NULL;
1300 dce_ctx->lp_ctx = lp_ctx;
1302 for (i=0;endpoint_servers[i];i++) {
1303 const struct dcesrv_endpoint_server *ep_server;
1305 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1307 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1308 return NT_STATUS_INTERNAL_ERROR;
1311 status = ep_server->init_server(dce_ctx, ep_server);
1312 if (!NT_STATUS_IS_OK(status)) {
1313 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1314 nt_errstr(status)));
1319 *_dce_ctx = dce_ctx;
1320 return NT_STATUS_OK;
1323 /* the list of currently registered DCERPC endpoint servers.
1325 static struct ep_server {
1326 struct dcesrv_endpoint_server *ep_server;
1327 } *ep_servers = NULL;
1328 static int num_ep_servers;
1331 register a DCERPC endpoint server.
1333 The 'name' can be later used by other backends to find the operations
1334 structure for this backend.
1336 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1338 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1340 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1342 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1343 /* its already registered! */
1344 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1346 return NT_STATUS_OBJECT_NAME_COLLISION;
1349 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1351 smb_panic("out of memory in dcerpc_register");
1354 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1355 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1359 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1362 return NT_STATUS_OK;
1366 return the operations structure for a named backend of the specified type
1368 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1372 for (i=0;i<num_ep_servers;i++) {
1373 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1374 return ep_servers[i].ep_server;
1382 return the DCERPC module version, and the size of some critical types
1383 This can be used by endpoint server modules to either detect compilation errors, or provide
1384 multiple implementations for different smbd compilation options in one module
1386 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1388 static const struct dcesrv_critical_sizes critical_sizes = {
1389 DCERPC_MODULE_VERSION,
1390 sizeof(struct dcesrv_context),
1391 sizeof(struct dcesrv_endpoint),
1392 sizeof(struct dcesrv_endpoint_server),
1393 sizeof(struct dcesrv_interface),
1394 sizeof(struct dcesrv_if_list),
1395 sizeof(struct dcesrv_connection),
1396 sizeof(struct dcesrv_call_state),
1397 sizeof(struct dcesrv_auth),
1398 sizeof(struct dcesrv_handle)
1401 return &critical_sizes;
1405 initialise the dcerpc server context for ncacn_np based services
1407 _PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
1408 struct dcesrv_context **_dce_ctx)
1411 struct dcesrv_context *dce_ctx;
1413 status = dcesrv_init_context(mem_ctx, lp_ctx, lp_dcerpc_endpoint_servers(lp_ctx), &dce_ctx);
1414 NT_STATUS_NOT_OK_RETURN(status);
1416 *_dce_ctx = dce_ctx;
1417 return NT_STATUS_OK;