s4: rpc: Refactor dcesrv_alter() function into setup and send steps.
[Samba.git] / source4 / rpc_server / dcerpc_server.c
blob04ba5f82e7269375aecbee0e46cd9f39ab0ec253
1 /*
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/>.
23 #include "includes.h"
24 #include "auth/auth.h"
25 #include "auth/gensec/gensec.h"
26 #include "../lib/util/dlinklist.h"
27 #include "rpc_server/dcerpc_server.h"
28 #include "rpc_server/dcerpc_server_proto.h"
29 #include "rpc_server/common/proto.h"
30 #include "librpc/rpc/dcerpc_proto.h"
31 #include "system/filesys.h"
32 #include "libcli/security/security.h"
33 #include "param/param.h"
34 #include "../lib/tsocket/tsocket.h"
35 #include "../libcli/named_pipe_auth/npa_tstream.h"
36 #include "smbd/service_stream.h"
37 #include "../lib/tsocket/tsocket.h"
38 #include "lib/socket/socket.h"
39 #include "smbd/process_model.h"
40 #include "lib/messaging/irpc.h"
41 #include "librpc/rpc/rpc_common.h"
42 #include "lib/util/samba_modules.h"
44 /* this is only used when the client asks for an unknown interface */
45 #define DUMMY_ASSOC_GROUP 0x0FFFFFFF
47 extern const struct dcesrv_interface dcesrv_mgmt_interface;
51 find an association group given a assoc_group_id
53 static struct dcesrv_assoc_group *dcesrv_assoc_group_find(struct dcesrv_context *dce_ctx,
54 uint32_t id)
56 void *id_ptr;
58 id_ptr = idr_find(dce_ctx->assoc_groups_idr, id);
59 if (id_ptr == NULL) {
60 return NULL;
62 return talloc_get_type_abort(id_ptr, struct dcesrv_assoc_group);
66 take a reference to an existing association group
68 static struct dcesrv_assoc_group *dcesrv_assoc_group_reference(TALLOC_CTX *mem_ctx,
69 struct dcesrv_context *dce_ctx,
70 uint32_t id)
72 struct dcesrv_assoc_group *assoc_group;
74 assoc_group = dcesrv_assoc_group_find(dce_ctx, id);
75 if (assoc_group == NULL) {
76 DEBUG(0,(__location__ ": Failed to find assoc_group 0x%08x\n", id));
77 return NULL;
79 return talloc_reference(mem_ctx, assoc_group);
82 static int dcesrv_assoc_group_destructor(struct dcesrv_assoc_group *assoc_group)
84 int ret;
85 ret = idr_remove(assoc_group->dce_ctx->assoc_groups_idr, assoc_group->id);
86 if (ret != 0) {
87 DEBUG(0,(__location__ ": Failed to remove assoc_group 0x%08x\n",
88 assoc_group->id));
90 return 0;
94 allocate a new association group
96 static struct dcesrv_assoc_group *dcesrv_assoc_group_new(TALLOC_CTX *mem_ctx,
97 struct dcesrv_context *dce_ctx)
99 struct dcesrv_assoc_group *assoc_group;
100 int id;
102 assoc_group = talloc_zero(mem_ctx, struct dcesrv_assoc_group);
103 if (assoc_group == NULL) {
104 return NULL;
107 id = idr_get_new_random(dce_ctx->assoc_groups_idr, assoc_group, UINT16_MAX);
108 if (id == -1) {
109 talloc_free(assoc_group);
110 DEBUG(0,(__location__ ": Out of association groups!\n"));
111 return NULL;
114 assoc_group->id = id;
115 assoc_group->dce_ctx = dce_ctx;
117 talloc_set_destructor(assoc_group, dcesrv_assoc_group_destructor);
119 return assoc_group;
124 see if two endpoints match
126 static bool endpoints_match(const struct dcerpc_binding *ep1,
127 const struct dcerpc_binding *ep2)
129 if (ep1->transport != ep2->transport) {
130 return false;
133 if (!ep1->endpoint || !ep2->endpoint) {
134 return ep1->endpoint == ep2->endpoint;
137 if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
138 return false;
140 return true;
144 find an endpoint in the dcesrv_context
146 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
147 const struct dcerpc_binding *ep_description)
149 struct dcesrv_endpoint *ep;
150 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
151 if (endpoints_match(ep->ep_description, ep_description)) {
152 return ep;
155 return NULL;
159 find a registered context_id from a bind or alter_context
161 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn,
162 uint32_t context_id)
164 struct dcesrv_connection_context *c;
165 for (c=conn->contexts;c;c=c->next) {
166 if (c->context_id == context_id) return c;
168 return NULL;
172 see if a uuid and if_version match to an interface
174 static bool interface_match(const struct dcesrv_interface *if1,
175 const struct dcesrv_interface *if2)
177 return (if1->syntax_id.if_version == if2->syntax_id.if_version &&
178 GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
182 find the interface operations on an endpoint
184 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
185 const struct dcesrv_interface *iface)
187 struct dcesrv_if_list *ifl;
188 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
189 if (interface_match(&(ifl->iface), iface)) {
190 return &(ifl->iface);
193 return NULL;
197 see if a uuid and if_version match to an interface
199 static bool interface_match_by_uuid(const struct dcesrv_interface *iface,
200 const struct GUID *uuid, uint32_t if_version)
202 return (iface->syntax_id.if_version == if_version &&
203 GUID_equal(&iface->syntax_id.uuid, uuid));
207 find the interface operations on an endpoint by uuid
209 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
210 const struct GUID *uuid, uint32_t if_version)
212 struct dcesrv_if_list *ifl;
213 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
214 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
215 return &(ifl->iface);
218 return NULL;
222 find the earlier parts of a fragmented call awaiting reassembily
224 static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
226 struct dcesrv_call_state *c;
227 for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
228 if (c->pkt.call_id == call_id) {
229 return c;
232 return NULL;
236 register an interface on an endpoint
238 _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
239 const char *ep_name,
240 const struct dcesrv_interface *iface,
241 const struct security_descriptor *sd)
243 struct dcesrv_endpoint *ep;
244 struct dcesrv_if_list *ifl;
245 struct dcerpc_binding *binding;
246 bool add_ep = false;
247 NTSTATUS status;
249 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
251 if (NT_STATUS_IS_ERR(status)) {
252 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
253 return status;
256 /* check if this endpoint exists
258 if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
259 ep = talloc(dce_ctx, struct dcesrv_endpoint);
260 if (!ep) {
261 return NT_STATUS_NO_MEMORY;
263 ZERO_STRUCTP(ep);
264 ep->ep_description = talloc_reference(ep, binding);
265 add_ep = true;
267 /* add mgmt interface */
268 ifl = talloc(dce_ctx, struct dcesrv_if_list);
269 if (!ifl) {
270 return NT_STATUS_NO_MEMORY;
273 memcpy(&(ifl->iface), &dcesrv_mgmt_interface,
274 sizeof(struct dcesrv_interface));
276 DLIST_ADD(ep->interface_list, ifl);
279 /* see if the interface is already registered on te endpoint */
280 if (find_interface(ep, iface)!=NULL) {
281 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
282 iface->name, ep_name));
283 return NT_STATUS_OBJECT_NAME_COLLISION;
286 /* talloc a new interface list element */
287 ifl = talloc(dce_ctx, struct dcesrv_if_list);
288 if (!ifl) {
289 return NT_STATUS_NO_MEMORY;
292 /* copy the given interface struct to the one on the endpoints interface list */
293 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
295 /* if we have a security descriptor given,
296 * we should see if we can set it up on the endpoint
298 if (sd != NULL) {
299 /* if there's currently no security descriptor given on the endpoint
300 * we try to set it
302 if (ep->sd == NULL) {
303 ep->sd = security_descriptor_copy(dce_ctx, sd);
306 /* if now there's no security descriptor given on the endpoint
307 * something goes wrong, either we failed to copy the security descriptor
308 * or there was already one on the endpoint
310 if (ep->sd != NULL) {
311 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
312 " on endpoint '%s'\n",
313 iface->name, ep_name));
314 if (add_ep) free(ep);
315 free(ifl);
316 return NT_STATUS_OBJECT_NAME_COLLISION;
320 /* finally add the interface on the endpoint */
321 DLIST_ADD(ep->interface_list, ifl);
323 /* if it's a new endpoint add it to the dcesrv_context */
324 if (add_ep) {
325 DLIST_ADD(dce_ctx->endpoint_list, ep);
328 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
329 iface->name, ep_name));
331 return NT_STATUS_OK;
334 NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
335 DATA_BLOB *session_key)
337 if (p->auth_state.session_info->session_key.length) {
338 *session_key = p->auth_state.session_info->session_key;
339 return NT_STATUS_OK;
341 return NT_STATUS_NO_USER_SESSION_KEY;
345 fetch the user session key - may be default (above) or the SMB session key
347 The key is always truncated to 16 bytes
349 _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
350 DATA_BLOB *session_key)
352 NTSTATUS status = p->auth_state.session_key(p, session_key);
353 if (!NT_STATUS_IS_OK(status)) {
354 return status;
357 session_key->length = MIN(session_key->length, 16);
359 return NT_STATUS_OK;
363 connect to a dcerpc endpoint
365 _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
366 TALLOC_CTX *mem_ctx,
367 const struct dcesrv_endpoint *ep,
368 struct auth_session_info *session_info,
369 struct tevent_context *event_ctx,
370 struct imessaging_context *msg_ctx,
371 struct server_id server_id,
372 uint32_t state_flags,
373 struct dcesrv_connection **_p)
375 struct dcesrv_connection *p;
377 if (!session_info) {
378 return NT_STATUS_ACCESS_DENIED;
381 p = talloc(mem_ctx, struct dcesrv_connection);
382 NT_STATUS_HAVE_NO_MEMORY(p);
384 if (!talloc_reference(p, session_info)) {
385 talloc_free(p);
386 return NT_STATUS_NO_MEMORY;
389 p->prev = NULL;
390 p->next = NULL;
391 p->dce_ctx = dce_ctx;
392 p->endpoint = ep;
393 p->contexts = NULL;
394 p->call_list = NULL;
395 p->packet_log_dir = lpcfg_lockdir(dce_ctx->lp_ctx);
396 p->incoming_fragmented_call_list = NULL;
397 p->pending_call_list = NULL;
398 p->cli_max_recv_frag = 0;
399 p->partial_input = data_blob(NULL, 0);
400 p->auth_state.auth_info = NULL;
401 p->auth_state.gensec_security = NULL;
402 p->auth_state.session_info = session_info;
403 p->auth_state.session_key = dcesrv_generic_session_key;
404 p->event_ctx = event_ctx;
405 p->msg_ctx = msg_ctx;
406 p->server_id = server_id;
407 p->terminate = NULL;
408 p->state_flags = state_flags;
409 ZERO_STRUCT(p->transport);
411 *_p = p;
412 return NT_STATUS_OK;
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
418 list when moving it.
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:
425 break;
426 case DCESRV_LIST_CALL_LIST:
427 DLIST_REMOVE(call->conn->call_list, call);
428 break;
429 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
430 DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
431 break;
432 case DCESRV_LIST_PENDING_CALL_LIST:
433 DLIST_REMOVE(call->conn->pending_call_list, call);
434 break;
436 call->list = list;
437 switch (list) {
438 case DCESRV_LIST_NONE:
439 break;
440 case DCESRV_LIST_CALL_LIST:
441 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
442 break;
443 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
444 DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
445 break;
446 case DCESRV_LIST_PENDING_CALL_LIST:
447 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
448 break;
454 return a dcerpc bind_nak
456 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
458 struct ncacn_packet pkt;
459 struct data_blob_list_item *rep;
460 NTSTATUS status;
462 /* setup a bind_nak */
463 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
464 pkt.auth_length = 0;
465 pkt.call_id = call->pkt.call_id;
466 pkt.ptype = DCERPC_PKT_BIND_NAK;
467 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
468 pkt.u.bind_nak.reject_reason = reason;
469 if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
470 pkt.u.bind_nak.versions.v.num_versions = 0;
473 rep = talloc(call, struct data_blob_list_item);
474 if (!rep) {
475 return NT_STATUS_NO_MEMORY;
478 status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
479 if (!NT_STATUS_IS_OK(status)) {
480 return status;
483 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
485 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
486 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
488 if (call->conn->call_list && call->conn->call_list->replies) {
489 if (call->conn->transport.report_output_data) {
490 call->conn->transport.report_output_data(call->conn);
494 return NT_STATUS_OK;
497 static int dcesrv_connection_context_destructor(struct dcesrv_connection_context *c)
499 DLIST_REMOVE(c->conn->contexts, c);
501 if (c->iface && c->iface->unbind) {
502 c->iface->unbind(c, c->iface);
503 c->iface = NULL;
506 return 0;
510 handle a bind request
512 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
514 uint32_t if_version, transfer_syntax_version;
515 struct GUID uuid, *transfer_syntax_uuid;
516 struct ncacn_packet pkt;
517 struct data_blob_list_item *rep;
518 NTSTATUS status;
519 uint32_t result=0, reason=0;
520 uint32_t context_id;
521 const struct dcesrv_interface *iface;
522 uint32_t extra_flags = 0;
525 if provided, check the assoc_group is valid
527 if (call->pkt.u.bind.assoc_group_id != 0 &&
528 lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
529 dcesrv_assoc_group_find(call->conn->dce_ctx, call->pkt.u.bind.assoc_group_id) == NULL) {
530 return dcesrv_bind_nak(call, 0);
533 if (call->pkt.u.bind.num_contexts < 1 ||
534 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
535 return dcesrv_bind_nak(call, 0);
538 context_id = call->pkt.u.bind.ctx_list[0].context_id;
540 /* you can't bind twice on one context */
541 if (dcesrv_find_context(call->conn, context_id) != NULL) {
542 return dcesrv_bind_nak(call, 0);
545 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
546 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
548 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
549 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
550 if (!GUID_equal(&ndr_transfer_syntax_ndr.uuid, transfer_syntax_uuid) != 0 ||
551 ndr_transfer_syntax_ndr.if_version != transfer_syntax_version) {
552 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
553 /* we only do NDR encoded dcerpc */
554 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
555 talloc_free(uuid_str);
556 return dcesrv_bind_nak(call, 0);
559 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
560 if (iface == NULL) {
561 char *uuid_str = GUID_string(call, &uuid);
562 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
563 talloc_free(uuid_str);
565 /* we don't know about that interface */
566 result = DCERPC_BIND_PROVIDER_REJECT;
567 reason = DCERPC_BIND_REASON_ASYNTAX;
570 if (iface) {
571 /* add this context to the list of available context_ids */
572 struct dcesrv_connection_context *context = talloc(call->conn,
573 struct dcesrv_connection_context);
574 if (context == NULL) {
575 return dcesrv_bind_nak(call, 0);
577 context->conn = call->conn;
578 context->iface = iface;
579 context->context_id = context_id;
580 if (call->pkt.u.bind.assoc_group_id != 0) {
581 context->assoc_group = dcesrv_assoc_group_reference(context,
582 call->conn->dce_ctx,
583 call->pkt.u.bind.assoc_group_id);
584 } else {
585 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
587 if (context->assoc_group == NULL) {
588 talloc_free(context);
589 return dcesrv_bind_nak(call, 0);
591 context->private_data = NULL;
592 DLIST_ADD(call->conn->contexts, context);
593 call->context = context;
594 talloc_set_destructor(context, dcesrv_connection_context_destructor);
596 status = iface->bind(call, iface, if_version);
597 if (!NT_STATUS_IS_OK(status)) {
598 char *uuid_str = GUID_string(call, &uuid);
599 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
600 uuid_str, if_version, nt_errstr(status)));
601 talloc_free(uuid_str);
602 /* we don't want to trigger the iface->unbind() hook */
603 context->iface = NULL;
604 talloc_free(call->context);
605 call->context = NULL;
606 return dcesrv_bind_nak(call, 0);
610 if (call->conn->cli_max_recv_frag == 0) {
611 call->conn->cli_max_recv_frag = MIN(0x2000, call->pkt.u.bind.max_recv_frag);
614 if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) &&
615 lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","header signing", false)) {
616 call->conn->state_flags |= DCESRV_CALL_STATE_FLAG_HEADER_SIGNING;
617 extra_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
620 if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_CONC_MPX) &&
621 (call->state_flags & DCESRV_CALL_STATE_FLAG_MULTIPLEXED)) {
622 call->context->conn->state_flags |= DCESRV_CALL_STATE_FLAG_MULTIPLEXED;
623 extra_flags |= DCERPC_PFC_FLAG_CONC_MPX;
626 if (call->state_flags & DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL) {
627 call->context->conn->state_flags |= DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL;
630 /* handle any authentication that is being requested */
631 if (!dcesrv_auth_bind(call)) {
632 talloc_free(call->context);
633 call->context = NULL;
634 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
637 /* setup a bind_ack */
638 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
639 pkt.auth_length = 0;
640 pkt.call_id = call->pkt.call_id;
641 pkt.ptype = DCERPC_PKT_BIND_ACK;
642 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
643 pkt.u.bind_ack.max_xmit_frag = call->conn->cli_max_recv_frag;
644 pkt.u.bind_ack.max_recv_frag = 0x2000;
647 make it possible for iface->bind() to specify the assoc_group_id
648 This helps the openchange mapiproxy plugin to work correctly.
650 metze
652 if (call->context) {
653 pkt.u.bind_ack.assoc_group_id = call->context->assoc_group->id;
654 } else {
655 pkt.u.bind_ack.assoc_group_id = DUMMY_ASSOC_GROUP;
658 if (iface) {
659 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
660 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
661 } else {
662 pkt.u.bind_ack.secondary_address = "";
664 pkt.u.bind_ack.num_results = 1;
665 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
666 if (!pkt.u.bind_ack.ctx_list) {
667 talloc_free(call->context);
668 call->context = NULL;
669 return NT_STATUS_NO_MEMORY;
671 pkt.u.bind_ack.ctx_list[0].result = result;
672 pkt.u.bind_ack.ctx_list[0].reason = reason;
673 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax_ndr;
674 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
676 status = dcesrv_auth_bind_ack(call, &pkt);
677 if (!NT_STATUS_IS_OK(status)) {
678 talloc_free(call->context);
679 call->context = NULL;
680 return dcesrv_bind_nak(call, 0);
683 rep = talloc(call, struct data_blob_list_item);
684 if (!rep) {
685 talloc_free(call->context);
686 call->context = NULL;
687 return NT_STATUS_NO_MEMORY;
690 status = ncacn_push_auth(&rep->blob, call, &pkt,
691 call->conn->auth_state.auth_info);
692 if (!NT_STATUS_IS_OK(status)) {
693 talloc_free(call->context);
694 call->context = NULL;
695 return status;
698 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
700 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
701 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
703 if (call->conn->call_list && call->conn->call_list->replies) {
704 if (call->conn->transport.report_output_data) {
705 call->conn->transport.report_output_data(call->conn);
709 return NT_STATUS_OK;
714 handle a auth3 request
716 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
718 /* handle the auth3 in the auth code */
719 if (!dcesrv_auth_auth3(call)) {
720 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
723 talloc_free(call);
725 /* we don't send a reply to a auth3 request, except by a
726 fault */
727 return NT_STATUS_OK;
732 handle a bind request
734 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
736 uint32_t if_version, transfer_syntax_version;
737 struct dcesrv_connection_context *context;
738 const struct dcesrv_interface *iface;
739 struct GUID uuid, *transfer_syntax_uuid;
740 NTSTATUS status;
742 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
743 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
745 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
746 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
747 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax_ndr.uuid) ||
748 ndr_transfer_syntax_ndr.if_version != transfer_syntax_version) {
749 /* we only do NDR encoded dcerpc */
750 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
753 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
754 if (iface == NULL) {
755 char *uuid_str = GUID_string(call, &uuid);
756 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
757 talloc_free(uuid_str);
758 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
761 /* add this context to the list of available context_ids */
762 context = talloc(call->conn, struct dcesrv_connection_context);
763 if (context == NULL) {
764 return NT_STATUS_NO_MEMORY;
766 context->conn = call->conn;
767 context->iface = iface;
768 context->context_id = context_id;
769 if (call->pkt.u.alter.assoc_group_id != 0) {
770 context->assoc_group = dcesrv_assoc_group_reference(context,
771 call->conn->dce_ctx,
772 call->pkt.u.alter.assoc_group_id);
773 } else {
774 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
776 if (context->assoc_group == NULL) {
777 talloc_free(context);
778 call->context = NULL;
779 return NT_STATUS_NO_MEMORY;
781 context->private_data = NULL;
782 DLIST_ADD(call->conn->contexts, context);
783 call->context = context;
784 talloc_set_destructor(context, dcesrv_connection_context_destructor);
786 status = iface->bind(call, iface, if_version);
787 if (!NT_STATUS_IS_OK(status)) {
788 /* we don't want to trigger the iface->unbind() hook */
789 context->iface = NULL;
790 talloc_free(context);
791 call->context = NULL;
792 return status;
795 return NT_STATUS_OK;
798 /* setup and send an alter_resp */
799 static NTSTATUS dcesrv_alter_resp(struct dcesrv_call_state *call,
800 uint32_t result,
801 uint32_t reason)
803 struct ncacn_packet pkt;
804 uint32_t extra_flags = 0;
805 struct data_blob_list_item *rep = NULL;
806 NTSTATUS status;
808 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
809 pkt.auth_length = 0;
810 pkt.call_id = call->pkt.call_id;
811 pkt.ptype = DCERPC_PKT_ALTER_RESP;
812 if (result == 0) {
813 if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_CONC_MPX) &&
814 call->context->conn->state_flags &
815 DCESRV_CALL_STATE_FLAG_MULTIPLEXED) {
816 extra_flags |= DCERPC_PFC_FLAG_CONC_MPX;
818 if (call->state_flags & DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL) {
819 call->context->conn->state_flags |=
820 DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL;
823 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
824 pkt.u.alter_resp.max_xmit_frag = 0x2000;
825 pkt.u.alter_resp.max_recv_frag = 0x2000;
826 if (result == 0) {
827 pkt.u.alter_resp.assoc_group_id = call->context->assoc_group->id;
828 } else {
829 pkt.u.alter_resp.assoc_group_id = 0;
831 pkt.u.alter_resp.num_results = 1;
832 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
833 if (!pkt.u.alter_resp.ctx_list) {
834 return NT_STATUS_NO_MEMORY;
836 pkt.u.alter_resp.ctx_list[0].result = result;
837 pkt.u.alter_resp.ctx_list[0].reason = reason;
838 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax_ndr;
839 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
840 pkt.u.alter_resp.secondary_address = "";
842 status = dcesrv_auth_alter_ack(call, &pkt);
843 if (!NT_STATUS_IS_OK(status)) {
844 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
845 || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
846 || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
847 || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
848 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
850 return dcesrv_fault(call, 0);
853 rep = talloc(call, struct data_blob_list_item);
854 if (!rep) {
855 return NT_STATUS_NO_MEMORY;
858 status = ncacn_push_auth(&rep->blob, call, &pkt, call->conn->auth_state.auth_info);
859 if (!NT_STATUS_IS_OK(status)) {
860 return status;
863 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
865 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
866 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
868 if (call->conn->call_list && call->conn->call_list->replies) {
869 if (call->conn->transport.report_output_data) {
870 call->conn->transport.report_output_data(call->conn);
874 return NT_STATUS_OK;
878 handle a alter context request
880 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
882 NTSTATUS status;
883 uint32_t context_id;
885 /* handle any authentication that is being requested */
886 if (!dcesrv_auth_alter(call)) {
887 /* TODO: work out the right reject code */
888 return dcesrv_alter_resp(call,
889 DCERPC_BIND_PROVIDER_REJECT,
890 DCERPC_BIND_REASON_ASYNTAX);
893 context_id = call->pkt.u.alter.ctx_list[0].context_id;
895 /* see if they are asking for a new interface */
896 call->context = dcesrv_find_context(call->conn, context_id);
897 if (!call->context) {
898 status = dcesrv_alter_new_context(call, context_id);
899 if (!NT_STATUS_IS_OK(status)) {
900 return dcesrv_alter_resp(call,
901 DCERPC_BIND_PROVIDER_REJECT,
902 DCERPC_BIND_REASON_ASYNTAX);
906 if (call->pkt.u.alter.assoc_group_id != 0 &&
907 lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
908 call->pkt.u.alter.assoc_group_id != call->context->assoc_group->id) {
909 DEBUG(0,(__location__ ": Failed attempt to use new assoc_group in alter context (0x%08x 0x%08x)\n",
910 call->context->assoc_group->id, call->pkt.u.alter.assoc_group_id));
911 /* TODO: can they ask for a new association group? */
912 return dcesrv_alter_resp(call,
913 DCERPC_BIND_PROVIDER_REJECT,
914 DCERPC_BIND_REASON_ASYNTAX);
917 return dcesrv_alter_resp(call,
923 possibly save the call for inspection with ndrdump
925 static void dcesrv_save_call(struct dcesrv_call_state *call, const char *why)
927 #ifdef DEVELOPER
928 char *fname;
929 const char *dump_dir;
930 dump_dir = lpcfg_parm_string(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv", "stubs directory");
931 if (!dump_dir) {
932 return;
934 fname = talloc_asprintf(call, "%s/RPC-%s-%u-%s.dat",
935 dump_dir,
936 call->context->iface->name,
937 call->pkt.u.request.opnum,
938 why);
939 if (file_save(fname, call->pkt.u.request.stub_and_verifier.data, call->pkt.u.request.stub_and_verifier.length)) {
940 DEBUG(0,("RPC SAVED %s\n", fname));
942 talloc_free(fname);
943 #endif
947 handle a dcerpc request packet
949 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
951 struct ndr_pull *pull;
952 NTSTATUS status;
953 struct dcesrv_connection_context *context;
955 /* if authenticated, and the mech we use can't do async replies, don't use them... */
956 if (call->conn->auth_state.gensec_security &&
957 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
958 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
961 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
962 if (context == NULL) {
963 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
966 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
967 NT_STATUS_HAVE_NO_MEMORY(pull);
969 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
971 call->context = context;
972 call->ndr_pull = pull;
974 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
975 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
978 /* unravel the NDR for the packet */
979 status = context->iface->ndr_pull(call, call, pull, &call->r);
980 if (!NT_STATUS_IS_OK(status)) {
981 if (call->fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
982 /* we got an unknown call */
983 DEBUG(3,(__location__ ": Unknown RPC call %u on %s\n",
984 call->pkt.u.request.opnum, context->iface->name));
985 dcesrv_save_call(call, "unknown");
986 } else {
987 dcesrv_save_call(call, "pullfail");
989 return dcesrv_fault(call, call->fault_code);
992 if (pull->offset != pull->data_size) {
993 dcesrv_save_call(call, "extrabytes");
994 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
995 pull->data_size - pull->offset));
998 /* call the dispatch function */
999 status = context->iface->dispatch(call, call, call->r);
1000 if (!NT_STATUS_IS_OK(status)) {
1001 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
1002 context->iface->name,
1003 call->pkt.u.request.opnum,
1004 dcerpc_errstr(pull, call->fault_code)));
1005 return dcesrv_fault(call, call->fault_code);
1008 /* add the call to the pending list */
1009 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
1011 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
1012 return NT_STATUS_OK;
1015 return dcesrv_reply(call);
1020 remove the call from the right list when freed
1022 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1024 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1025 return 0;
1028 _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_local_address(struct dcesrv_connection *conn)
1030 return conn->local_address;
1033 _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_remote_address(struct dcesrv_connection *conn)
1035 return conn->remote_address;
1039 process some input to a dcerpc endpoint server.
1041 NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
1042 struct ncacn_packet *pkt,
1043 DATA_BLOB blob)
1045 NTSTATUS status;
1046 struct dcesrv_call_state *call;
1048 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1049 if (!call) {
1050 data_blob_free(&blob);
1051 talloc_free(pkt);
1052 return NT_STATUS_NO_MEMORY;
1054 call->conn = dce_conn;
1055 call->event_ctx = dce_conn->event_ctx;
1056 call->msg_ctx = dce_conn->msg_ctx;
1057 call->state_flags = call->conn->state_flags;
1058 call->time = timeval_current();
1059 call->list = DCESRV_LIST_NONE;
1061 talloc_steal(call, pkt);
1062 talloc_steal(call, blob.data);
1063 call->pkt = *pkt;
1065 talloc_set_destructor(call, dcesrv_call_dequeue);
1067 /* we have to check the signing here, before combining the
1068 pdus */
1069 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1070 !dcesrv_auth_request(call, &blob)) {
1071 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1074 /* see if this is a continued packet */
1075 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1076 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1077 struct dcesrv_call_state *call2 = call;
1078 uint32_t alloc_size;
1080 /* we only allow fragmented requests, no other packet types */
1081 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1082 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1085 /* this is a continuation of an existing call - find the call
1086 then tack it on the end */
1087 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1088 if (!call) {
1089 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1092 if (call->pkt.ptype != call2->pkt.ptype) {
1093 /* trying to play silly buggers are we? */
1094 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1097 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1098 call2->pkt.u.request.stub_and_verifier.length;
1099 if (call->pkt.u.request.alloc_hint > alloc_size) {
1100 alloc_size = call->pkt.u.request.alloc_hint;
1103 call->pkt.u.request.stub_and_verifier.data =
1104 talloc_realloc(call,
1105 call->pkt.u.request.stub_and_verifier.data,
1106 uint8_t, alloc_size);
1107 if (!call->pkt.u.request.stub_and_verifier.data) {
1108 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1110 memcpy(call->pkt.u.request.stub_and_verifier.data +
1111 call->pkt.u.request.stub_and_verifier.length,
1112 call2->pkt.u.request.stub_and_verifier.data,
1113 call2->pkt.u.request.stub_and_verifier.length);
1114 call->pkt.u.request.stub_and_verifier.length +=
1115 call2->pkt.u.request.stub_and_verifier.length;
1117 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1119 talloc_free(call2);
1122 /* this may not be the last pdu in the chain - if its isn't then
1123 just put it on the incoming_fragmented_call_list and wait for the rest */
1124 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1125 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1126 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1127 return NT_STATUS_OK;
1130 /* This removes any fragments we may have had stashed away */
1131 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1133 switch (call->pkt.ptype) {
1134 case DCERPC_PKT_BIND:
1135 status = dcesrv_bind(call);
1136 break;
1137 case DCERPC_PKT_AUTH3:
1138 status = dcesrv_auth3(call);
1139 break;
1140 case DCERPC_PKT_ALTER:
1141 status = dcesrv_alter(call);
1142 break;
1143 case DCERPC_PKT_REQUEST:
1144 status = dcesrv_request(call);
1145 break;
1146 default:
1147 status = NT_STATUS_INVALID_PARAMETER;
1148 break;
1151 /* if we are going to be sending a reply then add
1152 it to the list of pending calls. We add it to the end to keep the call
1153 list in the order we will answer */
1154 if (!NT_STATUS_IS_OK(status)) {
1155 talloc_free(call);
1158 return status;
1161 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1162 struct loadparm_context *lp_ctx,
1163 const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1165 NTSTATUS status;
1166 struct dcesrv_context *dce_ctx;
1167 int i;
1169 if (!endpoint_servers) {
1170 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1171 return NT_STATUS_INTERNAL_ERROR;
1174 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1175 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1176 dce_ctx->endpoint_list = NULL;
1177 dce_ctx->lp_ctx = lp_ctx;
1178 dce_ctx->assoc_groups_idr = idr_init(dce_ctx);
1179 NT_STATUS_HAVE_NO_MEMORY(dce_ctx->assoc_groups_idr);
1180 dce_ctx->broken_connections = NULL;
1182 for (i=0;endpoint_servers[i];i++) {
1183 const struct dcesrv_endpoint_server *ep_server;
1185 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1186 if (!ep_server) {
1187 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1188 return NT_STATUS_INTERNAL_ERROR;
1191 status = ep_server->init_server(dce_ctx, ep_server);
1192 if (!NT_STATUS_IS_OK(status)) {
1193 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1194 nt_errstr(status)));
1195 return status;
1199 *_dce_ctx = dce_ctx;
1200 return NT_STATUS_OK;
1203 /* the list of currently registered DCERPC endpoint servers.
1205 static struct ep_server {
1206 struct dcesrv_endpoint_server *ep_server;
1207 } *ep_servers = NULL;
1208 static int num_ep_servers;
1211 register a DCERPC endpoint server.
1213 The 'name' can be later used by other backends to find the operations
1214 structure for this backend.
1216 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1218 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1220 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1222 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1223 /* its already registered! */
1224 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1225 ep_server->name));
1226 return NT_STATUS_OBJECT_NAME_COLLISION;
1229 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1230 if (!ep_servers) {
1231 smb_panic("out of memory in dcerpc_register");
1234 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1235 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1237 num_ep_servers++;
1239 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1240 ep_server->name));
1242 return NT_STATUS_OK;
1246 return the operations structure for a named backend of the specified type
1248 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1250 int i;
1252 for (i=0;i<num_ep_servers;i++) {
1253 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1254 return ep_servers[i].ep_server;
1258 return NULL;
1261 void dcerpc_server_init(struct loadparm_context *lp_ctx)
1263 static bool initialized;
1264 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
1265 STATIC_dcerpc_server_MODULES_PROTO;
1266 init_module_fn static_init[] = { STATIC_dcerpc_server_MODULES };
1267 init_module_fn *shared_init;
1269 if (initialized) {
1270 return;
1272 initialized = true;
1274 shared_init = load_samba_modules(NULL, "dcerpc_server");
1276 run_init_functions(static_init);
1277 run_init_functions(shared_init);
1279 talloc_free(shared_init);
1283 return the DCERPC module version, and the size of some critical types
1284 This can be used by endpoint server modules to either detect compilation errors, or provide
1285 multiple implementations for different smbd compilation options in one module
1287 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1289 static const struct dcesrv_critical_sizes critical_sizes = {
1290 DCERPC_MODULE_VERSION,
1291 sizeof(struct dcesrv_context),
1292 sizeof(struct dcesrv_endpoint),
1293 sizeof(struct dcesrv_endpoint_server),
1294 sizeof(struct dcesrv_interface),
1295 sizeof(struct dcesrv_if_list),
1296 sizeof(struct dcesrv_connection),
1297 sizeof(struct dcesrv_call_state),
1298 sizeof(struct dcesrv_auth),
1299 sizeof(struct dcesrv_handle)
1302 return &critical_sizes;
1305 static void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, const char *reason)
1307 struct dcesrv_context *dce_ctx = dce_conn->dce_ctx;
1308 struct stream_connection *srv_conn;
1309 srv_conn = talloc_get_type(dce_conn->transport.private_data,
1310 struct stream_connection);
1312 if (dce_conn->pending_call_list == NULL) {
1313 char *full_reason = talloc_asprintf(dce_conn, "dcesrv: %s", reason);
1315 DLIST_REMOVE(dce_ctx->broken_connections, dce_conn);
1316 stream_terminate_connection(srv_conn, full_reason ? full_reason : reason);
1317 return;
1320 if (dce_conn->terminate != NULL) {
1321 return;
1324 DEBUG(3,("dcesrv: terminating connection due to '%s' defered due to pending calls\n",
1325 reason));
1326 dce_conn->terminate = talloc_strdup(dce_conn, reason);
1327 if (dce_conn->terminate == NULL) {
1328 dce_conn->terminate = "dcesrv: defered terminating connection - no memory";
1330 DLIST_ADD_END(dce_ctx->broken_connections, dce_conn, NULL);
1333 static void dcesrv_cleanup_broken_connections(struct dcesrv_context *dce_ctx)
1335 struct dcesrv_connection *cur, *next;
1337 next = dce_ctx->broken_connections;
1338 while (next != NULL) {
1339 cur = next;
1340 next = cur->next;
1342 if (cur->state_flags & DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL) {
1343 struct dcesrv_connection_context *context_cur, *context_next;
1345 context_next = cur->contexts;
1346 while (context_next != NULL) {
1347 context_cur = context_next;
1348 context_next = context_cur->next;
1350 dcesrv_connection_context_destructor(context_cur);
1354 dcesrv_terminate_connection(cur, cur->terminate);
1358 /* We need this include to be able to compile on some plateforms
1359 * (ie. freebsd 7.2) as it seems that <sys/uio.h> is not included
1360 * correctly.
1361 * It has to be that deep because otherwise we have a conflict on
1362 * const struct dcesrv_interface declaration.
1363 * This is mostly due to socket_wrapper defining #define bind swrap_bind
1364 * which conflict with the bind used before.
1366 #include "system/network.h"
1368 struct dcesrv_sock_reply_state {
1369 struct dcesrv_connection *dce_conn;
1370 struct dcesrv_call_state *call;
1371 struct iovec iov;
1374 static void dcesrv_sock_reply_done(struct tevent_req *subreq);
1376 static void dcesrv_sock_report_output_data(struct dcesrv_connection *dce_conn)
1378 struct dcesrv_call_state *call;
1380 call = dce_conn->call_list;
1381 if (!call || !call->replies) {
1382 return;
1385 while (call->replies) {
1386 struct data_blob_list_item *rep = call->replies;
1387 struct dcesrv_sock_reply_state *substate;
1388 struct tevent_req *subreq;
1390 substate = talloc(call, struct dcesrv_sock_reply_state);
1391 if (!substate) {
1392 dcesrv_terminate_connection(dce_conn, "no memory");
1393 return;
1396 substate->dce_conn = dce_conn;
1397 substate->call = NULL;
1399 DLIST_REMOVE(call->replies, rep);
1401 if (call->replies == NULL) {
1402 substate->call = call;
1405 substate->iov.iov_base = (void *) rep->blob.data;
1406 substate->iov.iov_len = rep->blob.length;
1408 subreq = tstream_writev_queue_send(substate,
1409 dce_conn->event_ctx,
1410 dce_conn->stream,
1411 dce_conn->send_queue,
1412 &substate->iov, 1);
1413 if (!subreq) {
1414 dcesrv_terminate_connection(dce_conn, "no memory");
1415 return;
1417 tevent_req_set_callback(subreq, dcesrv_sock_reply_done,
1418 substate);
1421 DLIST_REMOVE(call->conn->call_list, call);
1422 call->list = DCESRV_LIST_NONE;
1425 static void dcesrv_sock_reply_done(struct tevent_req *subreq)
1427 struct dcesrv_sock_reply_state *substate = tevent_req_callback_data(subreq,
1428 struct dcesrv_sock_reply_state);
1429 int ret;
1430 int sys_errno;
1431 NTSTATUS status;
1432 struct dcesrv_call_state *call = substate->call;
1434 ret = tstream_writev_queue_recv(subreq, &sys_errno);
1435 TALLOC_FREE(subreq);
1436 if (ret == -1) {
1437 status = map_nt_error_from_unix_common(sys_errno);
1438 dcesrv_terminate_connection(substate->dce_conn, nt_errstr(status));
1439 return;
1442 talloc_free(substate);
1443 if (call) {
1444 talloc_free(call);
1451 struct dcesrv_socket_context {
1452 const struct dcesrv_endpoint *endpoint;
1453 struct dcesrv_context *dcesrv_ctx;
1457 static void dcesrv_read_fragment_done(struct tevent_req *subreq);
1459 static void dcesrv_sock_accept(struct stream_connection *srv_conn)
1461 NTSTATUS status;
1462 struct dcesrv_socket_context *dcesrv_sock =
1463 talloc_get_type(srv_conn->private_data, struct dcesrv_socket_context);
1464 struct dcesrv_connection *dcesrv_conn = NULL;
1465 int ret;
1466 struct tevent_req *subreq;
1467 struct loadparm_context *lp_ctx = dcesrv_sock->dcesrv_ctx->lp_ctx;
1469 dcesrv_cleanup_broken_connections(dcesrv_sock->dcesrv_ctx);
1471 if (!srv_conn->session_info) {
1472 status = auth_anonymous_session_info(srv_conn,
1473 lp_ctx,
1474 &srv_conn->session_info);
1475 if (!NT_STATUS_IS_OK(status)) {
1476 DEBUG(0,("dcesrv_sock_accept: auth_anonymous_session_info failed: %s\n",
1477 nt_errstr(status)));
1478 stream_terminate_connection(srv_conn, nt_errstr(status));
1479 return;
1483 status = dcesrv_endpoint_connect(dcesrv_sock->dcesrv_ctx,
1484 srv_conn,
1485 dcesrv_sock->endpoint,
1486 srv_conn->session_info,
1487 srv_conn->event.ctx,
1488 srv_conn->msg_ctx,
1489 srv_conn->server_id,
1490 DCESRV_CALL_STATE_FLAG_MAY_ASYNC,
1491 &dcesrv_conn);
1492 if (!NT_STATUS_IS_OK(status)) {
1493 DEBUG(0,("dcesrv_sock_accept: dcesrv_endpoint_connect failed: %s\n",
1494 nt_errstr(status)));
1495 stream_terminate_connection(srv_conn, nt_errstr(status));
1496 return;
1499 dcesrv_conn->transport.private_data = srv_conn;
1500 dcesrv_conn->transport.report_output_data = dcesrv_sock_report_output_data;
1502 TALLOC_FREE(srv_conn->event.fde);
1504 dcesrv_conn->send_queue = tevent_queue_create(dcesrv_conn, "dcesrv send queue");
1505 if (!dcesrv_conn->send_queue) {
1506 status = NT_STATUS_NO_MEMORY;
1507 DEBUG(0,("dcesrv_sock_accept: tevent_queue_create(%s)\n",
1508 nt_errstr(status)));
1509 stream_terminate_connection(srv_conn, nt_errstr(status));
1510 return;
1513 if (dcesrv_sock->endpoint->ep_description->transport == NCACN_NP) {
1514 dcesrv_conn->auth_state.session_key = dcesrv_inherited_session_key;
1515 dcesrv_conn->stream = talloc_move(dcesrv_conn,
1516 &srv_conn->tstream);
1517 } else {
1518 ret = tstream_bsd_existing_socket(dcesrv_conn,
1519 socket_get_fd(srv_conn->socket),
1520 &dcesrv_conn->stream);
1521 if (ret == -1) {
1522 status = map_nt_error_from_unix_common(errno);
1523 DEBUG(0, ("dcesrv_sock_accept: "
1524 "failed to setup tstream: %s\n",
1525 nt_errstr(status)));
1526 stream_terminate_connection(srv_conn, nt_errstr(status));
1527 return;
1529 socket_set_flags(srv_conn->socket, SOCKET_FLAG_NOCLOSE);
1532 dcesrv_conn->local_address = srv_conn->local_address;
1533 dcesrv_conn->remote_address = srv_conn->remote_address;
1535 srv_conn->private_data = dcesrv_conn;
1537 irpc_add_name(srv_conn->msg_ctx, "rpc_server");
1539 subreq = dcerpc_read_ncacn_packet_send(dcesrv_conn,
1540 dcesrv_conn->event_ctx,
1541 dcesrv_conn->stream);
1542 if (!subreq) {
1543 status = NT_STATUS_NO_MEMORY;
1544 DEBUG(0,("dcesrv_sock_accept: dcerpc_read_fragment_buffer_send(%s)\n",
1545 nt_errstr(status)));
1546 stream_terminate_connection(srv_conn, nt_errstr(status));
1547 return;
1549 tevent_req_set_callback(subreq, dcesrv_read_fragment_done, dcesrv_conn);
1551 return;
1554 static void dcesrv_read_fragment_done(struct tevent_req *subreq)
1556 struct dcesrv_connection *dce_conn = tevent_req_callback_data(subreq,
1557 struct dcesrv_connection);
1558 struct dcesrv_context *dce_ctx = dce_conn->dce_ctx;
1559 struct ncacn_packet *pkt;
1560 DATA_BLOB buffer;
1561 NTSTATUS status;
1563 if (dce_conn->terminate) {
1565 * if the current connection is broken
1566 * we need to clean it up before any other connection
1568 dcesrv_terminate_connection(dce_conn, dce_conn->terminate);
1569 dcesrv_cleanup_broken_connections(dce_ctx);
1570 return;
1573 dcesrv_cleanup_broken_connections(dce_ctx);
1575 status = dcerpc_read_ncacn_packet_recv(subreq, dce_conn,
1576 &pkt, &buffer);
1577 TALLOC_FREE(subreq);
1578 if (!NT_STATUS_IS_OK(status)) {
1579 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1580 return;
1583 status = dcesrv_process_ncacn_packet(dce_conn, pkt, buffer);
1584 if (!NT_STATUS_IS_OK(status)) {
1585 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1586 return;
1589 subreq = dcerpc_read_ncacn_packet_send(dce_conn,
1590 dce_conn->event_ctx,
1591 dce_conn->stream);
1592 if (!subreq) {
1593 status = NT_STATUS_NO_MEMORY;
1594 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1595 return;
1597 tevent_req_set_callback(subreq, dcesrv_read_fragment_done, dce_conn);
1600 static void dcesrv_sock_recv(struct stream_connection *conn, uint16_t flags)
1602 struct dcesrv_connection *dce_conn = talloc_get_type(conn->private_data,
1603 struct dcesrv_connection);
1604 dcesrv_terminate_connection(dce_conn, "dcesrv_sock_recv triggered");
1607 static void dcesrv_sock_send(struct stream_connection *conn, uint16_t flags)
1609 struct dcesrv_connection *dce_conn = talloc_get_type(conn->private_data,
1610 struct dcesrv_connection);
1611 dcesrv_terminate_connection(dce_conn, "dcesrv_sock_send triggered");
1615 static const struct stream_server_ops dcesrv_stream_ops = {
1616 .name = "rpc",
1617 .accept_connection = dcesrv_sock_accept,
1618 .recv_handler = dcesrv_sock_recv,
1619 .send_handler = dcesrv_sock_send,
1622 static NTSTATUS dcesrv_add_ep_unix(struct dcesrv_context *dce_ctx,
1623 struct loadparm_context *lp_ctx,
1624 struct dcesrv_endpoint *e,
1625 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1627 struct dcesrv_socket_context *dcesrv_sock;
1628 uint16_t port = 1;
1629 NTSTATUS status;
1631 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1632 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1634 /* remember the endpoint of this socket */
1635 dcesrv_sock->endpoint = e;
1636 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1638 status = stream_setup_socket(dcesrv_sock, event_ctx, lp_ctx,
1639 model_ops, &dcesrv_stream_ops,
1640 "unix", e->ep_description->endpoint, &port,
1641 lpcfg_socket_options(lp_ctx),
1642 dcesrv_sock);
1643 if (!NT_STATUS_IS_OK(status)) {
1644 DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n",
1645 e->ep_description->endpoint, nt_errstr(status)));
1648 return status;
1651 static NTSTATUS dcesrv_add_ep_ncalrpc(struct dcesrv_context *dce_ctx,
1652 struct loadparm_context *lp_ctx,
1653 struct dcesrv_endpoint *e,
1654 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1656 struct dcesrv_socket_context *dcesrv_sock;
1657 uint16_t port = 1;
1658 char *full_path;
1659 NTSTATUS status;
1661 if (!e->ep_description->endpoint) {
1662 /* No identifier specified: use DEFAULT.
1663 * DO NOT hardcode this value anywhere else. Rather, specify
1664 * no endpoint and let the epmapper worry about it. */
1665 e->ep_description->endpoint = talloc_strdup(dce_ctx, "DEFAULT");
1668 full_path = talloc_asprintf(dce_ctx, "%s/%s", lpcfg_ncalrpc_dir(lp_ctx),
1669 e->ep_description->endpoint);
1671 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1672 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1674 /* remember the endpoint of this socket */
1675 dcesrv_sock->endpoint = e;
1676 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1678 status = stream_setup_socket(dcesrv_sock, event_ctx, lp_ctx,
1679 model_ops, &dcesrv_stream_ops,
1680 "unix", full_path, &port,
1681 lpcfg_socket_options(lp_ctx),
1682 dcesrv_sock);
1683 if (!NT_STATUS_IS_OK(status)) {
1684 DEBUG(0,("service_setup_stream_socket(identifier=%s,path=%s) failed - %s\n",
1685 e->ep_description->endpoint, full_path, nt_errstr(status)));
1687 return status;
1690 static NTSTATUS dcesrv_add_ep_np(struct dcesrv_context *dce_ctx,
1691 struct loadparm_context *lp_ctx,
1692 struct dcesrv_endpoint *e,
1693 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1695 struct dcesrv_socket_context *dcesrv_sock;
1696 NTSTATUS status;
1698 if (e->ep_description->endpoint == NULL) {
1699 DEBUG(0, ("Endpoint mandatory for named pipes\n"));
1700 return NT_STATUS_INVALID_PARAMETER;
1703 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1704 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1706 /* remember the endpoint of this socket */
1707 dcesrv_sock->endpoint = e;
1708 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1710 status = tstream_setup_named_pipe(dce_ctx, event_ctx, lp_ctx,
1711 model_ops, &dcesrv_stream_ops,
1712 e->ep_description->endpoint,
1713 dcesrv_sock);
1714 if (!NT_STATUS_IS_OK(status)) {
1715 DEBUG(0,("stream_setup_named_pipe(pipe=%s) failed - %s\n",
1716 e->ep_description->endpoint, nt_errstr(status)));
1717 return status;
1720 return NT_STATUS_OK;
1724 add a socket address to the list of events, one event per dcerpc endpoint
1726 static NTSTATUS add_socket_rpc_tcp_iface(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e,
1727 struct tevent_context *event_ctx, const struct model_ops *model_ops,
1728 const char *address)
1730 struct dcesrv_socket_context *dcesrv_sock;
1731 uint16_t port = 0;
1732 NTSTATUS status;
1734 if (e->ep_description->endpoint) {
1735 port = atoi(e->ep_description->endpoint);
1738 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1739 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1741 /* remember the endpoint of this socket */
1742 dcesrv_sock->endpoint = e;
1743 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1745 status = stream_setup_socket(dcesrv_sock, event_ctx, dce_ctx->lp_ctx,
1746 model_ops, &dcesrv_stream_ops,
1747 "ip", address, &port,
1748 lpcfg_socket_options(dce_ctx->lp_ctx),
1749 dcesrv_sock);
1750 if (!NT_STATUS_IS_OK(status)) {
1751 DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) failed - %s\n",
1752 address, port, nt_errstr(status)));
1755 if (e->ep_description->endpoint == NULL) {
1756 e->ep_description->endpoint = talloc_asprintf(dce_ctx, "%d", port);
1759 return status;
1762 #include "lib/socket/netif.h" /* Included here to work around the fact that socket_wrapper redefines bind() */
1764 static NTSTATUS dcesrv_add_ep_tcp(struct dcesrv_context *dce_ctx,
1765 struct loadparm_context *lp_ctx,
1766 struct dcesrv_endpoint *e,
1767 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1769 NTSTATUS status;
1771 /* Add TCP/IP sockets */
1772 if (lpcfg_interfaces(lp_ctx) && lpcfg_bind_interfaces_only(lp_ctx)) {
1773 int num_interfaces;
1774 int i;
1775 struct interface *ifaces;
1777 load_interface_list(dce_ctx, lp_ctx, &ifaces);
1779 num_interfaces = iface_list_count(ifaces);
1780 for(i = 0; i < num_interfaces; i++) {
1781 const char *address = iface_list_n_ip(ifaces, i);
1782 status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, address);
1783 NT_STATUS_NOT_OK_RETURN(status);
1785 } else {
1786 char **wcard;
1787 int i;
1788 int num_binds = 0;
1789 wcard = iface_list_wildcard(dce_ctx);
1790 NT_STATUS_HAVE_NO_MEMORY(wcard);
1791 for (i=0; wcard[i]; i++) {
1792 status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, wcard[i]);
1793 if (NT_STATUS_IS_OK(status)) {
1794 num_binds++;
1797 talloc_free(wcard);
1798 if (num_binds == 0) {
1799 return NT_STATUS_INVALID_PARAMETER_MIX;
1803 return NT_STATUS_OK;
1806 NTSTATUS dcesrv_add_ep(struct dcesrv_context *dce_ctx,
1807 struct loadparm_context *lp_ctx,
1808 struct dcesrv_endpoint *e,
1809 struct tevent_context *event_ctx,
1810 const struct model_ops *model_ops)
1812 switch (e->ep_description->transport) {
1813 case NCACN_UNIX_STREAM:
1814 return dcesrv_add_ep_unix(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1816 case NCALRPC:
1817 return dcesrv_add_ep_ncalrpc(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1819 case NCACN_IP_TCP:
1820 return dcesrv_add_ep_tcp(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1822 case NCACN_NP:
1823 return dcesrv_add_ep_np(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1825 default:
1826 return NT_STATUS_NOT_SUPPORTED;
1832 * retrieve credentials from a dce_call
1834 _PUBLIC_ struct cli_credentials *dcesrv_call_credentials(struct dcesrv_call_state *dce_call)
1836 return dce_call->conn->auth_state.session_info->credentials;
1840 * returns true if this is an authenticated call
1842 _PUBLIC_ bool dcesrv_call_authenticated(struct dcesrv_call_state *dce_call)
1844 enum security_user_level level;
1845 level = security_session_user_level(dce_call->conn->auth_state.session_info, NULL);
1846 return level >= SECURITY_USER;
1850 * retrieve account_name for a dce_call
1852 _PUBLIC_ const char *dcesrv_call_account_name(struct dcesrv_call_state *dce_call)
1854 return dce_call->context->conn->auth_state.session_info->info->account_name;