2 Unix SMB/CIFS implementation.
4 server side dcerpc core code
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) Stefan (metze) Metzmacher 2004-2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "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"
43 #include "librpc/gen_ndr/ndr_dcerpc.h"
45 /* this is only used when the client asks for an unknown interface */
46 #define DUMMY_ASSOC_GROUP 0x0FFFFFFF
48 extern const struct dcesrv_interface dcesrv_mgmt_interface;
52 find an association group given a assoc_group_id
54 static struct dcesrv_assoc_group *dcesrv_assoc_group_find(struct dcesrv_context *dce_ctx,
59 id_ptr = idr_find(dce_ctx->assoc_groups_idr, id);
63 return talloc_get_type_abort(id_ptr, struct dcesrv_assoc_group);
67 take a reference to an existing association group
69 static struct dcesrv_assoc_group *dcesrv_assoc_group_reference(TALLOC_CTX *mem_ctx,
70 struct dcesrv_context *dce_ctx,
73 struct dcesrv_assoc_group *assoc_group;
75 assoc_group = dcesrv_assoc_group_find(dce_ctx, id);
76 if (assoc_group == NULL) {
77 DEBUG(0,(__location__ ": Failed to find assoc_group 0x%08x\n", id));
80 return talloc_reference(mem_ctx, assoc_group);
83 static int dcesrv_assoc_group_destructor(struct dcesrv_assoc_group *assoc_group)
86 ret = idr_remove(assoc_group->dce_ctx->assoc_groups_idr, assoc_group->id);
88 DEBUG(0,(__location__ ": Failed to remove assoc_group 0x%08x\n",
95 allocate a new association group
97 static struct dcesrv_assoc_group *dcesrv_assoc_group_new(TALLOC_CTX *mem_ctx,
98 struct dcesrv_context *dce_ctx)
100 struct dcesrv_assoc_group *assoc_group;
103 assoc_group = talloc_zero(mem_ctx, struct dcesrv_assoc_group);
104 if (assoc_group == NULL) {
108 id = idr_get_new_random(dce_ctx->assoc_groups_idr, assoc_group, UINT16_MAX);
110 talloc_free(assoc_group);
111 DEBUG(0,(__location__ ": Out of association groups!\n"));
115 assoc_group->id = id;
116 assoc_group->dce_ctx = dce_ctx;
118 talloc_set_destructor(assoc_group, dcesrv_assoc_group_destructor);
125 see if two endpoints match
127 static bool endpoints_match(const struct dcerpc_binding *ep1,
128 const struct dcerpc_binding *ep2)
130 enum dcerpc_transport_t t1;
131 enum dcerpc_transport_t t2;
135 t1 = dcerpc_binding_get_transport(ep1);
136 t2 = dcerpc_binding_get_transport(ep2);
138 e1 = dcerpc_binding_get_string_option(ep1, "endpoint");
139 e2 = dcerpc_binding_get_string_option(ep2, "endpoint");
149 if (strcasecmp(e1, e2) != 0) {
157 find an endpoint in the dcesrv_context
159 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
160 const struct dcerpc_binding *ep_description)
162 struct dcesrv_endpoint *ep;
163 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
164 if (endpoints_match(ep->ep_description, ep_description)) {
172 find a registered context_id from a bind or alter_context
174 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn,
177 struct dcesrv_connection_context *c;
178 for (c=conn->contexts;c;c=c->next) {
179 if (c->context_id == context_id) return c;
185 see if a uuid and if_version match to an interface
187 static bool interface_match(const struct dcesrv_interface *if1,
188 const struct dcesrv_interface *if2)
190 return (if1->syntax_id.if_version == if2->syntax_id.if_version &&
191 GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
195 find the interface operations on an endpoint
197 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
198 const struct dcesrv_interface *iface)
200 struct dcesrv_if_list *ifl;
201 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
202 if (interface_match(&(ifl->iface), iface)) {
203 return &(ifl->iface);
210 see if a uuid and if_version match to an interface
212 static bool interface_match_by_uuid(const struct dcesrv_interface *iface,
213 const struct GUID *uuid, uint32_t if_version)
215 return (iface->syntax_id.if_version == if_version &&
216 GUID_equal(&iface->syntax_id.uuid, uuid));
220 find the interface operations on an endpoint by uuid
222 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
223 const struct GUID *uuid, uint32_t if_version)
225 struct dcesrv_if_list *ifl;
226 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
227 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
228 return &(ifl->iface);
235 find the earlier parts of a fragmented call awaiting reassembily
237 static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
239 struct dcesrv_call_state *c;
240 for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
241 if (c->pkt.call_id == call_id) {
249 register an interface on an endpoint
251 _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
253 const struct dcesrv_interface *iface,
254 const struct security_descriptor *sd)
256 struct dcesrv_endpoint *ep;
257 struct dcesrv_if_list *ifl;
258 struct dcerpc_binding *binding;
262 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
264 if (NT_STATUS_IS_ERR(status)) {
265 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
269 /* check if this endpoint exists
271 if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
272 ep = talloc_zero(dce_ctx, struct dcesrv_endpoint);
274 return NT_STATUS_NO_MEMORY;
277 ep->ep_description = talloc_move(ep, &binding);
280 /* add mgmt interface */
281 ifl = talloc_zero(ep, struct dcesrv_if_list);
283 return NT_STATUS_NO_MEMORY;
286 memcpy(&(ifl->iface), &dcesrv_mgmt_interface,
287 sizeof(struct dcesrv_interface));
289 DLIST_ADD(ep->interface_list, ifl);
292 /* see if the interface is already registered on te endpoint */
293 if (find_interface(ep, iface)!=NULL) {
294 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
295 iface->name, ep_name));
296 return NT_STATUS_OBJECT_NAME_COLLISION;
299 /* talloc a new interface list element */
300 ifl = talloc_zero(ep, struct dcesrv_if_list);
302 return NT_STATUS_NO_MEMORY;
305 /* copy the given interface struct to the one on the endpoints interface list */
306 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
308 /* if we have a security descriptor given,
309 * we should see if we can set it up on the endpoint
312 /* if there's currently no security descriptor given on the endpoint
315 if (ep->sd == NULL) {
316 ep->sd = security_descriptor_copy(ep, sd);
319 /* if now there's no security descriptor given on the endpoint
320 * something goes wrong, either we failed to copy the security descriptor
321 * or there was already one on the endpoint
323 if (ep->sd != NULL) {
324 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
325 " on endpoint '%s'\n",
326 iface->name, ep_name));
327 if (add_ep) free(ep);
329 return NT_STATUS_OBJECT_NAME_COLLISION;
333 /* finally add the interface on the endpoint */
334 DLIST_ADD(ep->interface_list, ifl);
336 /* if it's a new endpoint add it to the dcesrv_context */
338 DLIST_ADD(dce_ctx->endpoint_list, ep);
341 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
342 iface->name, ep_name));
347 NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
348 DATA_BLOB *session_key)
350 if (p->auth_state.session_info->session_key.length) {
351 *session_key = p->auth_state.session_info->session_key;
354 return NT_STATUS_NO_USER_SESSION_KEY;
358 fetch the user session key - may be default (above) or the SMB session key
360 The key is always truncated to 16 bytes
362 _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
363 DATA_BLOB *session_key)
365 NTSTATUS status = p->auth_state.session_key(p, session_key);
366 if (!NT_STATUS_IS_OK(status)) {
370 session_key->length = MIN(session_key->length, 16);
376 connect to a dcerpc endpoint
378 _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
380 const struct dcesrv_endpoint *ep,
381 struct auth_session_info *session_info,
382 struct tevent_context *event_ctx,
383 struct imessaging_context *msg_ctx,
384 struct server_id server_id,
385 uint32_t state_flags,
386 struct dcesrv_connection **_p)
388 struct dcesrv_connection *p;
391 return NT_STATUS_ACCESS_DENIED;
394 p = talloc_zero(mem_ctx, struct dcesrv_connection);
395 NT_STATUS_HAVE_NO_MEMORY(p);
397 if (!talloc_reference(p, session_info)) {
399 return NT_STATUS_NO_MEMORY;
402 p->dce_ctx = dce_ctx;
404 p->packet_log_dir = lpcfg_lock_directory(dce_ctx->lp_ctx);
405 p->auth_state.session_info = session_info;
406 p->auth_state.session_key = dcesrv_generic_session_key;
407 p->event_ctx = event_ctx;
408 p->msg_ctx = msg_ctx;
409 p->server_id = server_id;
410 p->state_flags = state_flags;
411 p->max_recv_frag = 5840;
412 p->max_xmit_frag = 5840;
419 move a call from an existing linked list to the specified list. This
420 prevents bugs where we forget to remove the call from a previous
423 static void dcesrv_call_set_list(struct dcesrv_call_state *call,
424 enum dcesrv_call_list list)
426 switch (call->list) {
427 case DCESRV_LIST_NONE:
429 case DCESRV_LIST_CALL_LIST:
430 DLIST_REMOVE(call->conn->call_list, call);
432 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
433 DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
435 case DCESRV_LIST_PENDING_CALL_LIST:
436 DLIST_REMOVE(call->conn->pending_call_list, call);
441 case DCESRV_LIST_NONE:
443 case DCESRV_LIST_CALL_LIST:
444 DLIST_ADD_END(call->conn->call_list, call);
446 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
447 DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call);
449 case DCESRV_LIST_PENDING_CALL_LIST:
450 DLIST_ADD_END(call->conn->pending_call_list, call);
457 return a dcerpc bind_nak
459 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
461 struct ncacn_packet pkt;
462 struct dcerpc_bind_nak_version version;
463 struct data_blob_list_item *rep;
465 static const uint8_t _pad[3] = { 0, };
467 /* setup a bind_nak */
468 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
470 pkt.call_id = call->pkt.call_id;
471 pkt.ptype = DCERPC_PKT_BIND_NAK;
472 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
473 pkt.u.bind_nak.reject_reason = reason;
474 version.rpc_vers = 5;
475 version.rpc_vers_minor = 0;
476 pkt.u.bind_nak.num_versions = 1;
477 pkt.u.bind_nak.versions = &version;
478 pkt.u.bind_nak._pad = data_blob_const(_pad, sizeof(_pad));
480 rep = talloc_zero(call, struct data_blob_list_item);
482 return NT_STATUS_NO_MEMORY;
485 status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
486 if (!NT_STATUS_IS_OK(status)) {
490 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
492 DLIST_ADD_END(call->replies, rep);
493 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
495 if (call->conn->call_list && call->conn->call_list->replies) {
496 if (call->conn->transport.report_output_data) {
497 call->conn->transport.report_output_data(call->conn);
504 static int dcesrv_connection_context_destructor(struct dcesrv_connection_context *c)
506 DLIST_REMOVE(c->conn->contexts, c);
508 if (c->iface && c->iface->unbind) {
509 c->iface->unbind(c, c->iface);
516 static void dcesrv_prepare_context_auth(struct dcesrv_call_state *dce_call)
518 struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
519 const struct dcesrv_endpoint *endpoint = dce_call->conn->endpoint;
520 enum dcerpc_transport_t transport =
521 dcerpc_binding_get_transport(endpoint->ep_description);
522 struct dcesrv_connection_context *context = dce_call->context;
523 const struct dcesrv_interface *iface = context->iface;
525 context->min_auth_level = DCERPC_AUTH_LEVEL_NONE;
527 if (transport == NCALRPC) {
528 context->allow_connect = true;
533 * allow overwrite per interface
534 * allow dcerpc auth level connect:<interface>
536 context->allow_connect = lpcfg_allow_dcerpc_auth_level_connect(lp_ctx);
537 context->allow_connect = lpcfg_parm_bool(lp_ctx, NULL,
538 "allow dcerpc auth level connect",
540 context->allow_connect);
543 NTSTATUS dcesrv_interface_bind_require_integrity(struct dcesrv_call_state *dce_call,
544 const struct dcesrv_interface *iface)
546 if (dce_call->context == NULL) {
547 return NT_STATUS_INTERNAL_ERROR;
550 dce_call->context->min_auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
554 NTSTATUS dcesrv_interface_bind_require_privacy(struct dcesrv_call_state *dce_call,
555 const struct dcesrv_interface *iface)
557 if (dce_call->context == NULL) {
558 return NT_STATUS_INTERNAL_ERROR;
561 dce_call->context->min_auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
565 _PUBLIC_ NTSTATUS dcesrv_interface_bind_reject_connect(struct dcesrv_call_state *dce_call,
566 const struct dcesrv_interface *iface)
568 struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
569 const struct dcesrv_endpoint *endpoint = dce_call->conn->endpoint;
570 enum dcerpc_transport_t transport =
571 dcerpc_binding_get_transport(endpoint->ep_description);
572 struct dcesrv_connection_context *context = dce_call->context;
574 if (context == NULL) {
575 return NT_STATUS_INTERNAL_ERROR;
578 if (transport == NCALRPC) {
579 context->allow_connect = true;
584 * allow overwrite per interface
585 * allow dcerpc auth level connect:<interface>
587 context->allow_connect = false;
588 context->allow_connect = lpcfg_parm_bool(lp_ctx, NULL,
589 "allow dcerpc auth level connect",
591 context->allow_connect);
595 _PUBLIC_ NTSTATUS dcesrv_interface_bind_allow_connect(struct dcesrv_call_state *dce_call,
596 const struct dcesrv_interface *iface)
598 struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
599 const struct dcesrv_endpoint *endpoint = dce_call->conn->endpoint;
600 enum dcerpc_transport_t transport =
601 dcerpc_binding_get_transport(endpoint->ep_description);
602 struct dcesrv_connection_context *context = dce_call->context;
604 if (context == NULL) {
605 return NT_STATUS_INTERNAL_ERROR;
608 if (transport == NCALRPC) {
609 context->allow_connect = true;
614 * allow overwrite per interface
615 * allow dcerpc auth level connect:<interface>
617 context->allow_connect = true;
618 context->allow_connect = lpcfg_parm_bool(lp_ctx, NULL,
619 "allow dcerpc auth level connect",
621 context->allow_connect);
626 handle a bind request
628 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
630 uint32_t if_version, transfer_syntax_version;
631 struct GUID uuid, *transfer_syntax_uuid;
632 struct ncacn_packet pkt;
633 struct data_blob_list_item *rep;
635 uint32_t result=0, reason=0;
637 const struct dcesrv_interface *iface;
638 uint32_t extra_flags = 0;
639 uint16_t max_req = 0;
640 uint16_t max_rep = 0;
642 /* max_recv_frag and max_xmit_frag result always in the same value! */
643 max_req = MIN(call->pkt.u.bind.max_xmit_frag,
644 call->pkt.u.bind.max_recv_frag);
646 * The values are between 2048 and 5840 tested against Windows 2012R2
647 * via ncacn_ip_tcp on port 135.
649 max_req = MAX(2048, max_req);
650 max_rep = MIN(max_req, call->conn->max_recv_frag);
651 /* They are truncated to an 8 byte boundary. */
654 /* max_recv_frag and max_xmit_frag result always in the same value! */
655 call->conn->max_recv_frag = max_rep;
656 call->conn->max_xmit_frag = max_rep;
659 if provided, check the assoc_group is valid
661 if (call->pkt.u.bind.assoc_group_id != 0 &&
662 lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
663 dcesrv_assoc_group_find(call->conn->dce_ctx, call->pkt.u.bind.assoc_group_id) == NULL) {
664 return dcesrv_bind_nak(call, 0);
667 if (call->pkt.u.bind.num_contexts < 1 ||
668 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
669 return dcesrv_bind_nak(call, 0);
672 context_id = call->pkt.u.bind.ctx_list[0].context_id;
674 /* you can't bind twice on one context */
675 if (dcesrv_find_context(call->conn, context_id) != NULL) {
676 return dcesrv_bind_nak(call, 0);
679 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
680 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
682 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
683 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
684 if (!GUID_equal(&ndr_transfer_syntax_ndr.uuid, transfer_syntax_uuid) != 0 ||
685 ndr_transfer_syntax_ndr.if_version != transfer_syntax_version) {
686 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
687 /* we only do NDR encoded dcerpc */
688 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
689 talloc_free(uuid_str);
690 return dcesrv_bind_nak(call, 0);
693 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
695 char *uuid_str = GUID_string(call, &uuid);
696 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
697 talloc_free(uuid_str);
699 /* we don't know about that interface */
700 result = DCERPC_BIND_PROVIDER_REJECT;
701 reason = DCERPC_BIND_REASON_ASYNTAX;
705 /* add this context to the list of available context_ids */
706 struct dcesrv_connection_context *context = talloc_zero(call->conn,
707 struct dcesrv_connection_context);
708 if (context == NULL) {
709 return dcesrv_bind_nak(call, 0);
711 context->conn = call->conn;
712 context->iface = iface;
713 context->context_id = context_id;
714 if (call->pkt.u.bind.assoc_group_id != 0) {
715 context->assoc_group = dcesrv_assoc_group_reference(context,
717 call->pkt.u.bind.assoc_group_id);
719 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
721 if (context->assoc_group == NULL) {
722 talloc_free(context);
723 return dcesrv_bind_nak(call, 0);
725 context->private_data = NULL;
726 DLIST_ADD(call->conn->contexts, context);
727 call->context = context;
728 talloc_set_destructor(context, dcesrv_connection_context_destructor);
730 dcesrv_prepare_context_auth(call);
732 status = iface->bind(call, iface, if_version);
733 if (!NT_STATUS_IS_OK(status)) {
734 char *uuid_str = GUID_string(call, &uuid);
735 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
736 uuid_str, if_version, nt_errstr(status)));
737 talloc_free(uuid_str);
738 /* we don't want to trigger the iface->unbind() hook */
739 context->iface = NULL;
740 talloc_free(call->context);
741 call->context = NULL;
742 return dcesrv_bind_nak(call, 0);
746 if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_CONC_MPX) &&
747 (call->state_flags & DCESRV_CALL_STATE_FLAG_MULTIPLEXED)) {
748 call->context->conn->state_flags |= DCESRV_CALL_STATE_FLAG_MULTIPLEXED;
749 extra_flags |= DCERPC_PFC_FLAG_CONC_MPX;
752 if (call->state_flags & DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL) {
753 call->context->conn->state_flags |= DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL;
756 /* handle any authentication that is being requested */
757 if (!dcesrv_auth_bind(call)) {
758 talloc_free(call->context);
759 call->context = NULL;
760 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
763 /* setup a bind_ack */
764 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
766 pkt.call_id = call->pkt.call_id;
767 pkt.ptype = DCERPC_PKT_BIND_ACK;
768 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
769 pkt.u.bind_ack.max_xmit_frag = call->conn->max_xmit_frag;
770 pkt.u.bind_ack.max_recv_frag = call->conn->max_recv_frag;
773 make it possible for iface->bind() to specify the assoc_group_id
774 This helps the openchange mapiproxy plugin to work correctly.
779 pkt.u.bind_ack.assoc_group_id = call->context->assoc_group->id;
781 pkt.u.bind_ack.assoc_group_id = DUMMY_ASSOC_GROUP;
785 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
786 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
788 pkt.u.bind_ack.secondary_address = "";
790 pkt.u.bind_ack.num_results = 1;
791 pkt.u.bind_ack.ctx_list = talloc_zero(call, struct dcerpc_ack_ctx);
792 if (!pkt.u.bind_ack.ctx_list) {
793 talloc_free(call->context);
794 call->context = NULL;
795 return NT_STATUS_NO_MEMORY;
797 pkt.u.bind_ack.ctx_list[0].result = result;
798 pkt.u.bind_ack.ctx_list[0].reason.value = reason;
799 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax_ndr;
800 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
802 status = dcesrv_auth_bind_ack(call, &pkt);
803 if (!NT_STATUS_IS_OK(status)) {
804 talloc_free(call->context);
805 call->context = NULL;
806 return dcesrv_bind_nak(call, 0);
809 rep = talloc_zero(call, struct data_blob_list_item);
811 talloc_free(call->context);
812 call->context = NULL;
813 return NT_STATUS_NO_MEMORY;
816 status = ncacn_push_auth(&rep->blob, call, &pkt,
817 call->conn->auth_state.auth_info);
818 if (!NT_STATUS_IS_OK(status)) {
819 talloc_free(call->context);
820 call->context = NULL;
824 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
826 DLIST_ADD_END(call->replies, rep);
827 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
829 if (call->conn->call_list && call->conn->call_list->replies) {
830 if (call->conn->transport.report_output_data) {
831 call->conn->transport.report_output_data(call->conn);
840 handle a auth3 request
842 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
844 /* handle the auth3 in the auth code */
845 if (!dcesrv_auth_auth3(call)) {
846 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
851 /* we don't send a reply to a auth3 request, except by a
858 handle a bind request
860 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
862 uint32_t if_version, transfer_syntax_version;
863 struct dcesrv_connection_context *context;
864 const struct dcesrv_interface *iface;
865 struct GUID uuid, *transfer_syntax_uuid;
868 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
869 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
871 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
872 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
873 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax_ndr.uuid) ||
874 ndr_transfer_syntax_ndr.if_version != transfer_syntax_version) {
875 /* we only do NDR encoded dcerpc */
876 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
879 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
881 char *uuid_str = GUID_string(call, &uuid);
882 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
883 talloc_free(uuid_str);
884 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
887 /* add this context to the list of available context_ids */
888 context = talloc_zero(call->conn, struct dcesrv_connection_context);
889 if (context == NULL) {
890 return NT_STATUS_NO_MEMORY;
892 context->conn = call->conn;
893 context->iface = iface;
894 context->context_id = context_id;
895 if (call->pkt.u.alter.assoc_group_id != 0) {
896 context->assoc_group = dcesrv_assoc_group_reference(context,
898 call->pkt.u.alter.assoc_group_id);
900 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
902 if (context->assoc_group == NULL) {
903 talloc_free(context);
904 call->context = NULL;
905 return NT_STATUS_NO_MEMORY;
907 context->private_data = NULL;
908 DLIST_ADD(call->conn->contexts, context);
909 call->context = context;
910 talloc_set_destructor(context, dcesrv_connection_context_destructor);
912 dcesrv_prepare_context_auth(call);
914 status = iface->bind(call, iface, if_version);
915 if (!NT_STATUS_IS_OK(status)) {
916 /* we don't want to trigger the iface->unbind() hook */
917 context->iface = NULL;
918 talloc_free(context);
919 call->context = NULL;
926 /* setup and send an alter_resp */
927 static NTSTATUS dcesrv_alter_resp(struct dcesrv_call_state *call,
931 struct ncacn_packet pkt;
932 uint32_t extra_flags = 0;
933 struct data_blob_list_item *rep = NULL;
936 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
938 pkt.call_id = call->pkt.call_id;
939 pkt.ptype = DCERPC_PKT_ALTER_RESP;
941 if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_CONC_MPX) &&
942 call->context->conn->state_flags &
943 DCESRV_CALL_STATE_FLAG_MULTIPLEXED) {
944 extra_flags |= DCERPC_PFC_FLAG_CONC_MPX;
946 if (call->state_flags & DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL) {
947 call->context->conn->state_flags |=
948 DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL;
951 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
952 pkt.u.alter_resp.max_xmit_frag = call->conn->max_xmit_frag;
953 pkt.u.alter_resp.max_recv_frag = call->conn->max_recv_frag;
955 pkt.u.alter_resp.assoc_group_id = call->context->assoc_group->id;
957 pkt.u.alter_resp.assoc_group_id = 0;
959 pkt.u.alter_resp.num_results = 1;
960 pkt.u.alter_resp.ctx_list = talloc_zero(call, struct dcerpc_ack_ctx);
961 if (!pkt.u.alter_resp.ctx_list) {
962 return NT_STATUS_NO_MEMORY;
964 pkt.u.alter_resp.ctx_list[0].result = result;
965 pkt.u.alter_resp.ctx_list[0].reason.value = reason;
966 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax_ndr;
967 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
968 pkt.u.alter_resp.secondary_address = "";
970 status = dcesrv_auth_alter_ack(call, &pkt);
971 if (!NT_STATUS_IS_OK(status)) {
972 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
973 || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
974 || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
975 || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
976 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
978 return dcesrv_fault(call, 0);
981 rep = talloc_zero(call, struct data_blob_list_item);
983 return NT_STATUS_NO_MEMORY;
986 status = ncacn_push_auth(&rep->blob, call, &pkt, call->conn->auth_state.auth_info);
987 if (!NT_STATUS_IS_OK(status)) {
991 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
993 DLIST_ADD_END(call->replies, rep);
994 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
996 if (call->conn->call_list && call->conn->call_list->replies) {
997 if (call->conn->transport.report_output_data) {
998 call->conn->transport.report_output_data(call->conn);
1002 return NT_STATUS_OK;
1006 handle a alter context request
1008 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
1011 uint32_t context_id;
1013 /* handle any authentication that is being requested */
1014 if (!dcesrv_auth_alter(call)) {
1015 /* TODO: work out the right reject code */
1016 return dcesrv_alter_resp(call,
1017 DCERPC_BIND_PROVIDER_REJECT,
1018 DCERPC_BIND_REASON_ASYNTAX);
1021 context_id = call->pkt.u.alter.ctx_list[0].context_id;
1023 /* see if they are asking for a new interface */
1024 call->context = dcesrv_find_context(call->conn, context_id);
1025 if (!call->context) {
1026 status = dcesrv_alter_new_context(call, context_id);
1027 if (!NT_STATUS_IS_OK(status)) {
1028 return dcesrv_alter_resp(call,
1029 DCERPC_BIND_PROVIDER_REJECT,
1030 DCERPC_BIND_REASON_ASYNTAX);
1034 if (call->pkt.u.alter.assoc_group_id != 0 &&
1035 lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
1036 call->pkt.u.alter.assoc_group_id != call->context->assoc_group->id) {
1037 DEBUG(0,(__location__ ": Failed attempt to use new assoc_group in alter context (0x%08x 0x%08x)\n",
1038 call->context->assoc_group->id, call->pkt.u.alter.assoc_group_id));
1039 /* TODO: can they ask for a new association group? */
1040 return dcesrv_alter_resp(call,
1041 DCERPC_BIND_PROVIDER_REJECT,
1042 DCERPC_BIND_REASON_ASYNTAX);
1045 return dcesrv_alter_resp(call,
1046 DCERPC_BIND_ACK_RESULT_ACCEPTANCE,
1047 DCERPC_BIND_ACK_REASON_NOT_SPECIFIED);
1051 possibly save the call for inspection with ndrdump
1053 static void dcesrv_save_call(struct dcesrv_call_state *call, const char *why)
1057 const char *dump_dir;
1058 dump_dir = lpcfg_parm_string(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv", "stubs directory");
1062 fname = talloc_asprintf(call, "%s/RPC-%s-%u-%s.dat",
1064 call->context->iface->name,
1065 call->pkt.u.request.opnum,
1067 if (file_save(fname, call->pkt.u.request.stub_and_verifier.data, call->pkt.u.request.stub_and_verifier.length)) {
1068 DEBUG(0,("RPC SAVED %s\n", fname));
1074 static NTSTATUS dcesrv_check_verification_trailer(struct dcesrv_call_state *call)
1076 TALLOC_CTX *frame = talloc_stackframe();
1077 const uint32_t bitmask1 = call->conn->auth_state.client_hdr_signing ?
1078 DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING : 0;
1079 const struct dcerpc_sec_vt_pcontext pcontext = {
1080 .abstract_syntax = call->context->iface->syntax_id,
1081 .transfer_syntax = ndr_transfer_syntax_ndr,
1083 const struct dcerpc_sec_vt_header2 header2 =
1084 dcerpc_sec_vt_header2_from_ncacn_packet(&call->pkt);
1085 enum ndr_err_code ndr_err;
1086 struct dcerpc_sec_verification_trailer *vt = NULL;
1087 NTSTATUS status = NT_STATUS_OK;
1090 SMB_ASSERT(call->pkt.ptype == DCERPC_PKT_REQUEST);
1092 ndr_err = ndr_pop_dcerpc_sec_verification_trailer(call->ndr_pull,
1094 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1095 status = ndr_map_error2ntstatus(ndr_err);
1099 ok = dcerpc_sec_verification_trailer_check(vt, &bitmask1,
1100 &pcontext, &header2);
1102 status = NT_STATUS_ACCESS_DENIED;
1111 handle a dcerpc request packet
1113 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
1115 const struct dcesrv_endpoint *endpoint = call->conn->endpoint;
1116 enum dcerpc_transport_t transport =
1117 dcerpc_binding_get_transport(endpoint->ep_description);
1118 struct ndr_pull *pull;
1120 struct dcesrv_connection_context *context;
1122 /* if authenticated, and the mech we use can't do async replies, don't use them... */
1123 if (call->conn->auth_state.gensec_security &&
1124 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
1125 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
1128 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
1129 if (context == NULL) {
1130 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
1133 switch (call->conn->auth_state.auth_level) {
1134 case DCERPC_AUTH_LEVEL_NONE:
1135 case DCERPC_AUTH_LEVEL_INTEGRITY:
1136 case DCERPC_AUTH_LEVEL_PRIVACY:
1139 if (!context->allow_connect) {
1142 addr = tsocket_address_string(call->conn->remote_address,
1145 DEBUG(2, ("%s: restrict auth_level_connect access "
1146 "to [%s] with auth[type=0x%x,level=0x%x] "
1147 "on [%s] from [%s]\n",
1148 __func__, context->iface->name,
1149 call->conn->auth_state.auth_type,
1150 call->conn->auth_state.auth_level,
1151 derpc_transport_string_by_transport(transport),
1153 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1158 if (call->conn->auth_state.auth_level < context->min_auth_level) {
1161 addr = tsocket_address_string(call->conn->remote_address, call);
1163 DEBUG(2, ("%s: restrict access by min_auth_level[0x%x] "
1164 "to [%s] with auth[type=0x%x,level=0x%x] "
1165 "on [%s] from [%s]\n",
1167 context->min_auth_level,
1168 context->iface->name,
1169 call->conn->auth_state.auth_type,
1170 call->conn->auth_state.auth_level,
1171 derpc_transport_string_by_transport(transport),
1173 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1176 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
1177 NT_STATUS_HAVE_NO_MEMORY(pull);
1179 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1181 call->context = context;
1182 call->ndr_pull = pull;
1184 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
1185 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1188 status = dcesrv_check_verification_trailer(call);
1189 if (!NT_STATUS_IS_OK(status)) {
1190 uint32_t faultcode = DCERPC_FAULT_OTHER;
1191 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1192 faultcode = DCERPC_FAULT_ACCESS_DENIED;
1194 DEBUG(10, ("dcesrv_check_verification_trailer failed: %s\n",
1195 nt_errstr(status)));
1196 return dcesrv_fault(call, faultcode);
1199 /* unravel the NDR for the packet */
1200 status = context->iface->ndr_pull(call, call, pull, &call->r);
1201 if (!NT_STATUS_IS_OK(status)) {
1202 if (call->fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
1203 /* we got an unknown call */
1204 DEBUG(3,(__location__ ": Unknown RPC call %u on %s\n",
1205 call->pkt.u.request.opnum, context->iface->name));
1206 dcesrv_save_call(call, "unknown");
1208 dcesrv_save_call(call, "pullfail");
1210 return dcesrv_fault(call, call->fault_code);
1213 if (pull->offset != pull->data_size) {
1214 dcesrv_save_call(call, "extrabytes");
1215 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
1216 pull->data_size - pull->offset));
1219 /* call the dispatch function */
1220 status = context->iface->dispatch(call, call, call->r);
1221 if (!NT_STATUS_IS_OK(status)) {
1222 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
1223 context->iface->name,
1224 call->pkt.u.request.opnum,
1225 dcerpc_errstr(pull, call->fault_code)));
1226 return dcesrv_fault(call, call->fault_code);
1229 /* add the call to the pending list */
1230 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
1232 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
1233 return NT_STATUS_OK;
1236 return dcesrv_reply(call);
1241 remove the call from the right list when freed
1243 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1245 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1249 _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_local_address(struct dcesrv_connection *conn)
1251 return conn->local_address;
1254 _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_remote_address(struct dcesrv_connection *conn)
1256 return conn->remote_address;
1260 process some input to a dcerpc endpoint server.
1262 NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
1263 struct ncacn_packet *pkt,
1267 struct dcesrv_call_state *call;
1269 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1271 data_blob_free(&blob);
1273 return NT_STATUS_NO_MEMORY;
1275 call->conn = dce_conn;
1276 call->event_ctx = dce_conn->event_ctx;
1277 call->msg_ctx = dce_conn->msg_ctx;
1278 call->state_flags = call->conn->state_flags;
1279 call->time = timeval_current();
1280 call->list = DCESRV_LIST_NONE;
1282 talloc_steal(call, pkt);
1283 talloc_steal(call, blob.data);
1286 talloc_set_destructor(call, dcesrv_call_dequeue);
1288 /* we have to check the signing here, before combining the
1290 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1291 !dcesrv_auth_request(call, &blob)) {
1292 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1295 /* see if this is a continued packet */
1296 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1297 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1298 struct dcesrv_call_state *call2 = call;
1299 uint32_t alloc_size;
1301 /* we only allow fragmented requests, no other packet types */
1302 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1303 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1306 /* this is a continuation of an existing call - find the call
1307 then tack it on the end */
1308 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1310 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1313 if (call->pkt.ptype != call2->pkt.ptype) {
1314 /* trying to play silly buggers are we? */
1315 return dcesrv_fault(call2, DCERPC_NCA_S_PROTO_ERROR);
1317 if (memcmp(call->pkt.drep, call2->pkt.drep, sizeof(pkt->drep)) != 0) {
1318 return dcesrv_fault(call2, DCERPC_NCA_S_PROTO_ERROR);
1320 if (call->pkt.call_id != call2->pkt.call_id) {
1321 return dcesrv_fault(call2, DCERPC_NCA_S_PROTO_ERROR);
1323 if (call->pkt.u.request.context_id != call2->pkt.u.request.context_id) {
1324 return dcesrv_fault(call2, DCERPC_NCA_S_PROTO_ERROR);
1326 if (call->pkt.u.request.opnum != call2->pkt.u.request.opnum) {
1327 return dcesrv_fault(call2, DCERPC_NCA_S_PROTO_ERROR);
1330 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1331 call2->pkt.u.request.stub_and_verifier.length;
1332 if (call->pkt.u.request.alloc_hint > alloc_size) {
1333 alloc_size = call->pkt.u.request.alloc_hint;
1336 call->pkt.u.request.stub_and_verifier.data =
1337 talloc_realloc(call,
1338 call->pkt.u.request.stub_and_verifier.data,
1339 uint8_t, alloc_size);
1340 if (!call->pkt.u.request.stub_and_verifier.data) {
1341 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1343 memcpy(call->pkt.u.request.stub_and_verifier.data +
1344 call->pkt.u.request.stub_and_verifier.length,
1345 call2->pkt.u.request.stub_and_verifier.data,
1346 call2->pkt.u.request.stub_and_verifier.length);
1347 call->pkt.u.request.stub_and_verifier.length +=
1348 call2->pkt.u.request.stub_and_verifier.length;
1350 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1355 /* this may not be the last pdu in the chain - if its isn't then
1356 just put it on the incoming_fragmented_call_list and wait for the rest */
1357 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1358 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1359 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1360 return NT_STATUS_OK;
1363 /* This removes any fragments we may have had stashed away */
1364 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1366 switch (call->pkt.ptype) {
1367 case DCERPC_PKT_BIND:
1368 status = dcesrv_bind(call);
1370 case DCERPC_PKT_AUTH3:
1371 status = dcesrv_auth3(call);
1373 case DCERPC_PKT_ALTER:
1374 status = dcesrv_alter(call);
1376 case DCERPC_PKT_REQUEST:
1377 status = dcesrv_request(call);
1380 status = NT_STATUS_INVALID_PARAMETER;
1384 /* if we are going to be sending a reply then add
1385 it to the list of pending calls. We add it to the end to keep the call
1386 list in the order we will answer */
1387 if (!NT_STATUS_IS_OK(status)) {
1394 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1395 struct loadparm_context *lp_ctx,
1396 const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1399 struct dcesrv_context *dce_ctx;
1402 if (!endpoint_servers) {
1403 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1404 return NT_STATUS_INTERNAL_ERROR;
1407 dce_ctx = talloc_zero(mem_ctx, struct dcesrv_context);
1408 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1410 if (uid_wrapper_enabled()) {
1411 setenv("UID_WRAPPER_MYUID", "1", 1);
1413 dce_ctx->initial_euid = geteuid();
1414 if (uid_wrapper_enabled()) {
1415 unsetenv("UID_WRAPPER_MYUID");
1418 dce_ctx->endpoint_list = NULL;
1419 dce_ctx->lp_ctx = lp_ctx;
1420 dce_ctx->assoc_groups_idr = idr_init(dce_ctx);
1421 NT_STATUS_HAVE_NO_MEMORY(dce_ctx->assoc_groups_idr);
1422 dce_ctx->broken_connections = NULL;
1424 for (i=0;endpoint_servers[i];i++) {
1425 const struct dcesrv_endpoint_server *ep_server;
1427 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1429 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1430 return NT_STATUS_INTERNAL_ERROR;
1433 status = ep_server->init_server(dce_ctx, ep_server);
1434 if (!NT_STATUS_IS_OK(status)) {
1435 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1436 nt_errstr(status)));
1441 *_dce_ctx = dce_ctx;
1442 return NT_STATUS_OK;
1445 /* the list of currently registered DCERPC endpoint servers.
1447 static struct ep_server {
1448 struct dcesrv_endpoint_server *ep_server;
1449 } *ep_servers = NULL;
1450 static int num_ep_servers;
1453 register a DCERPC endpoint server.
1455 The 'name' can be later used by other backends to find the operations
1456 structure for this backend.
1458 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1460 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1462 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1464 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1465 /* its already registered! */
1466 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1468 return NT_STATUS_OBJECT_NAME_COLLISION;
1471 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1473 smb_panic("out of memory in dcerpc_register");
1476 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1477 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1481 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1484 return NT_STATUS_OK;
1488 return the operations structure for a named backend of the specified type
1490 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1494 for (i=0;i<num_ep_servers;i++) {
1495 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1496 return ep_servers[i].ep_server;
1503 void dcerpc_server_init(struct loadparm_context *lp_ctx)
1505 static bool initialized;
1506 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
1507 STATIC_dcerpc_server_MODULES_PROTO;
1508 init_module_fn static_init[] = { STATIC_dcerpc_server_MODULES };
1509 init_module_fn *shared_init;
1516 shared_init = load_samba_modules(NULL, "dcerpc_server");
1518 run_init_functions(static_init);
1519 run_init_functions(shared_init);
1521 talloc_free(shared_init);
1525 return the DCERPC module version, and the size of some critical types
1526 This can be used by endpoint server modules to either detect compilation errors, or provide
1527 multiple implementations for different smbd compilation options in one module
1529 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1531 static const struct dcesrv_critical_sizes critical_sizes = {
1532 DCERPC_MODULE_VERSION,
1533 sizeof(struct dcesrv_context),
1534 sizeof(struct dcesrv_endpoint),
1535 sizeof(struct dcesrv_endpoint_server),
1536 sizeof(struct dcesrv_interface),
1537 sizeof(struct dcesrv_if_list),
1538 sizeof(struct dcesrv_connection),
1539 sizeof(struct dcesrv_call_state),
1540 sizeof(struct dcesrv_auth),
1541 sizeof(struct dcesrv_handle)
1544 return &critical_sizes;
1547 static void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, const char *reason)
1549 struct dcesrv_context *dce_ctx = dce_conn->dce_ctx;
1550 struct stream_connection *srv_conn;
1551 srv_conn = talloc_get_type(dce_conn->transport.private_data,
1552 struct stream_connection);
1554 if (dce_conn->pending_call_list == NULL) {
1555 char *full_reason = talloc_asprintf(dce_conn, "dcesrv: %s", reason);
1557 DLIST_REMOVE(dce_ctx->broken_connections, dce_conn);
1558 stream_terminate_connection(srv_conn, full_reason ? full_reason : reason);
1562 if (dce_conn->terminate != NULL) {
1566 DEBUG(3,("dcesrv: terminating connection due to '%s' defered due to pending calls\n",
1568 dce_conn->terminate = talloc_strdup(dce_conn, reason);
1569 if (dce_conn->terminate == NULL) {
1570 dce_conn->terminate = "dcesrv: defered terminating connection - no memory";
1572 DLIST_ADD_END(dce_ctx->broken_connections, dce_conn);
1575 static void dcesrv_cleanup_broken_connections(struct dcesrv_context *dce_ctx)
1577 struct dcesrv_connection *cur, *next;
1579 next = dce_ctx->broken_connections;
1580 while (next != NULL) {
1584 if (cur->state_flags & DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL) {
1585 struct dcesrv_connection_context *context_cur, *context_next;
1587 context_next = cur->contexts;
1588 while (context_next != NULL) {
1589 context_cur = context_next;
1590 context_next = context_cur->next;
1592 dcesrv_connection_context_destructor(context_cur);
1596 dcesrv_terminate_connection(cur, cur->terminate);
1600 /* We need this include to be able to compile on some plateforms
1601 * (ie. freebsd 7.2) as it seems that <sys/uio.h> is not included
1603 * It has to be that deep because otherwise we have a conflict on
1604 * const struct dcesrv_interface declaration.
1605 * This is mostly due to socket_wrapper defining #define bind swrap_bind
1606 * which conflict with the bind used before.
1608 #include "system/network.h"
1610 struct dcesrv_sock_reply_state {
1611 struct dcesrv_connection *dce_conn;
1612 struct dcesrv_call_state *call;
1616 static void dcesrv_sock_reply_done(struct tevent_req *subreq);
1618 static void dcesrv_sock_report_output_data(struct dcesrv_connection *dce_conn)
1620 struct dcesrv_call_state *call;
1622 call = dce_conn->call_list;
1623 if (!call || !call->replies) {
1627 while (call->replies) {
1628 struct data_blob_list_item *rep = call->replies;
1629 struct dcesrv_sock_reply_state *substate;
1630 struct tevent_req *subreq;
1632 substate = talloc_zero(call, struct dcesrv_sock_reply_state);
1634 dcesrv_terminate_connection(dce_conn, "no memory");
1638 substate->dce_conn = dce_conn;
1639 substate->call = NULL;
1641 DLIST_REMOVE(call->replies, rep);
1643 if (call->replies == NULL) {
1644 substate->call = call;
1647 substate->iov.iov_base = (void *) rep->blob.data;
1648 substate->iov.iov_len = rep->blob.length;
1650 subreq = tstream_writev_queue_send(substate,
1651 dce_conn->event_ctx,
1653 dce_conn->send_queue,
1656 dcesrv_terminate_connection(dce_conn, "no memory");
1659 tevent_req_set_callback(subreq, dcesrv_sock_reply_done,
1663 DLIST_REMOVE(call->conn->call_list, call);
1664 call->list = DCESRV_LIST_NONE;
1667 static void dcesrv_sock_reply_done(struct tevent_req *subreq)
1669 struct dcesrv_sock_reply_state *substate = tevent_req_callback_data(subreq,
1670 struct dcesrv_sock_reply_state);
1674 struct dcesrv_call_state *call = substate->call;
1676 ret = tstream_writev_queue_recv(subreq, &sys_errno);
1677 TALLOC_FREE(subreq);
1679 status = map_nt_error_from_unix_common(sys_errno);
1680 dcesrv_terminate_connection(substate->dce_conn, nt_errstr(status));
1684 talloc_free(substate);
1693 struct dcesrv_socket_context {
1694 const struct dcesrv_endpoint *endpoint;
1695 struct dcesrv_context *dcesrv_ctx;
1699 static void dcesrv_read_fragment_done(struct tevent_req *subreq);
1701 static void dcesrv_sock_accept(struct stream_connection *srv_conn)
1704 struct dcesrv_socket_context *dcesrv_sock =
1705 talloc_get_type(srv_conn->private_data, struct dcesrv_socket_context);
1706 enum dcerpc_transport_t transport =
1707 dcerpc_binding_get_transport(dcesrv_sock->endpoint->ep_description);
1708 struct dcesrv_connection *dcesrv_conn = NULL;
1710 struct tevent_req *subreq;
1711 struct loadparm_context *lp_ctx = dcesrv_sock->dcesrv_ctx->lp_ctx;
1713 dcesrv_cleanup_broken_connections(dcesrv_sock->dcesrv_ctx);
1715 if (!srv_conn->session_info) {
1716 status = auth_anonymous_session_info(srv_conn,
1718 &srv_conn->session_info);
1719 if (!NT_STATUS_IS_OK(status)) {
1720 DEBUG(0,("dcesrv_sock_accept: auth_anonymous_session_info failed: %s\n",
1721 nt_errstr(status)));
1722 stream_terminate_connection(srv_conn, nt_errstr(status));
1727 status = dcesrv_endpoint_connect(dcesrv_sock->dcesrv_ctx,
1729 dcesrv_sock->endpoint,
1730 srv_conn->session_info,
1731 srv_conn->event.ctx,
1733 srv_conn->server_id,
1734 DCESRV_CALL_STATE_FLAG_MAY_ASYNC,
1736 if (!NT_STATUS_IS_OK(status)) {
1737 DEBUG(0,("dcesrv_sock_accept: dcesrv_endpoint_connect failed: %s\n",
1738 nt_errstr(status)));
1739 stream_terminate_connection(srv_conn, nt_errstr(status));
1743 dcesrv_conn->transport.private_data = srv_conn;
1744 dcesrv_conn->transport.report_output_data = dcesrv_sock_report_output_data;
1746 TALLOC_FREE(srv_conn->event.fde);
1748 dcesrv_conn->send_queue = tevent_queue_create(dcesrv_conn, "dcesrv send queue");
1749 if (!dcesrv_conn->send_queue) {
1750 status = NT_STATUS_NO_MEMORY;
1751 DEBUG(0,("dcesrv_sock_accept: tevent_queue_create(%s)\n",
1752 nt_errstr(status)));
1753 stream_terminate_connection(srv_conn, nt_errstr(status));
1757 if (transport == NCACN_NP) {
1758 dcesrv_conn->auth_state.session_key = dcesrv_inherited_session_key;
1759 dcesrv_conn->stream = talloc_move(dcesrv_conn,
1760 &srv_conn->tstream);
1762 ret = tstream_bsd_existing_socket(dcesrv_conn,
1763 socket_get_fd(srv_conn->socket),
1764 &dcesrv_conn->stream);
1766 status = map_nt_error_from_unix_common(errno);
1767 DEBUG(0, ("dcesrv_sock_accept: "
1768 "failed to setup tstream: %s\n",
1769 nt_errstr(status)));
1770 stream_terminate_connection(srv_conn, nt_errstr(status));
1773 socket_set_flags(srv_conn->socket, SOCKET_FLAG_NOCLOSE);
1776 dcesrv_conn->local_address = srv_conn->local_address;
1777 dcesrv_conn->remote_address = srv_conn->remote_address;
1779 if (transport == NCALRPC) {
1783 ret = getpeereid(socket_get_fd(srv_conn->socket), &uid, &gid);
1785 status = map_nt_error_from_unix_common(errno);
1786 DEBUG(0, ("dcesrv_sock_accept: "
1787 "getpeereid() failed for NCALRPC: %s\n",
1788 nt_errstr(status)));
1789 stream_terminate_connection(srv_conn, nt_errstr(status));
1792 if (uid == dcesrv_conn->dce_ctx->initial_euid) {
1793 struct tsocket_address *r = NULL;
1795 ret = tsocket_address_unix_from_path(dcesrv_conn,
1796 "/root/ncalrpc_as_system",
1799 status = map_nt_error_from_unix_common(errno);
1800 DEBUG(0, ("dcesrv_sock_accept: "
1801 "tsocket_address_unix_from_path() failed for NCALRPC: %s\n",
1802 nt_errstr(status)));
1803 stream_terminate_connection(srv_conn, nt_errstr(status));
1806 dcesrv_conn->remote_address = r;
1810 srv_conn->private_data = dcesrv_conn;
1812 irpc_add_name(srv_conn->msg_ctx, "rpc_server");
1814 subreq = dcerpc_read_ncacn_packet_send(dcesrv_conn,
1815 dcesrv_conn->event_ctx,
1816 dcesrv_conn->stream);
1818 status = NT_STATUS_NO_MEMORY;
1819 DEBUG(0,("dcesrv_sock_accept: dcerpc_read_fragment_buffer_send(%s)\n",
1820 nt_errstr(status)));
1821 stream_terminate_connection(srv_conn, nt_errstr(status));
1824 tevent_req_set_callback(subreq, dcesrv_read_fragment_done, dcesrv_conn);
1829 static void dcesrv_read_fragment_done(struct tevent_req *subreq)
1831 struct dcesrv_connection *dce_conn = tevent_req_callback_data(subreq,
1832 struct dcesrv_connection);
1833 struct dcesrv_context *dce_ctx = dce_conn->dce_ctx;
1834 struct ncacn_packet *pkt;
1838 if (dce_conn->terminate) {
1840 * if the current connection is broken
1841 * we need to clean it up before any other connection
1843 dcesrv_terminate_connection(dce_conn, dce_conn->terminate);
1844 dcesrv_cleanup_broken_connections(dce_ctx);
1848 dcesrv_cleanup_broken_connections(dce_ctx);
1850 status = dcerpc_read_ncacn_packet_recv(subreq, dce_conn,
1852 TALLOC_FREE(subreq);
1853 if (!NT_STATUS_IS_OK(status)) {
1854 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1858 status = dcesrv_process_ncacn_packet(dce_conn, pkt, buffer);
1859 if (!NT_STATUS_IS_OK(status)) {
1860 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1864 subreq = dcerpc_read_ncacn_packet_send(dce_conn,
1865 dce_conn->event_ctx,
1868 status = NT_STATUS_NO_MEMORY;
1869 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1872 tevent_req_set_callback(subreq, dcesrv_read_fragment_done, dce_conn);
1875 static void dcesrv_sock_recv(struct stream_connection *conn, uint16_t flags)
1877 struct dcesrv_connection *dce_conn = talloc_get_type(conn->private_data,
1878 struct dcesrv_connection);
1879 dcesrv_terminate_connection(dce_conn, "dcesrv_sock_recv triggered");
1882 static void dcesrv_sock_send(struct stream_connection *conn, uint16_t flags)
1884 struct dcesrv_connection *dce_conn = talloc_get_type(conn->private_data,
1885 struct dcesrv_connection);
1886 dcesrv_terminate_connection(dce_conn, "dcesrv_sock_send triggered");
1890 static const struct stream_server_ops dcesrv_stream_ops = {
1892 .accept_connection = dcesrv_sock_accept,
1893 .recv_handler = dcesrv_sock_recv,
1894 .send_handler = dcesrv_sock_send,
1897 static NTSTATUS dcesrv_add_ep_unix(struct dcesrv_context *dce_ctx,
1898 struct loadparm_context *lp_ctx,
1899 struct dcesrv_endpoint *e,
1900 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1902 struct dcesrv_socket_context *dcesrv_sock;
1905 const char *endpoint;
1907 dcesrv_sock = talloc_zero(event_ctx, struct dcesrv_socket_context);
1908 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1910 /* remember the endpoint of this socket */
1911 dcesrv_sock->endpoint = e;
1912 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1914 endpoint = dcerpc_binding_get_string_option(e->ep_description, "endpoint");
1916 status = stream_setup_socket(dcesrv_sock, event_ctx, lp_ctx,
1917 model_ops, &dcesrv_stream_ops,
1918 "unix", endpoint, &port,
1919 lpcfg_socket_options(lp_ctx),
1921 if (!NT_STATUS_IS_OK(status)) {
1922 DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n",
1923 endpoint, nt_errstr(status)));
1929 static NTSTATUS dcesrv_add_ep_ncalrpc(struct dcesrv_context *dce_ctx,
1930 struct loadparm_context *lp_ctx,
1931 struct dcesrv_endpoint *e,
1932 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1934 struct dcesrv_socket_context *dcesrv_sock;
1938 const char *endpoint;
1940 endpoint = dcerpc_binding_get_string_option(e->ep_description, "endpoint");
1942 if (endpoint == NULL) {
1944 * No identifier specified: use DEFAULT.
1946 * TODO: DO NOT hardcode this value anywhere else. Rather, specify
1947 * no endpoint and let the epmapper worry about it.
1949 endpoint = "DEFAULT";
1950 status = dcerpc_binding_set_string_option(e->ep_description,
1953 if (!NT_STATUS_IS_OK(status)) {
1954 DEBUG(0,("dcerpc_binding_set_string_option() failed - %s\n",
1955 nt_errstr(status)));
1960 full_path = talloc_asprintf(dce_ctx, "%s/%s", lpcfg_ncalrpc_dir(lp_ctx),
1963 dcesrv_sock = talloc_zero(event_ctx, struct dcesrv_socket_context);
1964 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1966 /* remember the endpoint of this socket */
1967 dcesrv_sock->endpoint = e;
1968 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1970 status = stream_setup_socket(dcesrv_sock, event_ctx, lp_ctx,
1971 model_ops, &dcesrv_stream_ops,
1972 "unix", full_path, &port,
1973 lpcfg_socket_options(lp_ctx),
1975 if (!NT_STATUS_IS_OK(status)) {
1976 DEBUG(0,("service_setup_stream_socket(identifier=%s,path=%s) failed - %s\n",
1977 endpoint, full_path, nt_errstr(status)));
1982 static NTSTATUS dcesrv_add_ep_np(struct dcesrv_context *dce_ctx,
1983 struct loadparm_context *lp_ctx,
1984 struct dcesrv_endpoint *e,
1985 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1987 struct dcesrv_socket_context *dcesrv_sock;
1989 const char *endpoint;
1991 endpoint = dcerpc_binding_get_string_option(e->ep_description, "endpoint");
1992 if (endpoint == NULL) {
1993 DEBUG(0, ("Endpoint mandatory for named pipes\n"));
1994 return NT_STATUS_INVALID_PARAMETER;
1997 dcesrv_sock = talloc_zero(event_ctx, struct dcesrv_socket_context);
1998 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
2000 /* remember the endpoint of this socket */
2001 dcesrv_sock->endpoint = e;
2002 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
2004 status = tstream_setup_named_pipe(dce_ctx, event_ctx, lp_ctx,
2005 model_ops, &dcesrv_stream_ops,
2008 if (!NT_STATUS_IS_OK(status)) {
2009 DEBUG(0,("stream_setup_named_pipe(pipe=%s) failed - %s\n",
2010 endpoint, nt_errstr(status)));
2014 return NT_STATUS_OK;
2018 add a socket address to the list of events, one event per dcerpc endpoint
2020 static NTSTATUS add_socket_rpc_tcp_iface(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e,
2021 struct tevent_context *event_ctx, const struct model_ops *model_ops,
2022 const char *address)
2024 struct dcesrv_socket_context *dcesrv_sock;
2027 const char *endpoint;
2030 endpoint = dcerpc_binding_get_string_option(e->ep_description, "endpoint");
2031 if (endpoint != NULL) {
2032 port = atoi(endpoint);
2035 dcesrv_sock = talloc_zero(event_ctx, struct dcesrv_socket_context);
2036 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
2038 /* remember the endpoint of this socket */
2039 dcesrv_sock->endpoint = e;
2040 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
2042 status = stream_setup_socket(dcesrv_sock, event_ctx, dce_ctx->lp_ctx,
2043 model_ops, &dcesrv_stream_ops,
2044 "ip", address, &port,
2045 lpcfg_socket_options(dce_ctx->lp_ctx),
2047 if (!NT_STATUS_IS_OK(status)) {
2048 DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) failed - %s\n",
2049 address, port, nt_errstr(status)));
2053 snprintf(port_str, sizeof(port_str), "%u", port);
2055 status = dcerpc_binding_set_string_option(e->ep_description,
2056 "endpoint", port_str);
2057 if (!NT_STATUS_IS_OK(status)) {
2058 DEBUG(0,("dcerpc_binding_set_string_option(endpoint, %s) failed - %s\n",
2059 port_str, nt_errstr(status)));
2063 return NT_STATUS_OK;
2066 #include "lib/socket/netif.h" /* Included here to work around the fact that socket_wrapper redefines bind() */
2068 static NTSTATUS dcesrv_add_ep_tcp(struct dcesrv_context *dce_ctx,
2069 struct loadparm_context *lp_ctx,
2070 struct dcesrv_endpoint *e,
2071 struct tevent_context *event_ctx, const struct model_ops *model_ops)
2075 /* Add TCP/IP sockets */
2076 if (lpcfg_interfaces(lp_ctx) && lpcfg_bind_interfaces_only(lp_ctx)) {
2079 struct interface *ifaces;
2081 load_interface_list(dce_ctx, lp_ctx, &ifaces);
2083 num_interfaces = iface_list_count(ifaces);
2084 for(i = 0; i < num_interfaces; i++) {
2085 const char *address = iface_list_n_ip(ifaces, i);
2086 status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, address);
2087 NT_STATUS_NOT_OK_RETURN(status);
2093 wcard = iface_list_wildcard(dce_ctx);
2094 NT_STATUS_HAVE_NO_MEMORY(wcard);
2095 for (i=0; wcard[i]; i++) {
2096 status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, wcard[i]);
2097 if (NT_STATUS_IS_OK(status)) {
2102 if (num_binds == 0) {
2103 return NT_STATUS_INVALID_PARAMETER_MIX;
2107 return NT_STATUS_OK;
2110 NTSTATUS dcesrv_add_ep(struct dcesrv_context *dce_ctx,
2111 struct loadparm_context *lp_ctx,
2112 struct dcesrv_endpoint *e,
2113 struct tevent_context *event_ctx,
2114 const struct model_ops *model_ops)
2116 enum dcerpc_transport_t transport =
2117 dcerpc_binding_get_transport(e->ep_description);
2119 switch (transport) {
2120 case NCACN_UNIX_STREAM:
2121 return dcesrv_add_ep_unix(dce_ctx, lp_ctx, e, event_ctx, model_ops);
2124 return dcesrv_add_ep_ncalrpc(dce_ctx, lp_ctx, e, event_ctx, model_ops);
2127 return dcesrv_add_ep_tcp(dce_ctx, lp_ctx, e, event_ctx, model_ops);
2130 return dcesrv_add_ep_np(dce_ctx, lp_ctx, e, event_ctx, model_ops);
2133 return NT_STATUS_NOT_SUPPORTED;
2139 * retrieve credentials from a dce_call
2141 _PUBLIC_ struct cli_credentials *dcesrv_call_credentials(struct dcesrv_call_state *dce_call)
2143 return dce_call->conn->auth_state.session_info->credentials;
2147 * returns true if this is an authenticated call
2149 _PUBLIC_ bool dcesrv_call_authenticated(struct dcesrv_call_state *dce_call)
2151 enum security_user_level level;
2152 level = security_session_user_level(dce_call->conn->auth_state.session_info, NULL);
2153 return level >= SECURITY_USER;
2157 * retrieve account_name for a dce_call
2159 _PUBLIC_ const char *dcesrv_call_account_name(struct dcesrv_call_state *dce_call)
2161 return dce_call->context->conn->auth_state.session_info->info->account_name;