Add DCERPC flag to call unbind hooks without destroying the connection itself upon...
[Samba.git] / source4 / rpc_server / dcerpc_server.c
blob8c0a1015fa228cccb6ce160601afd0ba32dbbbd6
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;
800 handle a alter context request
802 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
804 struct ncacn_packet pkt;
805 struct data_blob_list_item *rep;
806 NTSTATUS status;
807 uint32_t result=0, reason=0;
808 uint32_t context_id;
809 uint32_t extra_flags = 0;
811 /* handle any authentication that is being requested */
812 if (!dcesrv_auth_alter(call)) {
813 /* TODO: work out the right reject code */
814 result = DCERPC_BIND_PROVIDER_REJECT;
815 reason = DCERPC_BIND_REASON_ASYNTAX;
818 context_id = call->pkt.u.alter.ctx_list[0].context_id;
820 /* see if they are asking for a new interface */
821 if (result == 0) {
822 call->context = dcesrv_find_context(call->conn, context_id);
823 if (!call->context) {
824 status = dcesrv_alter_new_context(call, context_id);
825 if (!NT_STATUS_IS_OK(status)) {
826 result = DCERPC_BIND_PROVIDER_REJECT;
827 reason = DCERPC_BIND_REASON_ASYNTAX;
832 if (result == 0 &&
833 call->pkt.u.alter.assoc_group_id != 0 &&
834 lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
835 call->pkt.u.alter.assoc_group_id != call->context->assoc_group->id) {
836 DEBUG(0,(__location__ ": Failed attempt to use new assoc_group in alter context (0x%08x 0x%08x)\n",
837 call->context->assoc_group->id, call->pkt.u.alter.assoc_group_id));
838 /* TODO: can they ask for a new association group? */
839 result = DCERPC_BIND_PROVIDER_REJECT;
840 reason = DCERPC_BIND_REASON_ASYNTAX;
843 if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
844 if (call->context->conn->state_flags & DCESRV_CALL_STATE_FLAG_MULTIPLEXED) {
845 extra_flags |= DCERPC_PFC_FLAG_CONC_MPX;
849 if (call->state_flags & DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL) {
850 call->context->conn->state_flags |= DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL;
853 /* setup a alter_resp */
854 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
855 pkt.auth_length = 0;
856 pkt.call_id = call->pkt.call_id;
857 pkt.ptype = DCERPC_PKT_ALTER_RESP;
858 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
859 pkt.u.alter_resp.max_xmit_frag = 0x2000;
860 pkt.u.alter_resp.max_recv_frag = 0x2000;
861 if (result == 0) {
862 pkt.u.alter_resp.assoc_group_id = call->context->assoc_group->id;
863 } else {
864 pkt.u.alter_resp.assoc_group_id = 0;
866 pkt.u.alter_resp.num_results = 1;
867 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
868 if (!pkt.u.alter_resp.ctx_list) {
869 return NT_STATUS_NO_MEMORY;
871 pkt.u.alter_resp.ctx_list[0].result = result;
872 pkt.u.alter_resp.ctx_list[0].reason = reason;
873 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax_ndr;
874 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
875 pkt.u.alter_resp.secondary_address = "";
877 status = dcesrv_auth_alter_ack(call, &pkt);
878 if (!NT_STATUS_IS_OK(status)) {
879 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
880 || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
881 || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
882 || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
883 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
885 return dcesrv_fault(call, 0);
888 rep = talloc(call, struct data_blob_list_item);
889 if (!rep) {
890 return NT_STATUS_NO_MEMORY;
893 status = ncacn_push_auth(&rep->blob, call, &pkt, call->conn->auth_state.auth_info);
894 if (!NT_STATUS_IS_OK(status)) {
895 return status;
898 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
900 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
901 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
903 if (call->conn->call_list && call->conn->call_list->replies) {
904 if (call->conn->transport.report_output_data) {
905 call->conn->transport.report_output_data(call->conn);
909 return NT_STATUS_OK;
913 possibly save the call for inspection with ndrdump
915 static void dcesrv_save_call(struct dcesrv_call_state *call, const char *why)
917 #ifdef DEVELOPER
918 char *fname;
919 const char *dump_dir;
920 dump_dir = lpcfg_parm_string(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv", "stubs directory");
921 if (!dump_dir) {
922 return;
924 fname = talloc_asprintf(call, "%s/RPC-%s-%u-%s.dat",
925 dump_dir,
926 call->context->iface->name,
927 call->pkt.u.request.opnum,
928 why);
929 if (file_save(fname, call->pkt.u.request.stub_and_verifier.data, call->pkt.u.request.stub_and_verifier.length)) {
930 DEBUG(0,("RPC SAVED %s\n", fname));
932 talloc_free(fname);
933 #endif
937 handle a dcerpc request packet
939 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
941 struct ndr_pull *pull;
942 NTSTATUS status;
943 struct dcesrv_connection_context *context;
945 /* if authenticated, and the mech we use can't do async replies, don't use them... */
946 if (call->conn->auth_state.gensec_security &&
947 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
948 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
951 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
952 if (context == NULL) {
953 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
956 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
957 NT_STATUS_HAVE_NO_MEMORY(pull);
959 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
961 call->context = context;
962 call->ndr_pull = pull;
964 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
965 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
968 /* unravel the NDR for the packet */
969 status = context->iface->ndr_pull(call, call, pull, &call->r);
970 if (!NT_STATUS_IS_OK(status)) {
971 if (call->fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
972 /* we got an unknown call */
973 DEBUG(3,(__location__ ": Unknown RPC call %u on %s\n",
974 call->pkt.u.request.opnum, context->iface->name));
975 dcesrv_save_call(call, "unknown");
976 } else {
977 dcesrv_save_call(call, "pullfail");
979 return dcesrv_fault(call, call->fault_code);
982 if (pull->offset != pull->data_size) {
983 dcesrv_save_call(call, "extrabytes");
984 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
985 pull->data_size - pull->offset));
988 /* call the dispatch function */
989 status = context->iface->dispatch(call, call, call->r);
990 if (!NT_STATUS_IS_OK(status)) {
991 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
992 context->iface->name,
993 call->pkt.u.request.opnum,
994 dcerpc_errstr(pull, call->fault_code)));
995 return dcesrv_fault(call, call->fault_code);
998 /* add the call to the pending list */
999 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
1001 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
1002 return NT_STATUS_OK;
1005 return dcesrv_reply(call);
1010 remove the call from the right list when freed
1012 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1014 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1015 return 0;
1018 _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_local_address(struct dcesrv_connection *conn)
1020 return conn->local_address;
1023 _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_remote_address(struct dcesrv_connection *conn)
1025 return conn->remote_address;
1029 process some input to a dcerpc endpoint server.
1031 NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
1032 struct ncacn_packet *pkt,
1033 DATA_BLOB blob)
1035 NTSTATUS status;
1036 struct dcesrv_call_state *call;
1038 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1039 if (!call) {
1040 data_blob_free(&blob);
1041 talloc_free(pkt);
1042 return NT_STATUS_NO_MEMORY;
1044 call->conn = dce_conn;
1045 call->event_ctx = dce_conn->event_ctx;
1046 call->msg_ctx = dce_conn->msg_ctx;
1047 call->state_flags = call->conn->state_flags;
1048 call->time = timeval_current();
1049 call->list = DCESRV_LIST_NONE;
1051 talloc_steal(call, pkt);
1052 talloc_steal(call, blob.data);
1053 call->pkt = *pkt;
1055 talloc_set_destructor(call, dcesrv_call_dequeue);
1057 /* we have to check the signing here, before combining the
1058 pdus */
1059 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1060 !dcesrv_auth_request(call, &blob)) {
1061 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1064 /* see if this is a continued packet */
1065 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1066 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1067 struct dcesrv_call_state *call2 = call;
1068 uint32_t alloc_size;
1070 /* we only allow fragmented requests, no other packet types */
1071 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1072 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1075 /* this is a continuation of an existing call - find the call
1076 then tack it on the end */
1077 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1078 if (!call) {
1079 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1082 if (call->pkt.ptype != call2->pkt.ptype) {
1083 /* trying to play silly buggers are we? */
1084 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1087 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1088 call2->pkt.u.request.stub_and_verifier.length;
1089 if (call->pkt.u.request.alloc_hint > alloc_size) {
1090 alloc_size = call->pkt.u.request.alloc_hint;
1093 call->pkt.u.request.stub_and_verifier.data =
1094 talloc_realloc(call,
1095 call->pkt.u.request.stub_and_verifier.data,
1096 uint8_t, alloc_size);
1097 if (!call->pkt.u.request.stub_and_verifier.data) {
1098 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1100 memcpy(call->pkt.u.request.stub_and_verifier.data +
1101 call->pkt.u.request.stub_and_verifier.length,
1102 call2->pkt.u.request.stub_and_verifier.data,
1103 call2->pkt.u.request.stub_and_verifier.length);
1104 call->pkt.u.request.stub_and_verifier.length +=
1105 call2->pkt.u.request.stub_and_verifier.length;
1107 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1109 talloc_free(call2);
1112 /* this may not be the last pdu in the chain - if its isn't then
1113 just put it on the incoming_fragmented_call_list and wait for the rest */
1114 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1115 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1116 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1117 return NT_STATUS_OK;
1120 /* This removes any fragments we may have had stashed away */
1121 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1123 switch (call->pkt.ptype) {
1124 case DCERPC_PKT_BIND:
1125 status = dcesrv_bind(call);
1126 break;
1127 case DCERPC_PKT_AUTH3:
1128 status = dcesrv_auth3(call);
1129 break;
1130 case DCERPC_PKT_ALTER:
1131 status = dcesrv_alter(call);
1132 break;
1133 case DCERPC_PKT_REQUEST:
1134 status = dcesrv_request(call);
1135 break;
1136 default:
1137 status = NT_STATUS_INVALID_PARAMETER;
1138 break;
1141 /* if we are going to be sending a reply then add
1142 it to the list of pending calls. We add it to the end to keep the call
1143 list in the order we will answer */
1144 if (!NT_STATUS_IS_OK(status)) {
1145 talloc_free(call);
1148 return status;
1151 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1152 struct loadparm_context *lp_ctx,
1153 const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1155 NTSTATUS status;
1156 struct dcesrv_context *dce_ctx;
1157 int i;
1159 if (!endpoint_servers) {
1160 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1161 return NT_STATUS_INTERNAL_ERROR;
1164 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1165 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1166 dce_ctx->endpoint_list = NULL;
1167 dce_ctx->lp_ctx = lp_ctx;
1168 dce_ctx->assoc_groups_idr = idr_init(dce_ctx);
1169 NT_STATUS_HAVE_NO_MEMORY(dce_ctx->assoc_groups_idr);
1170 dce_ctx->broken_connections = NULL;
1172 for (i=0;endpoint_servers[i];i++) {
1173 const struct dcesrv_endpoint_server *ep_server;
1175 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1176 if (!ep_server) {
1177 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1178 return NT_STATUS_INTERNAL_ERROR;
1181 status = ep_server->init_server(dce_ctx, ep_server);
1182 if (!NT_STATUS_IS_OK(status)) {
1183 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1184 nt_errstr(status)));
1185 return status;
1189 *_dce_ctx = dce_ctx;
1190 return NT_STATUS_OK;
1193 /* the list of currently registered DCERPC endpoint servers.
1195 static struct ep_server {
1196 struct dcesrv_endpoint_server *ep_server;
1197 } *ep_servers = NULL;
1198 static int num_ep_servers;
1201 register a DCERPC endpoint server.
1203 The 'name' can be later used by other backends to find the operations
1204 structure for this backend.
1206 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1208 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1210 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1212 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1213 /* its already registered! */
1214 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1215 ep_server->name));
1216 return NT_STATUS_OBJECT_NAME_COLLISION;
1219 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1220 if (!ep_servers) {
1221 smb_panic("out of memory in dcerpc_register");
1224 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1225 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1227 num_ep_servers++;
1229 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1230 ep_server->name));
1232 return NT_STATUS_OK;
1236 return the operations structure for a named backend of the specified type
1238 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1240 int i;
1242 for (i=0;i<num_ep_servers;i++) {
1243 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1244 return ep_servers[i].ep_server;
1248 return NULL;
1251 void dcerpc_server_init(struct loadparm_context *lp_ctx)
1253 static bool initialized;
1254 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
1255 STATIC_dcerpc_server_MODULES_PROTO;
1256 init_module_fn static_init[] = { STATIC_dcerpc_server_MODULES };
1257 init_module_fn *shared_init;
1259 if (initialized) {
1260 return;
1262 initialized = true;
1264 shared_init = load_samba_modules(NULL, "dcerpc_server");
1266 run_init_functions(static_init);
1267 run_init_functions(shared_init);
1269 talloc_free(shared_init);
1273 return the DCERPC module version, and the size of some critical types
1274 This can be used by endpoint server modules to either detect compilation errors, or provide
1275 multiple implementations for different smbd compilation options in one module
1277 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1279 static const struct dcesrv_critical_sizes critical_sizes = {
1280 DCERPC_MODULE_VERSION,
1281 sizeof(struct dcesrv_context),
1282 sizeof(struct dcesrv_endpoint),
1283 sizeof(struct dcesrv_endpoint_server),
1284 sizeof(struct dcesrv_interface),
1285 sizeof(struct dcesrv_if_list),
1286 sizeof(struct dcesrv_connection),
1287 sizeof(struct dcesrv_call_state),
1288 sizeof(struct dcesrv_auth),
1289 sizeof(struct dcesrv_handle)
1292 return &critical_sizes;
1295 static void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, const char *reason)
1297 struct dcesrv_context *dce_ctx = dce_conn->dce_ctx;
1298 struct stream_connection *srv_conn;
1299 srv_conn = talloc_get_type(dce_conn->transport.private_data,
1300 struct stream_connection);
1302 if (dce_conn->pending_call_list == NULL) {
1303 char *full_reason = talloc_asprintf(dce_conn, "dcesrv: %s", reason);
1305 DLIST_REMOVE(dce_ctx->broken_connections, dce_conn);
1306 stream_terminate_connection(srv_conn, full_reason ? full_reason : reason);
1307 return;
1310 if (dce_conn->terminate != NULL) {
1311 return;
1314 DEBUG(3,("dcesrv: terminating connection due to '%s' defered due to pending calls\n",
1315 reason));
1316 dce_conn->terminate = talloc_strdup(dce_conn, reason);
1317 if (dce_conn->terminate == NULL) {
1318 dce_conn->terminate = "dcesrv: defered terminating connection - no memory";
1320 DLIST_ADD_END(dce_ctx->broken_connections, dce_conn, NULL);
1323 static void dcesrv_cleanup_broken_connections(struct dcesrv_context *dce_ctx)
1325 struct dcesrv_connection *cur, *next;
1327 next = dce_ctx->broken_connections;
1328 while (next != NULL) {
1329 cur = next;
1330 next = cur->next;
1332 if (cur->state_flags & DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL) {
1333 struct dcesrv_connection_context *context_cur, *context_next;
1335 context_next = cur->contexts;
1336 while (context_next != NULL) {
1337 context_cur = context_next;
1338 context_next = context_cur->next;
1340 dcesrv_connection_context_destructor(context_cur);
1344 dcesrv_terminate_connection(cur, cur->terminate);
1348 /* We need this include to be able to compile on some plateforms
1349 * (ie. freebsd 7.2) as it seems that <sys/uio.h> is not included
1350 * correctly.
1351 * It has to be that deep because otherwise we have a conflict on
1352 * const struct dcesrv_interface declaration.
1353 * This is mostly due to socket_wrapper defining #define bind swrap_bind
1354 * which conflict with the bind used before.
1356 #include "system/network.h"
1358 struct dcesrv_sock_reply_state {
1359 struct dcesrv_connection *dce_conn;
1360 struct dcesrv_call_state *call;
1361 struct iovec iov;
1364 static void dcesrv_sock_reply_done(struct tevent_req *subreq);
1366 static void dcesrv_sock_report_output_data(struct dcesrv_connection *dce_conn)
1368 struct dcesrv_call_state *call;
1370 call = dce_conn->call_list;
1371 if (!call || !call->replies) {
1372 return;
1375 while (call->replies) {
1376 struct data_blob_list_item *rep = call->replies;
1377 struct dcesrv_sock_reply_state *substate;
1378 struct tevent_req *subreq;
1380 substate = talloc(call, struct dcesrv_sock_reply_state);
1381 if (!substate) {
1382 dcesrv_terminate_connection(dce_conn, "no memory");
1383 return;
1386 substate->dce_conn = dce_conn;
1387 substate->call = NULL;
1389 DLIST_REMOVE(call->replies, rep);
1391 if (call->replies == NULL) {
1392 substate->call = call;
1395 substate->iov.iov_base = (void *) rep->blob.data;
1396 substate->iov.iov_len = rep->blob.length;
1398 subreq = tstream_writev_queue_send(substate,
1399 dce_conn->event_ctx,
1400 dce_conn->stream,
1401 dce_conn->send_queue,
1402 &substate->iov, 1);
1403 if (!subreq) {
1404 dcesrv_terminate_connection(dce_conn, "no memory");
1405 return;
1407 tevent_req_set_callback(subreq, dcesrv_sock_reply_done,
1408 substate);
1411 DLIST_REMOVE(call->conn->call_list, call);
1412 call->list = DCESRV_LIST_NONE;
1415 static void dcesrv_sock_reply_done(struct tevent_req *subreq)
1417 struct dcesrv_sock_reply_state *substate = tevent_req_callback_data(subreq,
1418 struct dcesrv_sock_reply_state);
1419 int ret;
1420 int sys_errno;
1421 NTSTATUS status;
1422 struct dcesrv_call_state *call = substate->call;
1424 ret = tstream_writev_queue_recv(subreq, &sys_errno);
1425 TALLOC_FREE(subreq);
1426 if (ret == -1) {
1427 status = map_nt_error_from_unix_common(sys_errno);
1428 dcesrv_terminate_connection(substate->dce_conn, nt_errstr(status));
1429 return;
1432 talloc_free(substate);
1433 if (call) {
1434 talloc_free(call);
1441 struct dcesrv_socket_context {
1442 const struct dcesrv_endpoint *endpoint;
1443 struct dcesrv_context *dcesrv_ctx;
1447 static void dcesrv_read_fragment_done(struct tevent_req *subreq);
1449 static void dcesrv_sock_accept(struct stream_connection *srv_conn)
1451 NTSTATUS status;
1452 struct dcesrv_socket_context *dcesrv_sock =
1453 talloc_get_type(srv_conn->private_data, struct dcesrv_socket_context);
1454 struct dcesrv_connection *dcesrv_conn = NULL;
1455 int ret;
1456 struct tevent_req *subreq;
1457 struct loadparm_context *lp_ctx = dcesrv_sock->dcesrv_ctx->lp_ctx;
1459 dcesrv_cleanup_broken_connections(dcesrv_sock->dcesrv_ctx);
1461 if (!srv_conn->session_info) {
1462 status = auth_anonymous_session_info(srv_conn,
1463 lp_ctx,
1464 &srv_conn->session_info);
1465 if (!NT_STATUS_IS_OK(status)) {
1466 DEBUG(0,("dcesrv_sock_accept: auth_anonymous_session_info failed: %s\n",
1467 nt_errstr(status)));
1468 stream_terminate_connection(srv_conn, nt_errstr(status));
1469 return;
1473 status = dcesrv_endpoint_connect(dcesrv_sock->dcesrv_ctx,
1474 srv_conn,
1475 dcesrv_sock->endpoint,
1476 srv_conn->session_info,
1477 srv_conn->event.ctx,
1478 srv_conn->msg_ctx,
1479 srv_conn->server_id,
1480 DCESRV_CALL_STATE_FLAG_MAY_ASYNC,
1481 &dcesrv_conn);
1482 if (!NT_STATUS_IS_OK(status)) {
1483 DEBUG(0,("dcesrv_sock_accept: dcesrv_endpoint_connect failed: %s\n",
1484 nt_errstr(status)));
1485 stream_terminate_connection(srv_conn, nt_errstr(status));
1486 return;
1489 dcesrv_conn->transport.private_data = srv_conn;
1490 dcesrv_conn->transport.report_output_data = dcesrv_sock_report_output_data;
1492 TALLOC_FREE(srv_conn->event.fde);
1494 dcesrv_conn->send_queue = tevent_queue_create(dcesrv_conn, "dcesrv send queue");
1495 if (!dcesrv_conn->send_queue) {
1496 status = NT_STATUS_NO_MEMORY;
1497 DEBUG(0,("dcesrv_sock_accept: tevent_queue_create(%s)\n",
1498 nt_errstr(status)));
1499 stream_terminate_connection(srv_conn, nt_errstr(status));
1500 return;
1503 if (dcesrv_sock->endpoint->ep_description->transport == NCACN_NP) {
1504 dcesrv_conn->auth_state.session_key = dcesrv_inherited_session_key;
1505 dcesrv_conn->stream = talloc_move(dcesrv_conn,
1506 &srv_conn->tstream);
1507 } else {
1508 ret = tstream_bsd_existing_socket(dcesrv_conn,
1509 socket_get_fd(srv_conn->socket),
1510 &dcesrv_conn->stream);
1511 if (ret == -1) {
1512 status = map_nt_error_from_unix_common(errno);
1513 DEBUG(0, ("dcesrv_sock_accept: "
1514 "failed to setup tstream: %s\n",
1515 nt_errstr(status)));
1516 stream_terminate_connection(srv_conn, nt_errstr(status));
1517 return;
1519 socket_set_flags(srv_conn->socket, SOCKET_FLAG_NOCLOSE);
1522 dcesrv_conn->local_address = srv_conn->local_address;
1523 dcesrv_conn->remote_address = srv_conn->remote_address;
1525 srv_conn->private_data = dcesrv_conn;
1527 irpc_add_name(srv_conn->msg_ctx, "rpc_server");
1529 subreq = dcerpc_read_ncacn_packet_send(dcesrv_conn,
1530 dcesrv_conn->event_ctx,
1531 dcesrv_conn->stream);
1532 if (!subreq) {
1533 status = NT_STATUS_NO_MEMORY;
1534 DEBUG(0,("dcesrv_sock_accept: dcerpc_read_fragment_buffer_send(%s)\n",
1535 nt_errstr(status)));
1536 stream_terminate_connection(srv_conn, nt_errstr(status));
1537 return;
1539 tevent_req_set_callback(subreq, dcesrv_read_fragment_done, dcesrv_conn);
1541 return;
1544 static void dcesrv_read_fragment_done(struct tevent_req *subreq)
1546 struct dcesrv_connection *dce_conn = tevent_req_callback_data(subreq,
1547 struct dcesrv_connection);
1548 struct dcesrv_context *dce_ctx = dce_conn->dce_ctx;
1549 struct ncacn_packet *pkt;
1550 DATA_BLOB buffer;
1551 NTSTATUS status;
1553 if (dce_conn->terminate) {
1555 * if the current connection is broken
1556 * we need to clean it up before any other connection
1558 dcesrv_terminate_connection(dce_conn, dce_conn->terminate);
1559 dcesrv_cleanup_broken_connections(dce_ctx);
1560 return;
1563 dcesrv_cleanup_broken_connections(dce_ctx);
1565 status = dcerpc_read_ncacn_packet_recv(subreq, dce_conn,
1566 &pkt, &buffer);
1567 TALLOC_FREE(subreq);
1568 if (!NT_STATUS_IS_OK(status)) {
1569 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1570 return;
1573 status = dcesrv_process_ncacn_packet(dce_conn, pkt, buffer);
1574 if (!NT_STATUS_IS_OK(status)) {
1575 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1576 return;
1579 subreq = dcerpc_read_ncacn_packet_send(dce_conn,
1580 dce_conn->event_ctx,
1581 dce_conn->stream);
1582 if (!subreq) {
1583 status = NT_STATUS_NO_MEMORY;
1584 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1585 return;
1587 tevent_req_set_callback(subreq, dcesrv_read_fragment_done, dce_conn);
1590 static void dcesrv_sock_recv(struct stream_connection *conn, uint16_t flags)
1592 struct dcesrv_connection *dce_conn = talloc_get_type(conn->private_data,
1593 struct dcesrv_connection);
1594 dcesrv_terminate_connection(dce_conn, "dcesrv_sock_recv triggered");
1597 static void dcesrv_sock_send(struct stream_connection *conn, uint16_t flags)
1599 struct dcesrv_connection *dce_conn = talloc_get_type(conn->private_data,
1600 struct dcesrv_connection);
1601 dcesrv_terminate_connection(dce_conn, "dcesrv_sock_send triggered");
1605 static const struct stream_server_ops dcesrv_stream_ops = {
1606 .name = "rpc",
1607 .accept_connection = dcesrv_sock_accept,
1608 .recv_handler = dcesrv_sock_recv,
1609 .send_handler = dcesrv_sock_send,
1612 static NTSTATUS dcesrv_add_ep_unix(struct dcesrv_context *dce_ctx,
1613 struct loadparm_context *lp_ctx,
1614 struct dcesrv_endpoint *e,
1615 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1617 struct dcesrv_socket_context *dcesrv_sock;
1618 uint16_t port = 1;
1619 NTSTATUS status;
1621 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1622 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1624 /* remember the endpoint of this socket */
1625 dcesrv_sock->endpoint = e;
1626 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1628 status = stream_setup_socket(dcesrv_sock, event_ctx, lp_ctx,
1629 model_ops, &dcesrv_stream_ops,
1630 "unix", e->ep_description->endpoint, &port,
1631 lpcfg_socket_options(lp_ctx),
1632 dcesrv_sock);
1633 if (!NT_STATUS_IS_OK(status)) {
1634 DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n",
1635 e->ep_description->endpoint, nt_errstr(status)));
1638 return status;
1641 static NTSTATUS dcesrv_add_ep_ncalrpc(struct dcesrv_context *dce_ctx,
1642 struct loadparm_context *lp_ctx,
1643 struct dcesrv_endpoint *e,
1644 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1646 struct dcesrv_socket_context *dcesrv_sock;
1647 uint16_t port = 1;
1648 char *full_path;
1649 NTSTATUS status;
1651 if (!e->ep_description->endpoint) {
1652 /* No identifier specified: use DEFAULT.
1653 * DO NOT hardcode this value anywhere else. Rather, specify
1654 * no endpoint and let the epmapper worry about it. */
1655 e->ep_description->endpoint = talloc_strdup(dce_ctx, "DEFAULT");
1658 full_path = talloc_asprintf(dce_ctx, "%s/%s", lpcfg_ncalrpc_dir(lp_ctx),
1659 e->ep_description->endpoint);
1661 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1662 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1664 /* remember the endpoint of this socket */
1665 dcesrv_sock->endpoint = e;
1666 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1668 status = stream_setup_socket(dcesrv_sock, event_ctx, lp_ctx,
1669 model_ops, &dcesrv_stream_ops,
1670 "unix", full_path, &port,
1671 lpcfg_socket_options(lp_ctx),
1672 dcesrv_sock);
1673 if (!NT_STATUS_IS_OK(status)) {
1674 DEBUG(0,("service_setup_stream_socket(identifier=%s,path=%s) failed - %s\n",
1675 e->ep_description->endpoint, full_path, nt_errstr(status)));
1677 return status;
1680 static NTSTATUS dcesrv_add_ep_np(struct dcesrv_context *dce_ctx,
1681 struct loadparm_context *lp_ctx,
1682 struct dcesrv_endpoint *e,
1683 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1685 struct dcesrv_socket_context *dcesrv_sock;
1686 NTSTATUS status;
1688 if (e->ep_description->endpoint == NULL) {
1689 DEBUG(0, ("Endpoint mandatory for named pipes\n"));
1690 return NT_STATUS_INVALID_PARAMETER;
1693 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1694 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1696 /* remember the endpoint of this socket */
1697 dcesrv_sock->endpoint = e;
1698 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1700 status = tstream_setup_named_pipe(dce_ctx, event_ctx, lp_ctx,
1701 model_ops, &dcesrv_stream_ops,
1702 e->ep_description->endpoint,
1703 dcesrv_sock);
1704 if (!NT_STATUS_IS_OK(status)) {
1705 DEBUG(0,("stream_setup_named_pipe(pipe=%s) failed - %s\n",
1706 e->ep_description->endpoint, nt_errstr(status)));
1707 return status;
1710 return NT_STATUS_OK;
1714 add a socket address to the list of events, one event per dcerpc endpoint
1716 static NTSTATUS add_socket_rpc_tcp_iface(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e,
1717 struct tevent_context *event_ctx, const struct model_ops *model_ops,
1718 const char *address)
1720 struct dcesrv_socket_context *dcesrv_sock;
1721 uint16_t port = 0;
1722 NTSTATUS status;
1724 if (e->ep_description->endpoint) {
1725 port = atoi(e->ep_description->endpoint);
1728 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1729 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1731 /* remember the endpoint of this socket */
1732 dcesrv_sock->endpoint = e;
1733 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1735 status = stream_setup_socket(dcesrv_sock, event_ctx, dce_ctx->lp_ctx,
1736 model_ops, &dcesrv_stream_ops,
1737 "ip", address, &port,
1738 lpcfg_socket_options(dce_ctx->lp_ctx),
1739 dcesrv_sock);
1740 if (!NT_STATUS_IS_OK(status)) {
1741 DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) failed - %s\n",
1742 address, port, nt_errstr(status)));
1745 if (e->ep_description->endpoint == NULL) {
1746 e->ep_description->endpoint = talloc_asprintf(dce_ctx, "%d", port);
1749 return status;
1752 #include "lib/socket/netif.h" /* Included here to work around the fact that socket_wrapper redefines bind() */
1754 static NTSTATUS dcesrv_add_ep_tcp(struct dcesrv_context *dce_ctx,
1755 struct loadparm_context *lp_ctx,
1756 struct dcesrv_endpoint *e,
1757 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1759 NTSTATUS status;
1761 /* Add TCP/IP sockets */
1762 if (lpcfg_interfaces(lp_ctx) && lpcfg_bind_interfaces_only(lp_ctx)) {
1763 int num_interfaces;
1764 int i;
1765 struct interface *ifaces;
1767 load_interface_list(dce_ctx, lp_ctx, &ifaces);
1769 num_interfaces = iface_list_count(ifaces);
1770 for(i = 0; i < num_interfaces; i++) {
1771 const char *address = iface_list_n_ip(ifaces, i);
1772 status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, address);
1773 NT_STATUS_NOT_OK_RETURN(status);
1775 } else {
1776 char **wcard;
1777 int i;
1778 int num_binds = 0;
1779 wcard = iface_list_wildcard(dce_ctx);
1780 NT_STATUS_HAVE_NO_MEMORY(wcard);
1781 for (i=0; wcard[i]; i++) {
1782 status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, wcard[i]);
1783 if (NT_STATUS_IS_OK(status)) {
1784 num_binds++;
1787 talloc_free(wcard);
1788 if (num_binds == 0) {
1789 return NT_STATUS_INVALID_PARAMETER_MIX;
1793 return NT_STATUS_OK;
1796 NTSTATUS dcesrv_add_ep(struct dcesrv_context *dce_ctx,
1797 struct loadparm_context *lp_ctx,
1798 struct dcesrv_endpoint *e,
1799 struct tevent_context *event_ctx,
1800 const struct model_ops *model_ops)
1802 switch (e->ep_description->transport) {
1803 case NCACN_UNIX_STREAM:
1804 return dcesrv_add_ep_unix(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1806 case NCALRPC:
1807 return dcesrv_add_ep_ncalrpc(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1809 case NCACN_IP_TCP:
1810 return dcesrv_add_ep_tcp(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1812 case NCACN_NP:
1813 return dcesrv_add_ep_np(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1815 default:
1816 return NT_STATUS_NOT_SUPPORTED;
1822 * retrieve credentials from a dce_call
1824 _PUBLIC_ struct cli_credentials *dcesrv_call_credentials(struct dcesrv_call_state *dce_call)
1826 return dce_call->conn->auth_state.session_info->credentials;
1830 * returns true if this is an authenticated call
1832 _PUBLIC_ bool dcesrv_call_authenticated(struct dcesrv_call_state *dce_call)
1834 enum security_user_level level;
1835 level = security_session_user_level(dce_call->conn->auth_state.session_info, NULL);
1836 return level >= SECURITY_USER;
1840 * retrieve account_name for a dce_call
1842 _PUBLIC_ const char *dcesrv_call_account_name(struct dcesrv_call_state *dce_call)
1844 return dce_call->context->conn->auth_state.session_info->info->account_name;