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(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(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(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
;
417 move a call from an existing linked list to the specified list. This
418 prevents bugs where we forget to remove the call from a previous
421 static void dcesrv_call_set_list(struct dcesrv_call_state
*call
,
422 enum dcesrv_call_list list
)
424 switch (call
->list
) {
425 case DCESRV_LIST_NONE
:
427 case DCESRV_LIST_CALL_LIST
:
428 DLIST_REMOVE(call
->conn
->call_list
, call
);
430 case DCESRV_LIST_FRAGMENTED_CALL_LIST
:
431 DLIST_REMOVE(call
->conn
->incoming_fragmented_call_list
, call
);
433 case DCESRV_LIST_PENDING_CALL_LIST
:
434 DLIST_REMOVE(call
->conn
->pending_call_list
, call
);
439 case DCESRV_LIST_NONE
:
441 case DCESRV_LIST_CALL_LIST
:
442 DLIST_ADD_END(call
->conn
->call_list
, call
, struct dcesrv_call_state
*);
444 case DCESRV_LIST_FRAGMENTED_CALL_LIST
:
445 DLIST_ADD_END(call
->conn
->incoming_fragmented_call_list
, call
, struct dcesrv_call_state
*);
447 case DCESRV_LIST_PENDING_CALL_LIST
:
448 DLIST_ADD_END(call
->conn
->pending_call_list
, call
, struct dcesrv_call_state
*);
455 return a dcerpc bind_nak
457 static NTSTATUS
dcesrv_bind_nak(struct dcesrv_call_state
*call
, uint32_t reason
)
459 struct ncacn_packet pkt
;
460 struct dcerpc_bind_nak_version version
;
461 struct data_blob_list_item
*rep
;
464 /* setup a bind_nak */
465 dcesrv_init_hdr(&pkt
, lpcfg_rpc_big_endian(call
->conn
->dce_ctx
->lp_ctx
));
467 pkt
.call_id
= call
->pkt
.call_id
;
468 pkt
.ptype
= DCERPC_PKT_BIND_NAK
;
469 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
470 pkt
.u
.bind_nak
.reject_reason
= reason
;
471 version
.rpc_vers
= 5;
472 version
.rpc_vers_minor
= 0;
473 pkt
.u
.bind_nak
.num_versions
= 1;
474 pkt
.u
.bind_nak
.versions
= &version
;
475 pkt
.u
.bind_nak
._pad
= data_blob_null
;
477 rep
= talloc(call
, struct data_blob_list_item
);
479 return NT_STATUS_NO_MEMORY
;
482 status
= ncacn_push_auth(&rep
->blob
, call
, &pkt
, NULL
);
483 if (!NT_STATUS_IS_OK(status
)) {
487 dcerpc_set_frag_length(&rep
->blob
, rep
->blob
.length
);
489 DLIST_ADD_END(call
->replies
, rep
, struct data_blob_list_item
*);
490 dcesrv_call_set_list(call
, DCESRV_LIST_CALL_LIST
);
492 if (call
->conn
->call_list
&& call
->conn
->call_list
->replies
) {
493 if (call
->conn
->transport
.report_output_data
) {
494 call
->conn
->transport
.report_output_data(call
->conn
);
501 static int dcesrv_connection_context_destructor(struct dcesrv_connection_context
*c
)
503 DLIST_REMOVE(c
->conn
->contexts
, c
);
505 if (c
->iface
&& c
->iface
->unbind
) {
506 c
->iface
->unbind(c
, c
->iface
);
514 handle a bind request
516 static NTSTATUS
dcesrv_bind(struct dcesrv_call_state
*call
)
518 uint32_t if_version
, transfer_syntax_version
;
519 struct GUID uuid
, *transfer_syntax_uuid
;
520 struct ncacn_packet pkt
;
521 struct data_blob_list_item
*rep
;
523 uint32_t result
=0, reason
=0;
525 const struct dcesrv_interface
*iface
;
526 uint32_t extra_flags
= 0;
529 if provided, check the assoc_group is valid
531 if (call
->pkt
.u
.bind
.assoc_group_id
!= 0 &&
532 lpcfg_parm_bool(call
->conn
->dce_ctx
->lp_ctx
, NULL
, "dcesrv","assoc group checking", true) &&
533 dcesrv_assoc_group_find(call
->conn
->dce_ctx
, call
->pkt
.u
.bind
.assoc_group_id
) == NULL
) {
534 return dcesrv_bind_nak(call
, 0);
537 if (call
->pkt
.u
.bind
.num_contexts
< 1 ||
538 call
->pkt
.u
.bind
.ctx_list
[0].num_transfer_syntaxes
< 1) {
539 return dcesrv_bind_nak(call
, 0);
542 context_id
= call
->pkt
.u
.bind
.ctx_list
[0].context_id
;
544 /* you can't bind twice on one context */
545 if (dcesrv_find_context(call
->conn
, context_id
) != NULL
) {
546 return dcesrv_bind_nak(call
, 0);
549 if_version
= call
->pkt
.u
.bind
.ctx_list
[0].abstract_syntax
.if_version
;
550 uuid
= call
->pkt
.u
.bind
.ctx_list
[0].abstract_syntax
.uuid
;
552 transfer_syntax_version
= call
->pkt
.u
.bind
.ctx_list
[0].transfer_syntaxes
[0].if_version
;
553 transfer_syntax_uuid
= &call
->pkt
.u
.bind
.ctx_list
[0].transfer_syntaxes
[0].uuid
;
554 if (!GUID_equal(&ndr_transfer_syntax_ndr
.uuid
, transfer_syntax_uuid
) != 0 ||
555 ndr_transfer_syntax_ndr
.if_version
!= transfer_syntax_version
) {
556 char *uuid_str
= GUID_string(call
, transfer_syntax_uuid
);
557 /* we only do NDR encoded dcerpc */
558 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str
));
559 talloc_free(uuid_str
);
560 return dcesrv_bind_nak(call
, 0);
563 iface
= find_interface_by_uuid(call
->conn
->endpoint
, &uuid
, if_version
);
565 char *uuid_str
= GUID_string(call
, &uuid
);
566 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str
, if_version
));
567 talloc_free(uuid_str
);
569 /* we don't know about that interface */
570 result
= DCERPC_BIND_PROVIDER_REJECT
;
571 reason
= DCERPC_BIND_REASON_ASYNTAX
;
575 /* add this context to the list of available context_ids */
576 struct dcesrv_connection_context
*context
= talloc(call
->conn
,
577 struct dcesrv_connection_context
);
578 if (context
== NULL
) {
579 return dcesrv_bind_nak(call
, 0);
581 context
->conn
= call
->conn
;
582 context
->iface
= iface
;
583 context
->context_id
= context_id
;
584 if (call
->pkt
.u
.bind
.assoc_group_id
!= 0) {
585 context
->assoc_group
= dcesrv_assoc_group_reference(context
,
587 call
->pkt
.u
.bind
.assoc_group_id
);
589 context
->assoc_group
= dcesrv_assoc_group_new(context
, call
->conn
->dce_ctx
);
591 if (context
->assoc_group
== NULL
) {
592 talloc_free(context
);
593 return dcesrv_bind_nak(call
, 0);
595 context
->private_data
= NULL
;
596 DLIST_ADD(call
->conn
->contexts
, context
);
597 call
->context
= context
;
598 talloc_set_destructor(context
, dcesrv_connection_context_destructor
);
600 status
= iface
->bind(call
, iface
, if_version
);
601 if (!NT_STATUS_IS_OK(status
)) {
602 char *uuid_str
= GUID_string(call
, &uuid
);
603 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
604 uuid_str
, if_version
, nt_errstr(status
)));
605 talloc_free(uuid_str
);
606 /* we don't want to trigger the iface->unbind() hook */
607 context
->iface
= NULL
;
608 talloc_free(call
->context
);
609 call
->context
= NULL
;
610 return dcesrv_bind_nak(call
, 0);
614 if (call
->conn
->cli_max_recv_frag
== 0) {
615 call
->conn
->cli_max_recv_frag
= MIN(0x2000, call
->pkt
.u
.bind
.max_recv_frag
);
618 if ((call
->pkt
.pfc_flags
& DCERPC_PFC_FLAG_CONC_MPX
) &&
619 (call
->state_flags
& DCESRV_CALL_STATE_FLAG_MULTIPLEXED
)) {
620 call
->context
->conn
->state_flags
|= DCESRV_CALL_STATE_FLAG_MULTIPLEXED
;
621 extra_flags
|= DCERPC_PFC_FLAG_CONC_MPX
;
624 if (call
->state_flags
& DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL
) {
625 call
->context
->conn
->state_flags
|= DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL
;
628 /* handle any authentication that is being requested */
629 if (!dcesrv_auth_bind(call
)) {
630 talloc_free(call
->context
);
631 call
->context
= NULL
;
632 return dcesrv_bind_nak(call
, DCERPC_BIND_REASON_INVALID_AUTH_TYPE
);
635 /* setup a bind_ack */
636 dcesrv_init_hdr(&pkt
, lpcfg_rpc_big_endian(call
->conn
->dce_ctx
->lp_ctx
));
638 pkt
.call_id
= call
->pkt
.call_id
;
639 pkt
.ptype
= DCERPC_PKT_BIND_ACK
;
640 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
| extra_flags
;
641 pkt
.u
.bind_ack
.max_xmit_frag
= call
->conn
->cli_max_recv_frag
;
642 pkt
.u
.bind_ack
.max_recv_frag
= 0x2000;
645 make it possible for iface->bind() to specify the assoc_group_id
646 This helps the openchange mapiproxy plugin to work correctly.
651 pkt
.u
.bind_ack
.assoc_group_id
= call
->context
->assoc_group
->id
;
653 pkt
.u
.bind_ack
.assoc_group_id
= DUMMY_ASSOC_GROUP
;
657 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
658 pkt
.u
.bind_ack
.secondary_address
= talloc_asprintf(call
, "\\PIPE\\%s", iface
->name
);
660 pkt
.u
.bind_ack
.secondary_address
= "";
662 pkt
.u
.bind_ack
.num_results
= 1;
663 pkt
.u
.bind_ack
.ctx_list
= talloc(call
, struct dcerpc_ack_ctx
);
664 if (!pkt
.u
.bind_ack
.ctx_list
) {
665 talloc_free(call
->context
);
666 call
->context
= NULL
;
667 return NT_STATUS_NO_MEMORY
;
669 pkt
.u
.bind_ack
.ctx_list
[0].result
= result
;
670 pkt
.u
.bind_ack
.ctx_list
[0].reason
.value
= reason
;
671 pkt
.u
.bind_ack
.ctx_list
[0].syntax
= ndr_transfer_syntax_ndr
;
672 pkt
.u
.bind_ack
.auth_info
= data_blob(NULL
, 0);
674 status
= dcesrv_auth_bind_ack(call
, &pkt
);
675 if (!NT_STATUS_IS_OK(status
)) {
676 talloc_free(call
->context
);
677 call
->context
= NULL
;
678 return dcesrv_bind_nak(call
, 0);
681 rep
= talloc(call
, struct data_blob_list_item
);
683 talloc_free(call
->context
);
684 call
->context
= NULL
;
685 return NT_STATUS_NO_MEMORY
;
688 status
= ncacn_push_auth(&rep
->blob
, call
, &pkt
,
689 call
->conn
->auth_state
.auth_info
);
690 if (!NT_STATUS_IS_OK(status
)) {
691 talloc_free(call
->context
);
692 call
->context
= NULL
;
696 dcerpc_set_frag_length(&rep
->blob
, rep
->blob
.length
);
698 DLIST_ADD_END(call
->replies
, rep
, struct data_blob_list_item
*);
699 dcesrv_call_set_list(call
, DCESRV_LIST_CALL_LIST
);
701 if (call
->conn
->call_list
&& call
->conn
->call_list
->replies
) {
702 if (call
->conn
->transport
.report_output_data
) {
703 call
->conn
->transport
.report_output_data(call
->conn
);
712 handle a auth3 request
714 static NTSTATUS
dcesrv_auth3(struct dcesrv_call_state
*call
)
716 /* handle the auth3 in the auth code */
717 if (!dcesrv_auth_auth3(call
)) {
718 return dcesrv_fault(call
, DCERPC_FAULT_OTHER
);
723 /* we don't send a reply to a auth3 request, except by a
730 handle a bind request
732 static NTSTATUS
dcesrv_alter_new_context(struct dcesrv_call_state
*call
, uint32_t context_id
)
734 uint32_t if_version
, transfer_syntax_version
;
735 struct dcesrv_connection_context
*context
;
736 const struct dcesrv_interface
*iface
;
737 struct GUID uuid
, *transfer_syntax_uuid
;
740 if_version
= call
->pkt
.u
.alter
.ctx_list
[0].abstract_syntax
.if_version
;
741 uuid
= call
->pkt
.u
.alter
.ctx_list
[0].abstract_syntax
.uuid
;
743 transfer_syntax_version
= call
->pkt
.u
.alter
.ctx_list
[0].transfer_syntaxes
[0].if_version
;
744 transfer_syntax_uuid
= &call
->pkt
.u
.alter
.ctx_list
[0].transfer_syntaxes
[0].uuid
;
745 if (!GUID_equal(transfer_syntax_uuid
, &ndr_transfer_syntax_ndr
.uuid
) ||
746 ndr_transfer_syntax_ndr
.if_version
!= transfer_syntax_version
) {
747 /* we only do NDR encoded dcerpc */
748 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED
;
751 iface
= find_interface_by_uuid(call
->conn
->endpoint
, &uuid
, if_version
);
753 char *uuid_str
= GUID_string(call
, &uuid
);
754 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str
, if_version
));
755 talloc_free(uuid_str
);
756 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED
;
759 /* add this context to the list of available context_ids */
760 context
= talloc(call
->conn
, struct dcesrv_connection_context
);
761 if (context
== NULL
) {
762 return NT_STATUS_NO_MEMORY
;
764 context
->conn
= call
->conn
;
765 context
->iface
= iface
;
766 context
->context_id
= context_id
;
767 if (call
->pkt
.u
.alter
.assoc_group_id
!= 0) {
768 context
->assoc_group
= dcesrv_assoc_group_reference(context
,
770 call
->pkt
.u
.alter
.assoc_group_id
);
772 context
->assoc_group
= dcesrv_assoc_group_new(context
, call
->conn
->dce_ctx
);
774 if (context
->assoc_group
== NULL
) {
775 talloc_free(context
);
776 call
->context
= NULL
;
777 return NT_STATUS_NO_MEMORY
;
779 context
->private_data
= NULL
;
780 DLIST_ADD(call
->conn
->contexts
, context
);
781 call
->context
= context
;
782 talloc_set_destructor(context
, dcesrv_connection_context_destructor
);
784 status
= iface
->bind(call
, iface
, if_version
);
785 if (!NT_STATUS_IS_OK(status
)) {
786 /* we don't want to trigger the iface->unbind() hook */
787 context
->iface
= NULL
;
788 talloc_free(context
);
789 call
->context
= NULL
;
796 /* setup and send an alter_resp */
797 static NTSTATUS
dcesrv_alter_resp(struct dcesrv_call_state
*call
,
801 struct ncacn_packet pkt
;
802 uint32_t extra_flags
= 0;
803 struct data_blob_list_item
*rep
= NULL
;
806 dcesrv_init_hdr(&pkt
, lpcfg_rpc_big_endian(call
->conn
->dce_ctx
->lp_ctx
));
808 pkt
.call_id
= call
->pkt
.call_id
;
809 pkt
.ptype
= DCERPC_PKT_ALTER_RESP
;
811 if ((call
->pkt
.pfc_flags
& DCERPC_PFC_FLAG_CONC_MPX
) &&
812 call
->context
->conn
->state_flags
&
813 DCESRV_CALL_STATE_FLAG_MULTIPLEXED
) {
814 extra_flags
|= DCERPC_PFC_FLAG_CONC_MPX
;
816 if (call
->state_flags
& DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL
) {
817 call
->context
->conn
->state_flags
|=
818 DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL
;
821 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
| extra_flags
;
822 pkt
.u
.alter_resp
.max_xmit_frag
= 0x2000;
823 pkt
.u
.alter_resp
.max_recv_frag
= 0x2000;
825 pkt
.u
.alter_resp
.assoc_group_id
= call
->context
->assoc_group
->id
;
827 pkt
.u
.alter_resp
.assoc_group_id
= 0;
829 pkt
.u
.alter_resp
.num_results
= 1;
830 pkt
.u
.alter_resp
.ctx_list
= talloc_array(call
, struct dcerpc_ack_ctx
, 1);
831 if (!pkt
.u
.alter_resp
.ctx_list
) {
832 return NT_STATUS_NO_MEMORY
;
834 pkt
.u
.alter_resp
.ctx_list
[0].result
= result
;
835 pkt
.u
.alter_resp
.ctx_list
[0].reason
.value
= reason
;
836 pkt
.u
.alter_resp
.ctx_list
[0].syntax
= ndr_transfer_syntax_ndr
;
837 pkt
.u
.alter_resp
.auth_info
= data_blob(NULL
, 0);
838 pkt
.u
.alter_resp
.secondary_address
= "";
840 status
= dcesrv_auth_alter_ack(call
, &pkt
);
841 if (!NT_STATUS_IS_OK(status
)) {
842 if (NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)
843 || NT_STATUS_EQUAL(status
, NT_STATUS_LOGON_FAILURE
)
844 || NT_STATUS_EQUAL(status
, NT_STATUS_NO_SUCH_USER
)
845 || NT_STATUS_EQUAL(status
, NT_STATUS_WRONG_PASSWORD
)) {
846 return dcesrv_fault(call
, DCERPC_FAULT_ACCESS_DENIED
);
848 return dcesrv_fault(call
, 0);
851 rep
= talloc(call
, struct data_blob_list_item
);
853 return NT_STATUS_NO_MEMORY
;
856 status
= ncacn_push_auth(&rep
->blob
, call
, &pkt
, call
->conn
->auth_state
.auth_info
);
857 if (!NT_STATUS_IS_OK(status
)) {
861 dcerpc_set_frag_length(&rep
->blob
, rep
->blob
.length
);
863 DLIST_ADD_END(call
->replies
, rep
, struct data_blob_list_item
*);
864 dcesrv_call_set_list(call
, DCESRV_LIST_CALL_LIST
);
866 if (call
->conn
->call_list
&& call
->conn
->call_list
->replies
) {
867 if (call
->conn
->transport
.report_output_data
) {
868 call
->conn
->transport
.report_output_data(call
->conn
);
876 handle a alter context request
878 static NTSTATUS
dcesrv_alter(struct dcesrv_call_state
*call
)
883 /* handle any authentication that is being requested */
884 if (!dcesrv_auth_alter(call
)) {
885 /* TODO: work out the right reject code */
886 return dcesrv_alter_resp(call
,
887 DCERPC_BIND_PROVIDER_REJECT
,
888 DCERPC_BIND_REASON_ASYNTAX
);
891 context_id
= call
->pkt
.u
.alter
.ctx_list
[0].context_id
;
893 /* see if they are asking for a new interface */
894 call
->context
= dcesrv_find_context(call
->conn
, context_id
);
895 if (!call
->context
) {
896 status
= dcesrv_alter_new_context(call
, context_id
);
897 if (!NT_STATUS_IS_OK(status
)) {
898 return dcesrv_alter_resp(call
,
899 DCERPC_BIND_PROVIDER_REJECT
,
900 DCERPC_BIND_REASON_ASYNTAX
);
904 if (call
->pkt
.u
.alter
.assoc_group_id
!= 0 &&
905 lpcfg_parm_bool(call
->conn
->dce_ctx
->lp_ctx
, NULL
, "dcesrv","assoc group checking", true) &&
906 call
->pkt
.u
.alter
.assoc_group_id
!= call
->context
->assoc_group
->id
) {
907 DEBUG(0,(__location__
": Failed attempt to use new assoc_group in alter context (0x%08x 0x%08x)\n",
908 call
->context
->assoc_group
->id
, call
->pkt
.u
.alter
.assoc_group_id
));
909 /* TODO: can they ask for a new association group? */
910 return dcesrv_alter_resp(call
,
911 DCERPC_BIND_PROVIDER_REJECT
,
912 DCERPC_BIND_REASON_ASYNTAX
);
915 return dcesrv_alter_resp(call
,
916 DCERPC_BIND_ACK_RESULT_ACCEPTANCE
,
917 DCERPC_BIND_ACK_REASON_NOT_SPECIFIED
);
921 possibly save the call for inspection with ndrdump
923 static void dcesrv_save_call(struct dcesrv_call_state
*call
, const char *why
)
927 const char *dump_dir
;
928 dump_dir
= lpcfg_parm_string(call
->conn
->dce_ctx
->lp_ctx
, NULL
, "dcesrv", "stubs directory");
932 fname
= talloc_asprintf(call
, "%s/RPC-%s-%u-%s.dat",
934 call
->context
->iface
->name
,
935 call
->pkt
.u
.request
.opnum
,
937 if (file_save(fname
, call
->pkt
.u
.request
.stub_and_verifier
.data
, call
->pkt
.u
.request
.stub_and_verifier
.length
)) {
938 DEBUG(0,("RPC SAVED %s\n", fname
));
944 static NTSTATUS
dcesrv_check_verification_trailer(struct dcesrv_call_state
*call
)
946 TALLOC_CTX
*frame
= talloc_stackframe();
947 const uint32_t bitmask1
= call
->conn
->auth_state
.client_hdr_signing
?
948 DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING
: 0;
949 const struct dcerpc_sec_vt_pcontext pcontext
= {
950 .abstract_syntax
= call
->context
->iface
->syntax_id
,
951 .transfer_syntax
= ndr_transfer_syntax_ndr
,
953 const struct dcerpc_sec_vt_header2 header2
=
954 dcerpc_sec_vt_header2_from_ncacn_packet(&call
->pkt
);
955 enum ndr_err_code ndr_err
;
956 struct dcerpc_sec_verification_trailer
*vt
= NULL
;
957 NTSTATUS status
= NT_STATUS_OK
;
960 SMB_ASSERT(call
->pkt
.ptype
== DCERPC_PKT_REQUEST
);
962 ndr_err
= ndr_pop_dcerpc_sec_verification_trailer(call
->ndr_pull
,
964 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
965 status
= ndr_map_error2ntstatus(ndr_err
);
969 ok
= dcerpc_sec_verification_trailer_check(vt
, &bitmask1
,
970 &pcontext
, &header2
);
972 status
= NT_STATUS_ACCESS_DENIED
;
981 handle a dcerpc request packet
983 static NTSTATUS
dcesrv_request(struct dcesrv_call_state
*call
)
985 struct ndr_pull
*pull
;
987 struct dcesrv_connection_context
*context
;
989 /* if authenticated, and the mech we use can't do async replies, don't use them... */
990 if (call
->conn
->auth_state
.gensec_security
&&
991 !gensec_have_feature(call
->conn
->auth_state
.gensec_security
, GENSEC_FEATURE_ASYNC_REPLIES
)) {
992 call
->state_flags
&= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC
;
995 context
= dcesrv_find_context(call
->conn
, call
->pkt
.u
.request
.context_id
);
996 if (context
== NULL
) {
997 return dcesrv_fault(call
, DCERPC_FAULT_UNK_IF
);
1000 pull
= ndr_pull_init_blob(&call
->pkt
.u
.request
.stub_and_verifier
, call
);
1001 NT_STATUS_HAVE_NO_MEMORY(pull
);
1003 pull
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
1005 call
->context
= context
;
1006 call
->ndr_pull
= pull
;
1008 if (!(call
->pkt
.drep
[0] & DCERPC_DREP_LE
)) {
1009 pull
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
1012 status
= dcesrv_check_verification_trailer(call
);
1013 if (!NT_STATUS_IS_OK(status
)) {
1014 uint32_t faultcode
= DCERPC_FAULT_OTHER
;
1015 if (NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
1016 faultcode
= DCERPC_FAULT_ACCESS_DENIED
;
1018 DEBUG(10, ("dcesrv_check_verification_trailer failed: %s\n",
1019 nt_errstr(status
)));
1020 return dcesrv_fault(call
, faultcode
);
1023 /* unravel the NDR for the packet */
1024 status
= context
->iface
->ndr_pull(call
, call
, pull
, &call
->r
);
1025 if (!NT_STATUS_IS_OK(status
)) {
1026 if (call
->fault_code
== DCERPC_FAULT_OP_RNG_ERROR
) {
1027 /* we got an unknown call */
1028 DEBUG(3,(__location__
": Unknown RPC call %u on %s\n",
1029 call
->pkt
.u
.request
.opnum
, context
->iface
->name
));
1030 dcesrv_save_call(call
, "unknown");
1032 dcesrv_save_call(call
, "pullfail");
1034 return dcesrv_fault(call
, call
->fault_code
);
1037 if (pull
->offset
!= pull
->data_size
) {
1038 dcesrv_save_call(call
, "extrabytes");
1039 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
1040 pull
->data_size
- pull
->offset
));
1043 /* call the dispatch function */
1044 status
= context
->iface
->dispatch(call
, call
, call
->r
);
1045 if (!NT_STATUS_IS_OK(status
)) {
1046 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
1047 context
->iface
->name
,
1048 call
->pkt
.u
.request
.opnum
,
1049 dcerpc_errstr(pull
, call
->fault_code
)));
1050 return dcesrv_fault(call
, call
->fault_code
);
1053 /* add the call to the pending list */
1054 dcesrv_call_set_list(call
, DCESRV_LIST_PENDING_CALL_LIST
);
1056 if (call
->state_flags
& DCESRV_CALL_STATE_FLAG_ASYNC
) {
1057 return NT_STATUS_OK
;
1060 return dcesrv_reply(call
);
1065 remove the call from the right list when freed
1067 static int dcesrv_call_dequeue(struct dcesrv_call_state
*call
)
1069 dcesrv_call_set_list(call
, DCESRV_LIST_NONE
);
1073 _PUBLIC_
const struct tsocket_address
*dcesrv_connection_get_local_address(struct dcesrv_connection
*conn
)
1075 return conn
->local_address
;
1078 _PUBLIC_
const struct tsocket_address
*dcesrv_connection_get_remote_address(struct dcesrv_connection
*conn
)
1080 return conn
->remote_address
;
1084 process some input to a dcerpc endpoint server.
1086 NTSTATUS
dcesrv_process_ncacn_packet(struct dcesrv_connection
*dce_conn
,
1087 struct ncacn_packet
*pkt
,
1091 struct dcesrv_call_state
*call
;
1093 call
= talloc_zero(dce_conn
, struct dcesrv_call_state
);
1095 data_blob_free(&blob
);
1097 return NT_STATUS_NO_MEMORY
;
1099 call
->conn
= dce_conn
;
1100 call
->event_ctx
= dce_conn
->event_ctx
;
1101 call
->msg_ctx
= dce_conn
->msg_ctx
;
1102 call
->state_flags
= call
->conn
->state_flags
;
1103 call
->time
= timeval_current();
1104 call
->list
= DCESRV_LIST_NONE
;
1106 talloc_steal(call
, pkt
);
1107 talloc_steal(call
, blob
.data
);
1110 talloc_set_destructor(call
, dcesrv_call_dequeue
);
1112 /* we have to check the signing here, before combining the
1114 if (call
->pkt
.ptype
== DCERPC_PKT_REQUEST
&&
1115 !dcesrv_auth_request(call
, &blob
)) {
1116 return dcesrv_fault(call
, DCERPC_FAULT_ACCESS_DENIED
);
1119 /* see if this is a continued packet */
1120 if (call
->pkt
.ptype
== DCERPC_PKT_REQUEST
&&
1121 !(call
->pkt
.pfc_flags
& DCERPC_PFC_FLAG_FIRST
)) {
1122 struct dcesrv_call_state
*call2
= call
;
1123 uint32_t alloc_size
;
1125 /* we only allow fragmented requests, no other packet types */
1126 if (call
->pkt
.ptype
!= DCERPC_PKT_REQUEST
) {
1127 return dcesrv_fault(call2
, DCERPC_FAULT_OTHER
);
1130 /* this is a continuation of an existing call - find the call
1131 then tack it on the end */
1132 call
= dcesrv_find_fragmented_call(dce_conn
, call2
->pkt
.call_id
);
1134 return dcesrv_fault(call2
, DCERPC_FAULT_OTHER
);
1137 if (call
->pkt
.ptype
!= call2
->pkt
.ptype
) {
1138 /* trying to play silly buggers are we? */
1139 return dcesrv_fault(call2
, DCERPC_NCA_S_PROTO_ERROR
);
1141 if (memcmp(call
->pkt
.drep
, call2
->pkt
.drep
, sizeof(pkt
->drep
)) != 0) {
1142 return dcesrv_fault(call2
, DCERPC_NCA_S_PROTO_ERROR
);
1144 if (call
->pkt
.call_id
!= call2
->pkt
.call_id
) {
1145 return dcesrv_fault(call2
, DCERPC_NCA_S_PROTO_ERROR
);
1147 if (call
->pkt
.u
.request
.context_id
!= call2
->pkt
.u
.request
.context_id
) {
1148 return dcesrv_fault(call2
, DCERPC_NCA_S_PROTO_ERROR
);
1150 if (call
->pkt
.u
.request
.opnum
!= call2
->pkt
.u
.request
.opnum
) {
1151 return dcesrv_fault(call2
, DCERPC_NCA_S_PROTO_ERROR
);
1154 alloc_size
= call
->pkt
.u
.request
.stub_and_verifier
.length
+
1155 call2
->pkt
.u
.request
.stub_and_verifier
.length
;
1156 if (call
->pkt
.u
.request
.alloc_hint
> alloc_size
) {
1157 alloc_size
= call
->pkt
.u
.request
.alloc_hint
;
1160 call
->pkt
.u
.request
.stub_and_verifier
.data
=
1161 talloc_realloc(call
,
1162 call
->pkt
.u
.request
.stub_and_verifier
.data
,
1163 uint8_t, alloc_size
);
1164 if (!call
->pkt
.u
.request
.stub_and_verifier
.data
) {
1165 return dcesrv_fault(call2
, DCERPC_FAULT_OTHER
);
1167 memcpy(call
->pkt
.u
.request
.stub_and_verifier
.data
+
1168 call
->pkt
.u
.request
.stub_and_verifier
.length
,
1169 call2
->pkt
.u
.request
.stub_and_verifier
.data
,
1170 call2
->pkt
.u
.request
.stub_and_verifier
.length
);
1171 call
->pkt
.u
.request
.stub_and_verifier
.length
+=
1172 call2
->pkt
.u
.request
.stub_and_verifier
.length
;
1174 call
->pkt
.pfc_flags
|= (call2
->pkt
.pfc_flags
& DCERPC_PFC_FLAG_LAST
);
1179 /* this may not be the last pdu in the chain - if its isn't then
1180 just put it on the incoming_fragmented_call_list and wait for the rest */
1181 if (call
->pkt
.ptype
== DCERPC_PKT_REQUEST
&&
1182 !(call
->pkt
.pfc_flags
& DCERPC_PFC_FLAG_LAST
)) {
1183 dcesrv_call_set_list(call
, DCESRV_LIST_FRAGMENTED_CALL_LIST
);
1184 return NT_STATUS_OK
;
1187 /* This removes any fragments we may have had stashed away */
1188 dcesrv_call_set_list(call
, DCESRV_LIST_NONE
);
1190 switch (call
->pkt
.ptype
) {
1191 case DCERPC_PKT_BIND
:
1192 status
= dcesrv_bind(call
);
1194 case DCERPC_PKT_AUTH3
:
1195 status
= dcesrv_auth3(call
);
1197 case DCERPC_PKT_ALTER
:
1198 status
= dcesrv_alter(call
);
1200 case DCERPC_PKT_REQUEST
:
1201 status
= dcesrv_request(call
);
1204 status
= NT_STATUS_INVALID_PARAMETER
;
1208 /* if we are going to be sending a reply then add
1209 it to the list of pending calls. We add it to the end to keep the call
1210 list in the order we will answer */
1211 if (!NT_STATUS_IS_OK(status
)) {
1218 _PUBLIC_ NTSTATUS
dcesrv_init_context(TALLOC_CTX
*mem_ctx
,
1219 struct loadparm_context
*lp_ctx
,
1220 const char **endpoint_servers
, struct dcesrv_context
**_dce_ctx
)
1223 struct dcesrv_context
*dce_ctx
;
1226 if (!endpoint_servers
) {
1227 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1228 return NT_STATUS_INTERNAL_ERROR
;
1231 dce_ctx
= talloc(mem_ctx
, struct dcesrv_context
);
1232 NT_STATUS_HAVE_NO_MEMORY(dce_ctx
);
1234 if (uid_wrapper_enabled()) {
1235 setenv("UID_WRAPPER_MYUID", "1", 1);
1237 dce_ctx
->initial_euid
= geteuid();
1238 if (uid_wrapper_enabled()) {
1239 unsetenv("UID_WRAPPER_MYUID");
1242 dce_ctx
->endpoint_list
= NULL
;
1243 dce_ctx
->lp_ctx
= lp_ctx
;
1244 dce_ctx
->assoc_groups_idr
= idr_init(dce_ctx
);
1245 NT_STATUS_HAVE_NO_MEMORY(dce_ctx
->assoc_groups_idr
);
1246 dce_ctx
->broken_connections
= NULL
;
1248 for (i
=0;endpoint_servers
[i
];i
++) {
1249 const struct dcesrv_endpoint_server
*ep_server
;
1251 ep_server
= dcesrv_ep_server_byname(endpoint_servers
[i
]);
1253 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers
[i
]));
1254 return NT_STATUS_INTERNAL_ERROR
;
1257 status
= ep_server
->init_server(dce_ctx
, ep_server
);
1258 if (!NT_STATUS_IS_OK(status
)) {
1259 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers
[i
],
1260 nt_errstr(status
)));
1265 *_dce_ctx
= dce_ctx
;
1266 return NT_STATUS_OK
;
1269 /* the list of currently registered DCERPC endpoint servers.
1271 static struct ep_server
{
1272 struct dcesrv_endpoint_server
*ep_server
;
1273 } *ep_servers
= NULL
;
1274 static int num_ep_servers
;
1277 register a DCERPC endpoint server.
1279 The 'name' can be later used by other backends to find the operations
1280 structure for this backend.
1282 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1284 _PUBLIC_ NTSTATUS
dcerpc_register_ep_server(const void *_ep_server
)
1286 const struct dcesrv_endpoint_server
*ep_server
= _ep_server
;
1288 if (dcesrv_ep_server_byname(ep_server
->name
) != NULL
) {
1289 /* its already registered! */
1290 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1292 return NT_STATUS_OBJECT_NAME_COLLISION
;
1295 ep_servers
= realloc_p(ep_servers
, struct ep_server
, num_ep_servers
+1);
1297 smb_panic("out of memory in dcerpc_register");
1300 ep_servers
[num_ep_servers
].ep_server
= smb_xmemdup(ep_server
, sizeof(*ep_server
));
1301 ep_servers
[num_ep_servers
].ep_server
->name
= smb_xstrdup(ep_server
->name
);
1305 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1308 return NT_STATUS_OK
;
1312 return the operations structure for a named backend of the specified type
1314 const struct dcesrv_endpoint_server
*dcesrv_ep_server_byname(const char *name
)
1318 for (i
=0;i
<num_ep_servers
;i
++) {
1319 if (strcmp(ep_servers
[i
].ep_server
->name
, name
) == 0) {
1320 return ep_servers
[i
].ep_server
;
1327 void dcerpc_server_init(struct loadparm_context
*lp_ctx
)
1329 static bool initialized
;
1330 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
1331 STATIC_dcerpc_server_MODULES_PROTO
;
1332 init_module_fn static_init
[] = { STATIC_dcerpc_server_MODULES
};
1333 init_module_fn
*shared_init
;
1340 shared_init
= load_samba_modules(NULL
, "dcerpc_server");
1342 run_init_functions(static_init
);
1343 run_init_functions(shared_init
);
1345 talloc_free(shared_init
);
1349 return the DCERPC module version, and the size of some critical types
1350 This can be used by endpoint server modules to either detect compilation errors, or provide
1351 multiple implementations for different smbd compilation options in one module
1353 const struct dcesrv_critical_sizes
*dcerpc_module_version(void)
1355 static const struct dcesrv_critical_sizes critical_sizes
= {
1356 DCERPC_MODULE_VERSION
,
1357 sizeof(struct dcesrv_context
),
1358 sizeof(struct dcesrv_endpoint
),
1359 sizeof(struct dcesrv_endpoint_server
),
1360 sizeof(struct dcesrv_interface
),
1361 sizeof(struct dcesrv_if_list
),
1362 sizeof(struct dcesrv_connection
),
1363 sizeof(struct dcesrv_call_state
),
1364 sizeof(struct dcesrv_auth
),
1365 sizeof(struct dcesrv_handle
)
1368 return &critical_sizes
;
1371 static void dcesrv_terminate_connection(struct dcesrv_connection
*dce_conn
, const char *reason
)
1373 struct dcesrv_context
*dce_ctx
= dce_conn
->dce_ctx
;
1374 struct stream_connection
*srv_conn
;
1375 srv_conn
= talloc_get_type(dce_conn
->transport
.private_data
,
1376 struct stream_connection
);
1378 if (dce_conn
->pending_call_list
== NULL
) {
1379 char *full_reason
= talloc_asprintf(dce_conn
, "dcesrv: %s", reason
);
1381 DLIST_REMOVE(dce_ctx
->broken_connections
, dce_conn
);
1382 stream_terminate_connection(srv_conn
, full_reason
? full_reason
: reason
);
1386 if (dce_conn
->terminate
!= NULL
) {
1390 DEBUG(3,("dcesrv: terminating connection due to '%s' defered due to pending calls\n",
1392 dce_conn
->terminate
= talloc_strdup(dce_conn
, reason
);
1393 if (dce_conn
->terminate
== NULL
) {
1394 dce_conn
->terminate
= "dcesrv: defered terminating connection - no memory";
1396 DLIST_ADD_END(dce_ctx
->broken_connections
, dce_conn
, NULL
);
1399 static void dcesrv_cleanup_broken_connections(struct dcesrv_context
*dce_ctx
)
1401 struct dcesrv_connection
*cur
, *next
;
1403 next
= dce_ctx
->broken_connections
;
1404 while (next
!= NULL
) {
1408 if (cur
->state_flags
& DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL
) {
1409 struct dcesrv_connection_context
*context_cur
, *context_next
;
1411 context_next
= cur
->contexts
;
1412 while (context_next
!= NULL
) {
1413 context_cur
= context_next
;
1414 context_next
= context_cur
->next
;
1416 dcesrv_connection_context_destructor(context_cur
);
1420 dcesrv_terminate_connection(cur
, cur
->terminate
);
1424 /* We need this include to be able to compile on some plateforms
1425 * (ie. freebsd 7.2) as it seems that <sys/uio.h> is not included
1427 * It has to be that deep because otherwise we have a conflict on
1428 * const struct dcesrv_interface declaration.
1429 * This is mostly due to socket_wrapper defining #define bind swrap_bind
1430 * which conflict with the bind used before.
1432 #include "system/network.h"
1434 struct dcesrv_sock_reply_state
{
1435 struct dcesrv_connection
*dce_conn
;
1436 struct dcesrv_call_state
*call
;
1440 static void dcesrv_sock_reply_done(struct tevent_req
*subreq
);
1442 static void dcesrv_sock_report_output_data(struct dcesrv_connection
*dce_conn
)
1444 struct dcesrv_call_state
*call
;
1446 call
= dce_conn
->call_list
;
1447 if (!call
|| !call
->replies
) {
1451 while (call
->replies
) {
1452 struct data_blob_list_item
*rep
= call
->replies
;
1453 struct dcesrv_sock_reply_state
*substate
;
1454 struct tevent_req
*subreq
;
1456 substate
= talloc(call
, struct dcesrv_sock_reply_state
);
1458 dcesrv_terminate_connection(dce_conn
, "no memory");
1462 substate
->dce_conn
= dce_conn
;
1463 substate
->call
= NULL
;
1465 DLIST_REMOVE(call
->replies
, rep
);
1467 if (call
->replies
== NULL
) {
1468 substate
->call
= call
;
1471 substate
->iov
.iov_base
= (void *) rep
->blob
.data
;
1472 substate
->iov
.iov_len
= rep
->blob
.length
;
1474 subreq
= tstream_writev_queue_send(substate
,
1475 dce_conn
->event_ctx
,
1477 dce_conn
->send_queue
,
1480 dcesrv_terminate_connection(dce_conn
, "no memory");
1483 tevent_req_set_callback(subreq
, dcesrv_sock_reply_done
,
1487 DLIST_REMOVE(call
->conn
->call_list
, call
);
1488 call
->list
= DCESRV_LIST_NONE
;
1491 static void dcesrv_sock_reply_done(struct tevent_req
*subreq
)
1493 struct dcesrv_sock_reply_state
*substate
= tevent_req_callback_data(subreq
,
1494 struct dcesrv_sock_reply_state
);
1498 struct dcesrv_call_state
*call
= substate
->call
;
1500 ret
= tstream_writev_queue_recv(subreq
, &sys_errno
);
1501 TALLOC_FREE(subreq
);
1503 status
= map_nt_error_from_unix_common(sys_errno
);
1504 dcesrv_terminate_connection(substate
->dce_conn
, nt_errstr(status
));
1508 talloc_free(substate
);
1517 struct dcesrv_socket_context
{
1518 const struct dcesrv_endpoint
*endpoint
;
1519 struct dcesrv_context
*dcesrv_ctx
;
1523 static void dcesrv_read_fragment_done(struct tevent_req
*subreq
);
1525 static void dcesrv_sock_accept(struct stream_connection
*srv_conn
)
1528 struct dcesrv_socket_context
*dcesrv_sock
=
1529 talloc_get_type(srv_conn
->private_data
, struct dcesrv_socket_context
);
1530 enum dcerpc_transport_t transport
=
1531 dcerpc_binding_get_transport(dcesrv_sock
->endpoint
->ep_description
);
1532 struct dcesrv_connection
*dcesrv_conn
= NULL
;
1534 struct tevent_req
*subreq
;
1535 struct loadparm_context
*lp_ctx
= dcesrv_sock
->dcesrv_ctx
->lp_ctx
;
1537 dcesrv_cleanup_broken_connections(dcesrv_sock
->dcesrv_ctx
);
1539 if (!srv_conn
->session_info
) {
1540 status
= auth_anonymous_session_info(srv_conn
,
1542 &srv_conn
->session_info
);
1543 if (!NT_STATUS_IS_OK(status
)) {
1544 DEBUG(0,("dcesrv_sock_accept: auth_anonymous_session_info failed: %s\n",
1545 nt_errstr(status
)));
1546 stream_terminate_connection(srv_conn
, nt_errstr(status
));
1551 status
= dcesrv_endpoint_connect(dcesrv_sock
->dcesrv_ctx
,
1553 dcesrv_sock
->endpoint
,
1554 srv_conn
->session_info
,
1555 srv_conn
->event
.ctx
,
1557 srv_conn
->server_id
,
1558 DCESRV_CALL_STATE_FLAG_MAY_ASYNC
,
1560 if (!NT_STATUS_IS_OK(status
)) {
1561 DEBUG(0,("dcesrv_sock_accept: dcesrv_endpoint_connect failed: %s\n",
1562 nt_errstr(status
)));
1563 stream_terminate_connection(srv_conn
, nt_errstr(status
));
1567 dcesrv_conn
->transport
.private_data
= srv_conn
;
1568 dcesrv_conn
->transport
.report_output_data
= dcesrv_sock_report_output_data
;
1570 TALLOC_FREE(srv_conn
->event
.fde
);
1572 dcesrv_conn
->send_queue
= tevent_queue_create(dcesrv_conn
, "dcesrv send queue");
1573 if (!dcesrv_conn
->send_queue
) {
1574 status
= NT_STATUS_NO_MEMORY
;
1575 DEBUG(0,("dcesrv_sock_accept: tevent_queue_create(%s)\n",
1576 nt_errstr(status
)));
1577 stream_terminate_connection(srv_conn
, nt_errstr(status
));
1581 if (transport
== NCACN_NP
) {
1582 dcesrv_conn
->auth_state
.session_key
= dcesrv_inherited_session_key
;
1583 dcesrv_conn
->stream
= talloc_move(dcesrv_conn
,
1584 &srv_conn
->tstream
);
1586 ret
= tstream_bsd_existing_socket(dcesrv_conn
,
1587 socket_get_fd(srv_conn
->socket
),
1588 &dcesrv_conn
->stream
);
1590 status
= map_nt_error_from_unix_common(errno
);
1591 DEBUG(0, ("dcesrv_sock_accept: "
1592 "failed to setup tstream: %s\n",
1593 nt_errstr(status
)));
1594 stream_terminate_connection(srv_conn
, nt_errstr(status
));
1597 socket_set_flags(srv_conn
->socket
, SOCKET_FLAG_NOCLOSE
);
1600 dcesrv_conn
->local_address
= srv_conn
->local_address
;
1601 dcesrv_conn
->remote_address
= srv_conn
->remote_address
;
1603 if (transport
== NCALRPC
) {
1607 ret
= getpeereid(socket_get_fd(srv_conn
->socket
), &uid
, &gid
);
1609 status
= map_nt_error_from_unix_common(errno
);
1610 DEBUG(0, ("dcesrv_sock_accept: "
1611 "getpeereid() failed for NCALRPC: %s\n",
1612 nt_errstr(status
)));
1613 stream_terminate_connection(srv_conn
, nt_errstr(status
));
1616 if (uid
== dcesrv_conn
->dce_ctx
->initial_euid
) {
1617 struct tsocket_address
*r
= NULL
;
1619 ret
= tsocket_address_unix_from_path(dcesrv_conn
,
1620 "/root/ncalrpc_as_system",
1623 status
= map_nt_error_from_unix_common(errno
);
1624 DEBUG(0, ("dcesrv_sock_accept: "
1625 "tsocket_address_unix_from_path() failed for NCALRPC: %s\n",
1626 nt_errstr(status
)));
1627 stream_terminate_connection(srv_conn
, nt_errstr(status
));
1630 dcesrv_conn
->remote_address
= r
;
1634 srv_conn
->private_data
= dcesrv_conn
;
1636 irpc_add_name(srv_conn
->msg_ctx
, "rpc_server");
1638 subreq
= dcerpc_read_ncacn_packet_send(dcesrv_conn
,
1639 dcesrv_conn
->event_ctx
,
1640 dcesrv_conn
->stream
);
1642 status
= NT_STATUS_NO_MEMORY
;
1643 DEBUG(0,("dcesrv_sock_accept: dcerpc_read_fragment_buffer_send(%s)\n",
1644 nt_errstr(status
)));
1645 stream_terminate_connection(srv_conn
, nt_errstr(status
));
1648 tevent_req_set_callback(subreq
, dcesrv_read_fragment_done
, dcesrv_conn
);
1653 static void dcesrv_read_fragment_done(struct tevent_req
*subreq
)
1655 struct dcesrv_connection
*dce_conn
= tevent_req_callback_data(subreq
,
1656 struct dcesrv_connection
);
1657 struct dcesrv_context
*dce_ctx
= dce_conn
->dce_ctx
;
1658 struct ncacn_packet
*pkt
;
1662 if (dce_conn
->terminate
) {
1664 * if the current connection is broken
1665 * we need to clean it up before any other connection
1667 dcesrv_terminate_connection(dce_conn
, dce_conn
->terminate
);
1668 dcesrv_cleanup_broken_connections(dce_ctx
);
1672 dcesrv_cleanup_broken_connections(dce_ctx
);
1674 status
= dcerpc_read_ncacn_packet_recv(subreq
, dce_conn
,
1676 TALLOC_FREE(subreq
);
1677 if (!NT_STATUS_IS_OK(status
)) {
1678 dcesrv_terminate_connection(dce_conn
, nt_errstr(status
));
1682 status
= dcesrv_process_ncacn_packet(dce_conn
, pkt
, buffer
);
1683 if (!NT_STATUS_IS_OK(status
)) {
1684 dcesrv_terminate_connection(dce_conn
, nt_errstr(status
));
1688 subreq
= dcerpc_read_ncacn_packet_send(dce_conn
,
1689 dce_conn
->event_ctx
,
1692 status
= NT_STATUS_NO_MEMORY
;
1693 dcesrv_terminate_connection(dce_conn
, nt_errstr(status
));
1696 tevent_req_set_callback(subreq
, dcesrv_read_fragment_done
, dce_conn
);
1699 static void dcesrv_sock_recv(struct stream_connection
*conn
, uint16_t flags
)
1701 struct dcesrv_connection
*dce_conn
= talloc_get_type(conn
->private_data
,
1702 struct dcesrv_connection
);
1703 dcesrv_terminate_connection(dce_conn
, "dcesrv_sock_recv triggered");
1706 static void dcesrv_sock_send(struct stream_connection
*conn
, uint16_t flags
)
1708 struct dcesrv_connection
*dce_conn
= talloc_get_type(conn
->private_data
,
1709 struct dcesrv_connection
);
1710 dcesrv_terminate_connection(dce_conn
, "dcesrv_sock_send triggered");
1714 static const struct stream_server_ops dcesrv_stream_ops
= {
1716 .accept_connection
= dcesrv_sock_accept
,
1717 .recv_handler
= dcesrv_sock_recv
,
1718 .send_handler
= dcesrv_sock_send
,
1721 static NTSTATUS
dcesrv_add_ep_unix(struct dcesrv_context
*dce_ctx
,
1722 struct loadparm_context
*lp_ctx
,
1723 struct dcesrv_endpoint
*e
,
1724 struct tevent_context
*event_ctx
, const struct model_ops
*model_ops
)
1726 struct dcesrv_socket_context
*dcesrv_sock
;
1729 const char *endpoint
;
1731 dcesrv_sock
= talloc(event_ctx
, struct dcesrv_socket_context
);
1732 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock
);
1734 /* remember the endpoint of this socket */
1735 dcesrv_sock
->endpoint
= e
;
1736 dcesrv_sock
->dcesrv_ctx
= talloc_reference(dcesrv_sock
, dce_ctx
);
1738 endpoint
= dcerpc_binding_get_string_option(e
->ep_description
, "endpoint");
1740 status
= stream_setup_socket(dcesrv_sock
, event_ctx
, lp_ctx
,
1741 model_ops
, &dcesrv_stream_ops
,
1742 "unix", endpoint
, &port
,
1743 lpcfg_socket_options(lp_ctx
),
1745 if (!NT_STATUS_IS_OK(status
)) {
1746 DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n",
1747 endpoint
, nt_errstr(status
)));
1753 static NTSTATUS
dcesrv_add_ep_ncalrpc(struct dcesrv_context
*dce_ctx
,
1754 struct loadparm_context
*lp_ctx
,
1755 struct dcesrv_endpoint
*e
,
1756 struct tevent_context
*event_ctx
, const struct model_ops
*model_ops
)
1758 struct dcesrv_socket_context
*dcesrv_sock
;
1762 const char *endpoint
;
1764 endpoint
= dcerpc_binding_get_string_option(e
->ep_description
, "endpoint");
1766 if (endpoint
== NULL
) {
1768 * No identifier specified: use DEFAULT.
1770 * TODO: DO NOT hardcode this value anywhere else. Rather, specify
1771 * no endpoint and let the epmapper worry about it.
1773 endpoint
= "DEFAULT";
1774 status
= dcerpc_binding_set_string_option(e
->ep_description
,
1777 if (!NT_STATUS_IS_OK(status
)) {
1778 DEBUG(0,("dcerpc_binding_set_string_option() failed - %s\n",
1779 nt_errstr(status
)));
1784 full_path
= talloc_asprintf(dce_ctx
, "%s/%s", lpcfg_ncalrpc_dir(lp_ctx
),
1787 dcesrv_sock
= talloc(event_ctx
, struct dcesrv_socket_context
);
1788 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock
);
1790 /* remember the endpoint of this socket */
1791 dcesrv_sock
->endpoint
= e
;
1792 dcesrv_sock
->dcesrv_ctx
= talloc_reference(dcesrv_sock
, dce_ctx
);
1794 status
= stream_setup_socket(dcesrv_sock
, event_ctx
, lp_ctx
,
1795 model_ops
, &dcesrv_stream_ops
,
1796 "unix", full_path
, &port
,
1797 lpcfg_socket_options(lp_ctx
),
1799 if (!NT_STATUS_IS_OK(status
)) {
1800 DEBUG(0,("service_setup_stream_socket(identifier=%s,path=%s) failed - %s\n",
1801 endpoint
, full_path
, nt_errstr(status
)));
1806 static NTSTATUS
dcesrv_add_ep_np(struct dcesrv_context
*dce_ctx
,
1807 struct loadparm_context
*lp_ctx
,
1808 struct dcesrv_endpoint
*e
,
1809 struct tevent_context
*event_ctx
, const struct model_ops
*model_ops
)
1811 struct dcesrv_socket_context
*dcesrv_sock
;
1813 const char *endpoint
;
1815 endpoint
= dcerpc_binding_get_string_option(e
->ep_description
, "endpoint");
1816 if (endpoint
== NULL
) {
1817 DEBUG(0, ("Endpoint mandatory for named pipes\n"));
1818 return NT_STATUS_INVALID_PARAMETER
;
1821 dcesrv_sock
= talloc(event_ctx
, struct dcesrv_socket_context
);
1822 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock
);
1824 /* remember the endpoint of this socket */
1825 dcesrv_sock
->endpoint
= e
;
1826 dcesrv_sock
->dcesrv_ctx
= talloc_reference(dcesrv_sock
, dce_ctx
);
1828 status
= tstream_setup_named_pipe(dce_ctx
, event_ctx
, lp_ctx
,
1829 model_ops
, &dcesrv_stream_ops
,
1832 if (!NT_STATUS_IS_OK(status
)) {
1833 DEBUG(0,("stream_setup_named_pipe(pipe=%s) failed - %s\n",
1834 endpoint
, nt_errstr(status
)));
1838 return NT_STATUS_OK
;
1842 add a socket address to the list of events, one event per dcerpc endpoint
1844 static NTSTATUS
add_socket_rpc_tcp_iface(struct dcesrv_context
*dce_ctx
, struct dcesrv_endpoint
*e
,
1845 struct tevent_context
*event_ctx
, const struct model_ops
*model_ops
,
1846 const char *address
)
1848 struct dcesrv_socket_context
*dcesrv_sock
;
1851 const char *endpoint
;
1854 endpoint
= dcerpc_binding_get_string_option(e
->ep_description
, "endpoint");
1855 if (endpoint
!= NULL
) {
1856 port
= atoi(endpoint
);
1859 dcesrv_sock
= talloc(event_ctx
, struct dcesrv_socket_context
);
1860 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock
);
1862 /* remember the endpoint of this socket */
1863 dcesrv_sock
->endpoint
= e
;
1864 dcesrv_sock
->dcesrv_ctx
= talloc_reference(dcesrv_sock
, dce_ctx
);
1866 status
= stream_setup_socket(dcesrv_sock
, event_ctx
, dce_ctx
->lp_ctx
,
1867 model_ops
, &dcesrv_stream_ops
,
1868 "ip", address
, &port
,
1869 lpcfg_socket_options(dce_ctx
->lp_ctx
),
1871 if (!NT_STATUS_IS_OK(status
)) {
1872 DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) failed - %s\n",
1873 address
, port
, nt_errstr(status
)));
1877 snprintf(port_str
, sizeof(port_str
), "%u", port
);
1879 status
= dcerpc_binding_set_string_option(e
->ep_description
,
1880 "endpoint", port_str
);
1881 if (!NT_STATUS_IS_OK(status
)) {
1882 DEBUG(0,("dcerpc_binding_set_string_option(endpoint, %s) failed - %s\n",
1883 port_str
, nt_errstr(status
)));
1887 return NT_STATUS_OK
;
1890 #include "lib/socket/netif.h" /* Included here to work around the fact that socket_wrapper redefines bind() */
1892 static NTSTATUS
dcesrv_add_ep_tcp(struct dcesrv_context
*dce_ctx
,
1893 struct loadparm_context
*lp_ctx
,
1894 struct dcesrv_endpoint
*e
,
1895 struct tevent_context
*event_ctx
, const struct model_ops
*model_ops
)
1899 /* Add TCP/IP sockets */
1900 if (lpcfg_interfaces(lp_ctx
) && lpcfg_bind_interfaces_only(lp_ctx
)) {
1903 struct interface
*ifaces
;
1905 load_interface_list(dce_ctx
, lp_ctx
, &ifaces
);
1907 num_interfaces
= iface_list_count(ifaces
);
1908 for(i
= 0; i
< num_interfaces
; i
++) {
1909 const char *address
= iface_list_n_ip(ifaces
, i
);
1910 status
= add_socket_rpc_tcp_iface(dce_ctx
, e
, event_ctx
, model_ops
, address
);
1911 NT_STATUS_NOT_OK_RETURN(status
);
1917 wcard
= iface_list_wildcard(dce_ctx
);
1918 NT_STATUS_HAVE_NO_MEMORY(wcard
);
1919 for (i
=0; wcard
[i
]; i
++) {
1920 status
= add_socket_rpc_tcp_iface(dce_ctx
, e
, event_ctx
, model_ops
, wcard
[i
]);
1921 if (NT_STATUS_IS_OK(status
)) {
1926 if (num_binds
== 0) {
1927 return NT_STATUS_INVALID_PARAMETER_MIX
;
1931 return NT_STATUS_OK
;
1934 NTSTATUS
dcesrv_add_ep(struct dcesrv_context
*dce_ctx
,
1935 struct loadparm_context
*lp_ctx
,
1936 struct dcesrv_endpoint
*e
,
1937 struct tevent_context
*event_ctx
,
1938 const struct model_ops
*model_ops
)
1940 enum dcerpc_transport_t transport
=
1941 dcerpc_binding_get_transport(e
->ep_description
);
1943 switch (transport
) {
1944 case NCACN_UNIX_STREAM
:
1945 return dcesrv_add_ep_unix(dce_ctx
, lp_ctx
, e
, event_ctx
, model_ops
);
1948 return dcesrv_add_ep_ncalrpc(dce_ctx
, lp_ctx
, e
, event_ctx
, model_ops
);
1951 return dcesrv_add_ep_tcp(dce_ctx
, lp_ctx
, e
, event_ctx
, model_ops
);
1954 return dcesrv_add_ep_np(dce_ctx
, lp_ctx
, e
, event_ctx
, model_ops
);
1957 return NT_STATUS_NOT_SUPPORTED
;
1963 * retrieve credentials from a dce_call
1965 _PUBLIC_
struct cli_credentials
*dcesrv_call_credentials(struct dcesrv_call_state
*dce_call
)
1967 return dce_call
->conn
->auth_state
.session_info
->credentials
;
1971 * returns true if this is an authenticated call
1973 _PUBLIC_
bool dcesrv_call_authenticated(struct dcesrv_call_state
*dce_call
)
1975 enum security_user_level level
;
1976 level
= security_session_user_level(dce_call
->conn
->auth_state
.session_info
, NULL
);
1977 return level
>= SECURITY_USER
;
1981 * retrieve account_name for a dce_call
1983 _PUBLIC_
const char *dcesrv_call_account_name(struct dcesrv_call_state
*dce_call
)
1985 return dce_call
->context
->conn
->auth_state
.session_info
->info
->account_name
;