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;
921 /* call the reply function */
922 status = context->iface->reply(call, call, call->r);
923 if (!NT_STATUS_IS_OK(status)) {
924 return dcesrv_fault(call, call->fault_code);
927 /* form the reply NDR */
928 push = ndr_push_init_ctx(call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
929 NT_STATUS_HAVE_NO_MEMORY(push);
931 /* carry over the pointer count to the reply in case we are
932 using full pointer. See NDR specification for full
934 push->ptr_count = call->ndr_pull->ptr_count;
936 if (lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
937 push->flags |= LIBNDR_FLAG_BIGENDIAN;
940 status = context->iface->ndr_push(call, call, push, call->r);
941 if (!NT_STATUS_IS_OK(status)) {
942 return dcesrv_fault(call, call->fault_code);
945 stub = ndr_push_blob(push);
947 total_length = stub.length;
949 /* we can write a full max_recv_frag size, minus the dcerpc
950 request header size */
951 chunk_size = call->conn->cli_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
955 struct data_blob_list_item *rep;
956 struct ncacn_packet pkt;
958 rep = talloc(call, struct data_blob_list_item);
959 NT_STATUS_HAVE_NO_MEMORY(rep);
961 length = MIN(chunk_size, stub.length);
963 /* form the dcerpc response packet */
964 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
966 pkt.call_id = call->pkt.call_id;
967 pkt.ptype = DCERPC_PKT_RESPONSE;
969 if (stub.length == total_length) {
970 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
972 if (length == stub.length) {
973 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
975 pkt.u.response.alloc_hint = stub.length;
976 pkt.u.response.context_id = call->pkt.u.request.context_id;
977 pkt.u.response.cancel_count = 0;
978 pkt.u.response.stub_and_verifier.data = stub.data;
979 pkt.u.response.stub_and_verifier.length = length;
981 if (!dcesrv_auth_response(call, &rep->blob, &pkt)) {
982 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
985 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
987 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
990 stub.length -= length;
991 } while (stub.length != 0);
993 /* move the call from the pending to the finished calls list */
994 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
996 if (call->conn->call_list && call->conn->call_list->replies) {
997 if (call->conn->transport.report_output_data) {
998 call->conn->transport.report_output_data(call->conn);
1002 return NT_STATUS_OK;
1005 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1007 if (!conn->transport.get_my_addr) {
1011 return conn->transport.get_my_addr(conn, mem_ctx);
1014 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1016 if (!conn->transport.get_peer_addr) {
1020 return conn->transport.get_peer_addr(conn, mem_ctx);
1024 work out if we have a full packet yet
1026 static bool dce_full_packet(const DATA_BLOB *data)
1028 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
1031 if (dcerpc_get_frag_length(data) > data->length) {
1038 we might have consumed only part of our input - advance past that part
1040 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
1044 if (dce_conn->partial_input.length == offset) {
1045 data_blob_free(&dce_conn->partial_input);
1049 blob = dce_conn->partial_input;
1050 dce_conn->partial_input = data_blob(blob.data + offset,
1051 blob.length - offset);
1052 data_blob_free(&blob);
1056 remove the call from the right list when freed
1058 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1060 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1065 process some input to a dcerpc endpoint server.
1067 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
1069 struct ndr_pull *ndr;
1070 enum ndr_err_code ndr_err;
1072 struct dcesrv_call_state *call;
1075 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1077 talloc_free(dce_conn->partial_input.data);
1078 return NT_STATUS_NO_MEMORY;
1080 call->conn = dce_conn;
1081 call->event_ctx = dce_conn->event_ctx;
1082 call->msg_ctx = dce_conn->msg_ctx;
1083 call->state_flags = call->conn->state_flags;
1084 call->time = timeval_current();
1085 call->list = DCESRV_LIST_NONE;
1087 talloc_set_destructor(call, dcesrv_call_dequeue);
1089 blob = dce_conn->partial_input;
1090 blob.length = dcerpc_get_frag_length(&blob);
1092 ndr = ndr_pull_init_blob(&blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
1094 talloc_free(dce_conn->partial_input.data);
1096 return NT_STATUS_NO_MEMORY;
1099 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
1100 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
1103 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
1104 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1105 talloc_free(dce_conn->partial_input.data);
1107 return ndr_map_error2ntstatus(ndr_err);
1110 /* we have to check the signing here, before combining the
1112 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1113 !dcesrv_auth_request(call, &blob)) {
1114 dce_partial_advance(dce_conn, blob.length);
1115 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1118 dce_partial_advance(dce_conn, blob.length);
1120 /* see if this is a continued packet */
1121 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1122 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1123 struct dcesrv_call_state *call2 = call;
1124 uint32_t alloc_size;
1126 /* we only allow fragmented requests, no other packet types */
1127 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1128 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1131 /* this is a continuation of an existing call - find the call then
1132 tack it on the end */
1133 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1135 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1138 if (call->pkt.ptype != call2->pkt.ptype) {
1139 /* trying to play silly buggers are we? */
1140 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1143 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1144 call2->pkt.u.request.stub_and_verifier.length;
1145 if (call->pkt.u.request.alloc_hint > alloc_size) {
1146 alloc_size = call->pkt.u.request.alloc_hint;
1149 call->pkt.u.request.stub_and_verifier.data =
1150 talloc_realloc(call,
1151 call->pkt.u.request.stub_and_verifier.data,
1152 uint8_t, alloc_size);
1153 if (!call->pkt.u.request.stub_and_verifier.data) {
1154 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1156 memcpy(call->pkt.u.request.stub_and_verifier.data +
1157 call->pkt.u.request.stub_and_verifier.length,
1158 call2->pkt.u.request.stub_and_verifier.data,
1159 call2->pkt.u.request.stub_and_verifier.length);
1160 call->pkt.u.request.stub_and_verifier.length +=
1161 call2->pkt.u.request.stub_and_verifier.length;
1163 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1168 /* this may not be the last pdu in the chain - if its isn't then
1169 just put it on the incoming_fragmented_call_list and wait for the rest */
1170 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1171 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1172 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1173 return NT_STATUS_OK;
1176 /* This removes any fragments we may have had stashed away */
1177 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1179 switch (call->pkt.ptype) {
1180 case DCERPC_PKT_BIND:
1181 status = dcesrv_bind(call);
1183 case DCERPC_PKT_AUTH3:
1184 status = dcesrv_auth3(call);
1186 case DCERPC_PKT_ALTER:
1187 status = dcesrv_alter(call);
1189 case DCERPC_PKT_REQUEST:
1190 status = dcesrv_request(call);
1193 status = NT_STATUS_INVALID_PARAMETER;
1197 /* if we are going to be sending a reply then add
1198 it to the list of pending calls. We add it to the end to keep the call
1199 list in the order we will answer */
1200 if (!NT_STATUS_IS_OK(status)) {
1209 provide some input to a dcerpc endpoint server. This passes data
1210 from a dcerpc client into the server
1212 _PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1216 dce_conn->partial_input.data = talloc_realloc(dce_conn,
1217 dce_conn->partial_input.data,
1219 dce_conn->partial_input.length + data->length);
1220 if (!dce_conn->partial_input.data) {
1221 return NT_STATUS_NO_MEMORY;
1223 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1224 data->data, data->length);
1225 dce_conn->partial_input.length += data->length;
1227 while (dce_full_packet(&dce_conn->partial_input)) {
1228 status = dcesrv_input_process(dce_conn);
1229 if (!NT_STATUS_IS_OK(status)) {
1234 return NT_STATUS_OK;
1238 retrieve some output from a dcerpc server
1239 The caller supplies a function that will be called to do the
1242 The first argument to write_fn() will be 'private', the second will
1243 be a pointer to a buffer containing the data to be sent and the 3rd
1244 will be a pointer to a size_t variable that will be set to the
1245 number of bytes that are consumed from the output.
1247 from the current fragment
1249 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
1251 NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1254 struct dcesrv_call_state *call;
1255 struct data_blob_list_item *rep;
1258 call = dce_conn->call_list;
1259 if (!call || !call->replies) {
1260 if (dce_conn->pending_call_list) {
1261 /* TODO: we need to say act async here
1262 * as we know we have pending requests
1263 * which will be finished at a time
1265 return NT_STATUS_FOOBAR;
1267 return NT_STATUS_FOOBAR;
1269 rep = call->replies;
1271 status = write_fn(private_data, &rep->blob, &nwritten);
1272 NT_STATUS_IS_ERR_RETURN(status);
1274 rep->blob.length -= nwritten;
1275 rep->blob.data += nwritten;
1277 if (rep->blob.length == 0) {
1278 /* we're done with this section of the call */
1279 DLIST_REMOVE(call->replies, rep);
1282 if (call->replies == NULL) {
1283 /* we're done with the whole call */
1284 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1291 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1292 struct loadparm_context *lp_ctx,
1293 const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1296 struct dcesrv_context *dce_ctx;
1299 if (!endpoint_servers) {
1300 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1301 return NT_STATUS_INTERNAL_ERROR;
1304 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1305 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1306 dce_ctx->endpoint_list = NULL;
1307 dce_ctx->lp_ctx = lp_ctx;
1309 for (i=0;endpoint_servers[i];i++) {
1310 const struct dcesrv_endpoint_server *ep_server;
1312 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1314 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1315 return NT_STATUS_INTERNAL_ERROR;
1318 status = ep_server->init_server(dce_ctx, ep_server);
1319 if (!NT_STATUS_IS_OK(status)) {
1320 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1321 nt_errstr(status)));
1326 *_dce_ctx = dce_ctx;
1327 return NT_STATUS_OK;
1330 /* the list of currently registered DCERPC endpoint servers.
1332 static struct ep_server {
1333 struct dcesrv_endpoint_server *ep_server;
1334 } *ep_servers = NULL;
1335 static int num_ep_servers;
1338 register a DCERPC endpoint server.
1340 The 'name' can be later used by other backends to find the operations
1341 structure for this backend.
1343 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1345 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1347 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1349 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1350 /* its already registered! */
1351 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1353 return NT_STATUS_OBJECT_NAME_COLLISION;
1356 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1358 smb_panic("out of memory in dcerpc_register");
1361 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1362 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1366 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1369 return NT_STATUS_OK;
1373 return the operations structure for a named backend of the specified type
1375 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1379 for (i=0;i<num_ep_servers;i++) {
1380 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1381 return ep_servers[i].ep_server;
1389 return the DCERPC module version, and the size of some critical types
1390 This can be used by endpoint server modules to either detect compilation errors, or provide
1391 multiple implementations for different smbd compilation options in one module
1393 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1395 static const struct dcesrv_critical_sizes critical_sizes = {
1396 DCERPC_MODULE_VERSION,
1397 sizeof(struct dcesrv_context),
1398 sizeof(struct dcesrv_endpoint),
1399 sizeof(struct dcesrv_endpoint_server),
1400 sizeof(struct dcesrv_interface),
1401 sizeof(struct dcesrv_if_list),
1402 sizeof(struct dcesrv_connection),
1403 sizeof(struct dcesrv_call_state),
1404 sizeof(struct dcesrv_auth),
1405 sizeof(struct dcesrv_handle)
1408 return &critical_sizes;
1412 initialise the dcerpc server context for ncacn_np based services
1414 _PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
1415 struct dcesrv_context **_dce_ctx)
1418 struct dcesrv_context *dce_ctx;
1420 status = dcesrv_init_context(mem_ctx, lp_ctx, lp_dcerpc_endpoint_servers(lp_ctx), &dce_ctx);
1421 NT_STATUS_NOT_OK_RETURN(status);
1423 *_dce_ctx = dce_ctx;
1424 return NT_STATUS_OK;