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;
547 uint32_t extra_flags = 0;
550 * Association groups allow policy handles to be shared across
551 * multiple client connections. We don't implement this yet.
553 * So we just allow 0 if the client wants to create a new
556 * And we allow the 0x12345678 value, we give away as
557 * assoc_group_id back to the clients
559 if (call->pkt.u.bind.assoc_group_id != 0 &&
560 call->pkt.u.bind.assoc_group_id != SAMBA_ACCOC_GROUP) {
561 return dcesrv_bind_nak(call, 0);
564 if (call->pkt.u.bind.num_contexts < 1 ||
565 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
566 return dcesrv_bind_nak(call, 0);
569 context_id = call->pkt.u.bind.ctx_list[0].context_id;
571 /* you can't bind twice on one context */
572 if (dcesrv_find_context(call->conn, context_id) != NULL) {
573 return dcesrv_bind_nak(call, 0);
576 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
577 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
579 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
580 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
581 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
582 ndr_transfer_syntax.if_version != transfer_syntax_version) {
583 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
584 /* we only do NDR encoded dcerpc */
585 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
586 talloc_free(uuid_str);
587 return dcesrv_bind_nak(call, 0);
590 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
592 char *uuid_str = GUID_string(call, &uuid);
593 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
594 talloc_free(uuid_str);
596 /* we don't know about that interface */
597 result = DCERPC_BIND_PROVIDER_REJECT;
598 reason = DCERPC_BIND_REASON_ASYNTAX;
602 /* add this context to the list of available context_ids */
603 struct dcesrv_connection_context *context = talloc(call->conn,
604 struct dcesrv_connection_context);
605 if (context == NULL) {
606 return dcesrv_bind_nak(call, 0);
608 context->conn = call->conn;
609 context->iface = iface;
610 context->context_id = context_id;
611 context->private = NULL;
612 context->handles = NULL;
613 DLIST_ADD(call->conn->contexts, context);
614 call->context = context;
617 if (call->conn->cli_max_recv_frag == 0) {
618 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
621 if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) &&
622 lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","header signing", false)) {
623 call->conn->state_flags |= DCESRV_CALL_STATE_FLAG_HEADER_SIGNING;
624 extra_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
627 /* handle any authentication that is being requested */
628 if (!dcesrv_auth_bind(call)) {
629 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
632 /* setup a bind_ack */
633 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
635 pkt.call_id = call->pkt.call_id;
636 pkt.ptype = DCERPC_PKT_BIND_ACK;
637 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
638 pkt.u.bind_ack.max_xmit_frag = 0x2000;
639 pkt.u.bind_ack.max_recv_frag = 0x2000;
640 /* we need to send a non zero assoc_group_id here to make longhorn happy, it also matches samba3 */
641 pkt.u.bind_ack.assoc_group_id = SAMBA_ACCOC_GROUP;
643 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
644 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
646 pkt.u.bind_ack.secondary_address = "";
648 pkt.u.bind_ack.num_results = 1;
649 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
650 if (!pkt.u.bind_ack.ctx_list) {
651 return NT_STATUS_NO_MEMORY;
653 pkt.u.bind_ack.ctx_list[0].result = result;
654 pkt.u.bind_ack.ctx_list[0].reason = reason;
655 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
656 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
658 status = dcesrv_auth_bind_ack(call, &pkt);
659 if (!NT_STATUS_IS_OK(status)) {
660 return dcesrv_bind_nak(call, 0);
664 status = iface->bind(call, iface);
665 if (!NT_STATUS_IS_OK(status)) {
666 char *uuid_str = GUID_string(call, &uuid);
667 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
668 uuid_str, if_version, nt_errstr(status)));
669 talloc_free(uuid_str);
670 return dcesrv_bind_nak(call, 0);
674 rep = talloc(call, struct data_blob_list_item);
676 return NT_STATUS_NO_MEMORY;
679 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
680 if (!NT_STATUS_IS_OK(status)) {
684 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
686 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
687 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
694 handle a auth3 request
696 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
698 /* handle the auth3 in the auth code */
699 if (!dcesrv_auth_auth3(call)) {
700 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
705 /* we don't send a reply to a auth3 request, except by a
712 handle a bind request
714 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
716 uint32_t if_version, transfer_syntax_version;
717 struct dcesrv_connection_context *context;
718 const struct dcesrv_interface *iface;
719 struct GUID uuid, *transfer_syntax_uuid;
722 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
723 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
725 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
726 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
727 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
728 ndr_transfer_syntax.if_version != transfer_syntax_version) {
729 /* we only do NDR encoded dcerpc */
730 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
733 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
735 char *uuid_str = GUID_string(call, &uuid);
736 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
737 talloc_free(uuid_str);
738 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
741 /* add this context to the list of available context_ids */
742 context = talloc(call->conn, struct dcesrv_connection_context);
743 if (context == NULL) {
744 return NT_STATUS_NO_MEMORY;
746 context->conn = call->conn;
747 context->iface = iface;
748 context->context_id = context_id;
749 context->private = NULL;
750 context->handles = NULL;
751 DLIST_ADD(call->conn->contexts, context);
752 call->context = context;
755 status = iface->bind(call, iface);
756 if (!NT_STATUS_IS_OK(status)) {
766 handle a alter context request
768 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
770 struct ncacn_packet pkt;
771 struct data_blob_list_item *rep;
773 uint32_t result=0, reason=0;
776 /* handle any authentication that is being requested */
777 if (!dcesrv_auth_alter(call)) {
778 /* TODO: work out the right reject code */
779 result = DCERPC_BIND_PROVIDER_REJECT;
780 reason = DCERPC_BIND_REASON_ASYNTAX;
783 context_id = call->pkt.u.alter.ctx_list[0].context_id;
785 /* see if they are asking for a new interface */
787 dcesrv_find_context(call->conn, context_id) == NULL) {
788 status = dcesrv_alter_new_context(call, context_id);
789 if (!NT_STATUS_IS_OK(status)) {
790 result = DCERPC_BIND_PROVIDER_REJECT;
791 reason = DCERPC_BIND_REASON_ASYNTAX;
795 /* setup a alter_resp */
796 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
798 pkt.call_id = call->pkt.call_id;
799 pkt.ptype = DCERPC_PKT_ALTER_RESP;
800 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
801 pkt.u.alter_resp.max_xmit_frag = 0x2000;
802 pkt.u.alter_resp.max_recv_frag = 0x2000;
803 pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
804 pkt.u.alter_resp.num_results = 1;
805 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
806 if (!pkt.u.alter_resp.ctx_list) {
807 return NT_STATUS_NO_MEMORY;
809 pkt.u.alter_resp.ctx_list[0].result = result;
810 pkt.u.alter_resp.ctx_list[0].reason = reason;
811 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
812 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
813 pkt.u.alter_resp.secondary_address = "";
815 status = dcesrv_auth_alter_ack(call, &pkt);
816 if (!NT_STATUS_IS_OK(status)) {
817 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
818 || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
819 || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
820 || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
821 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
823 return dcesrv_fault(call, 0);
826 rep = talloc(call, struct data_blob_list_item);
828 return NT_STATUS_NO_MEMORY;
831 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
832 if (!NT_STATUS_IS_OK(status)) {
836 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
838 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
839 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
845 handle a dcerpc request packet
847 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
849 struct ndr_pull *pull;
851 struct dcesrv_connection_context *context;
853 /* if authenticated, and the mech we use can't do async replies, don't use them... */
854 if (call->conn->auth_state.gensec_security &&
855 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
856 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
859 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
860 if (context == NULL) {
861 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
864 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call,
865 lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
866 NT_STATUS_HAVE_NO_MEMORY(pull);
868 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
870 call->context = context;
871 call->ndr_pull = pull;
873 if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
874 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
877 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
878 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
881 /* unravel the NDR for the packet */
882 status = context->iface->ndr_pull(call, call, pull, &call->r);
883 if (!NT_STATUS_IS_OK(status)) {
884 return dcesrv_fault(call, call->fault_code);
887 if (pull->offset != pull->data_size) {
888 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
889 pull->data_size - pull->offset));
890 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
893 /* call the dispatch function */
894 status = context->iface->dispatch(call, call, call->r);
895 if (!NT_STATUS_IS_OK(status)) {
896 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
897 context->iface->name,
898 call->pkt.u.request.opnum,
899 dcerpc_errstr(pull, call->fault_code)));
900 return dcesrv_fault(call, call->fault_code);
903 /* add the call to the pending list */
904 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
906 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
910 return dcesrv_reply(call);
913 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
915 struct ndr_push *push;
918 uint32_t total_length, chunk_size;
919 struct dcesrv_connection_context *context = call->context;
922 /* call the reply function */
923 status = context->iface->reply(call, call, call->r);
924 if (!NT_STATUS_IS_OK(status)) {
925 return dcesrv_fault(call, call->fault_code);
928 /* form the reply NDR */
929 push = ndr_push_init_ctx(call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
930 NT_STATUS_HAVE_NO_MEMORY(push);
932 /* carry over the pointer count to the reply in case we are
933 using full pointer. See NDR specification for full
935 push->ptr_count = call->ndr_pull->ptr_count;
937 if (lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
938 push->flags |= LIBNDR_FLAG_BIGENDIAN;
941 status = context->iface->ndr_push(call, call, push, call->r);
942 if (!NT_STATUS_IS_OK(status)) {
943 return dcesrv_fault(call, call->fault_code);
946 stub = ndr_push_blob(push);
948 total_length = stub.length;
950 /* we can write a full max_recv_frag size, minus the dcerpc
951 request header size */
952 chunk_size = call->conn->cli_max_recv_frag;
953 chunk_size -= DCERPC_REQUEST_LENGTH;
954 if (call->conn->auth_state.gensec_security) {
955 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
956 sig_size = gensec_sig_size(call->conn->auth_state.gensec_security,
957 call->conn->cli_max_recv_frag);
958 chunk_size -= sig_size;
959 chunk_size -= (chunk_size % 16);
964 struct data_blob_list_item *rep;
965 struct ncacn_packet pkt;
967 rep = talloc(call, struct data_blob_list_item);
968 NT_STATUS_HAVE_NO_MEMORY(rep);
970 length = MIN(chunk_size, stub.length);
972 /* form the dcerpc response packet */
973 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
975 pkt.call_id = call->pkt.call_id;
976 pkt.ptype = DCERPC_PKT_RESPONSE;
978 if (stub.length == total_length) {
979 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
981 if (length == stub.length) {
982 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
984 pkt.u.response.alloc_hint = stub.length;
985 pkt.u.response.context_id = call->pkt.u.request.context_id;
986 pkt.u.response.cancel_count = 0;
987 pkt.u.response.stub_and_verifier.data = stub.data;
988 pkt.u.response.stub_and_verifier.length = length;
990 if (!dcesrv_auth_response(call, &rep->blob, sig_size, &pkt)) {
991 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
994 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
996 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
999 stub.length -= length;
1000 } while (stub.length != 0);
1002 /* move the call from the pending to the finished calls list */
1003 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
1005 if (call->conn->call_list && call->conn->call_list->replies) {
1006 if (call->conn->transport.report_output_data) {
1007 call->conn->transport.report_output_data(call->conn);
1011 return NT_STATUS_OK;
1014 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1016 if (!conn->transport.get_my_addr) {
1020 return conn->transport.get_my_addr(conn, mem_ctx);
1023 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1025 if (!conn->transport.get_peer_addr) {
1029 return conn->transport.get_peer_addr(conn, mem_ctx);
1033 work out if we have a full packet yet
1035 static bool dce_full_packet(const DATA_BLOB *data)
1037 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
1040 if (dcerpc_get_frag_length(data) > data->length) {
1047 we might have consumed only part of our input - advance past that part
1049 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
1053 if (dce_conn->partial_input.length == offset) {
1054 data_blob_free(&dce_conn->partial_input);
1058 blob = dce_conn->partial_input;
1059 dce_conn->partial_input = data_blob(blob.data + offset,
1060 blob.length - offset);
1061 data_blob_free(&blob);
1065 remove the call from the right list when freed
1067 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1069 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1074 process some input to a dcerpc endpoint server.
1076 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
1078 struct ndr_pull *ndr;
1079 enum ndr_err_code ndr_err;
1081 struct dcesrv_call_state *call;
1084 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1086 talloc_free(dce_conn->partial_input.data);
1087 return NT_STATUS_NO_MEMORY;
1089 call->conn = dce_conn;
1090 call->event_ctx = dce_conn->event_ctx;
1091 call->msg_ctx = dce_conn->msg_ctx;
1092 call->state_flags = call->conn->state_flags;
1093 call->time = timeval_current();
1094 call->list = DCESRV_LIST_NONE;
1096 talloc_set_destructor(call, dcesrv_call_dequeue);
1098 blob = dce_conn->partial_input;
1099 blob.length = dcerpc_get_frag_length(&blob);
1101 ndr = ndr_pull_init_blob(&blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
1103 talloc_free(dce_conn->partial_input.data);
1105 return NT_STATUS_NO_MEMORY;
1108 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
1109 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
1112 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
1113 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1114 talloc_free(dce_conn->partial_input.data);
1116 return ndr_map_error2ntstatus(ndr_err);
1119 /* we have to check the signing here, before combining the
1121 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1122 !dcesrv_auth_request(call, &blob)) {
1123 dce_partial_advance(dce_conn, blob.length);
1124 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1127 dce_partial_advance(dce_conn, blob.length);
1129 /* see if this is a continued packet */
1130 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1131 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1132 struct dcesrv_call_state *call2 = call;
1133 uint32_t alloc_size;
1135 /* we only allow fragmented requests, no other packet types */
1136 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1137 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1140 /* this is a continuation of an existing call - find the call then
1141 tack it on the end */
1142 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1144 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1147 if (call->pkt.ptype != call2->pkt.ptype) {
1148 /* trying to play silly buggers are we? */
1149 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1152 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1153 call2->pkt.u.request.stub_and_verifier.length;
1154 if (call->pkt.u.request.alloc_hint > alloc_size) {
1155 alloc_size = call->pkt.u.request.alloc_hint;
1158 call->pkt.u.request.stub_and_verifier.data =
1159 talloc_realloc(call,
1160 call->pkt.u.request.stub_and_verifier.data,
1161 uint8_t, alloc_size);
1162 if (!call->pkt.u.request.stub_and_verifier.data) {
1163 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1165 memcpy(call->pkt.u.request.stub_and_verifier.data +
1166 call->pkt.u.request.stub_and_verifier.length,
1167 call2->pkt.u.request.stub_and_verifier.data,
1168 call2->pkt.u.request.stub_and_verifier.length);
1169 call->pkt.u.request.stub_and_verifier.length +=
1170 call2->pkt.u.request.stub_and_verifier.length;
1172 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1177 /* this may not be the last pdu in the chain - if its isn't then
1178 just put it on the incoming_fragmented_call_list and wait for the rest */
1179 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1180 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1181 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1182 return NT_STATUS_OK;
1185 /* This removes any fragments we may have had stashed away */
1186 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1188 switch (call->pkt.ptype) {
1189 case DCERPC_PKT_BIND:
1190 status = dcesrv_bind(call);
1192 case DCERPC_PKT_AUTH3:
1193 status = dcesrv_auth3(call);
1195 case DCERPC_PKT_ALTER:
1196 status = dcesrv_alter(call);
1198 case DCERPC_PKT_REQUEST:
1199 status = dcesrv_request(call);
1202 status = NT_STATUS_INVALID_PARAMETER;
1206 /* if we are going to be sending a reply then add
1207 it to the list of pending calls. We add it to the end to keep the call
1208 list in the order we will answer */
1209 if (!NT_STATUS_IS_OK(status)) {
1218 provide some input to a dcerpc endpoint server. This passes data
1219 from a dcerpc client into the server
1221 _PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1225 dce_conn->partial_input.data = talloc_realloc(dce_conn,
1226 dce_conn->partial_input.data,
1228 dce_conn->partial_input.length + data->length);
1229 if (!dce_conn->partial_input.data) {
1230 return NT_STATUS_NO_MEMORY;
1232 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1233 data->data, data->length);
1234 dce_conn->partial_input.length += data->length;
1236 while (dce_full_packet(&dce_conn->partial_input)) {
1237 status = dcesrv_input_process(dce_conn);
1238 if (!NT_STATUS_IS_OK(status)) {
1243 return NT_STATUS_OK;
1247 retrieve some output from a dcerpc server
1248 The caller supplies a function that will be called to do the
1251 The first argument to write_fn() will be 'private', the second will
1252 be a pointer to a buffer containing the data to be sent and the 3rd
1253 will be a pointer to a size_t variable that will be set to the
1254 number of bytes that are consumed from the output.
1256 from the current fragment
1258 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
1260 NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1263 struct dcesrv_call_state *call;
1264 struct data_blob_list_item *rep;
1267 call = dce_conn->call_list;
1268 if (!call || !call->replies) {
1269 if (dce_conn->pending_call_list) {
1270 /* TODO: we need to say act async here
1271 * as we know we have pending requests
1272 * which will be finished at a time
1274 return NT_STATUS_FOOBAR;
1276 return NT_STATUS_FOOBAR;
1278 rep = call->replies;
1280 status = write_fn(private_data, &rep->blob, &nwritten);
1281 NT_STATUS_IS_ERR_RETURN(status);
1283 rep->blob.length -= nwritten;
1284 rep->blob.data += nwritten;
1286 if (rep->blob.length == 0) {
1287 /* we're done with this section of the call */
1288 DLIST_REMOVE(call->replies, rep);
1291 if (call->replies == NULL) {
1292 /* we're done with the whole call */
1293 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1300 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1301 struct loadparm_context *lp_ctx,
1302 const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1305 struct dcesrv_context *dce_ctx;
1308 if (!endpoint_servers) {
1309 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1310 return NT_STATUS_INTERNAL_ERROR;
1313 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1314 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1315 dce_ctx->endpoint_list = NULL;
1316 dce_ctx->lp_ctx = lp_ctx;
1318 for (i=0;endpoint_servers[i];i++) {
1319 const struct dcesrv_endpoint_server *ep_server;
1321 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1323 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1324 return NT_STATUS_INTERNAL_ERROR;
1327 status = ep_server->init_server(dce_ctx, ep_server);
1328 if (!NT_STATUS_IS_OK(status)) {
1329 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1330 nt_errstr(status)));
1335 *_dce_ctx = dce_ctx;
1336 return NT_STATUS_OK;
1339 /* the list of currently registered DCERPC endpoint servers.
1341 static struct ep_server {
1342 struct dcesrv_endpoint_server *ep_server;
1343 } *ep_servers = NULL;
1344 static int num_ep_servers;
1347 register a DCERPC endpoint server.
1349 The 'name' can be later used by other backends to find the operations
1350 structure for this backend.
1352 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1354 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1356 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1358 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1359 /* its already registered! */
1360 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1362 return NT_STATUS_OBJECT_NAME_COLLISION;
1365 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1367 smb_panic("out of memory in dcerpc_register");
1370 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1371 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1375 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1378 return NT_STATUS_OK;
1382 return the operations structure for a named backend of the specified type
1384 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1388 for (i=0;i<num_ep_servers;i++) {
1389 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1390 return ep_servers[i].ep_server;
1398 return the DCERPC module version, and the size of some critical types
1399 This can be used by endpoint server modules to either detect compilation errors, or provide
1400 multiple implementations for different smbd compilation options in one module
1402 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1404 static const struct dcesrv_critical_sizes critical_sizes = {
1405 DCERPC_MODULE_VERSION,
1406 sizeof(struct dcesrv_context),
1407 sizeof(struct dcesrv_endpoint),
1408 sizeof(struct dcesrv_endpoint_server),
1409 sizeof(struct dcesrv_interface),
1410 sizeof(struct dcesrv_if_list),
1411 sizeof(struct dcesrv_connection),
1412 sizeof(struct dcesrv_call_state),
1413 sizeof(struct dcesrv_auth),
1414 sizeof(struct dcesrv_handle)
1417 return &critical_sizes;
1421 initialise the dcerpc server context for ncacn_np based services
1423 _PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
1424 struct dcesrv_context **_dce_ctx)
1427 struct dcesrv_context *dce_ctx;
1429 status = dcesrv_init_context(mem_ctx, lp_ctx, lp_dcerpc_endpoint_servers(lp_ctx), &dce_ctx);
1430 NT_STATUS_NOT_OK_RETURN(status);
1432 *_dce_ctx = dce_ctx;
1433 return NT_STATUS_OK;