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
);
513 handle a bind request
515 static NTSTATUS
dcesrv_bind(struct dcesrv_call_state
*call
)
517 uint32_t if_version
, transfer_syntax_version
;
518 struct GUID uuid
, *transfer_syntax_uuid
;
519 struct ncacn_packet pkt
;
520 struct data_blob_list_item
*rep
;
522 uint32_t result
=0, reason
=0;
524 const struct dcesrv_interface
*iface
;
525 uint32_t extra_flags
= 0;
528 if provided, check the assoc_group is valid
530 if (call
->pkt
.u
.bind
.assoc_group_id
!= 0 &&
531 lpcfg_parm_bool(call
->conn
->dce_ctx
->lp_ctx
, NULL
, "dcesrv","assoc group checking", true) &&
532 dcesrv_assoc_group_find(call
->conn
->dce_ctx
, call
->pkt
.u
.bind
.assoc_group_id
) == NULL
) {
533 return dcesrv_bind_nak(call
, 0);
536 if (call
->pkt
.u
.bind
.num_contexts
< 1 ||
537 call
->pkt
.u
.bind
.ctx_list
[0].num_transfer_syntaxes
< 1) {
538 return dcesrv_bind_nak(call
, 0);
541 context_id
= call
->pkt
.u
.bind
.ctx_list
[0].context_id
;
543 /* you can't bind twice on one context */
544 if (dcesrv_find_context(call
->conn
, context_id
) != NULL
) {
545 return dcesrv_bind_nak(call
, 0);
548 if_version
= call
->pkt
.u
.bind
.ctx_list
[0].abstract_syntax
.if_version
;
549 uuid
= call
->pkt
.u
.bind
.ctx_list
[0].abstract_syntax
.uuid
;
551 transfer_syntax_version
= call
->pkt
.u
.bind
.ctx_list
[0].transfer_syntaxes
[0].if_version
;
552 transfer_syntax_uuid
= &call
->pkt
.u
.bind
.ctx_list
[0].transfer_syntaxes
[0].uuid
;
553 if (!GUID_equal(&ndr_transfer_syntax_ndr
.uuid
, transfer_syntax_uuid
) != 0 ||
554 ndr_transfer_syntax_ndr
.if_version
!= transfer_syntax_version
) {
555 char *uuid_str
= GUID_string(call
, transfer_syntax_uuid
);
556 /* we only do NDR encoded dcerpc */
557 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str
));
558 talloc_free(uuid_str
);
559 return dcesrv_bind_nak(call
, 0);
562 iface
= find_interface_by_uuid(call
->conn
->endpoint
, &uuid
, if_version
);
564 char *uuid_str
= GUID_string(call
, &uuid
);
565 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str
, if_version
));
566 talloc_free(uuid_str
);
568 /* we don't know about that interface */
569 result
= DCERPC_BIND_PROVIDER_REJECT
;
570 reason
= DCERPC_BIND_REASON_ASYNTAX
;
574 /* add this context to the list of available context_ids */
575 struct dcesrv_connection_context
*context
= talloc(call
->conn
,
576 struct dcesrv_connection_context
);
577 if (context
== NULL
) {
578 return dcesrv_bind_nak(call
, 0);
580 context
->conn
= call
->conn
;
581 context
->iface
= iface
;
582 context
->context_id
= context_id
;
583 if (call
->pkt
.u
.bind
.assoc_group_id
!= 0) {
584 context
->assoc_group
= dcesrv_assoc_group_reference(context
,
586 call
->pkt
.u
.bind
.assoc_group_id
);
588 context
->assoc_group
= dcesrv_assoc_group_new(context
, call
->conn
->dce_ctx
);
590 if (context
->assoc_group
== NULL
) {
591 talloc_free(context
);
592 return dcesrv_bind_nak(call
, 0);
594 context
->private_data
= NULL
;
595 DLIST_ADD(call
->conn
->contexts
, context
);
596 call
->context
= context
;
597 talloc_set_destructor(context
, dcesrv_connection_context_destructor
);
599 status
= iface
->bind(call
, iface
, if_version
);
600 if (!NT_STATUS_IS_OK(status
)) {
601 char *uuid_str
= GUID_string(call
, &uuid
);
602 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
603 uuid_str
, if_version
, nt_errstr(status
)));
604 talloc_free(uuid_str
);
605 /* we don't want to trigger the iface->unbind() hook */
606 context
->iface
= NULL
;
607 talloc_free(call
->context
);
608 call
->context
= NULL
;
609 return dcesrv_bind_nak(call
, 0);
613 if (call
->conn
->cli_max_recv_frag
== 0) {
614 call
->conn
->cli_max_recv_frag
= MIN(0x2000, call
->pkt
.u
.bind
.max_recv_frag
);
617 /* handle any authentication that is being requested */
618 if (!dcesrv_auth_bind(call
)) {
619 talloc_free(call
->context
);
620 call
->context
= NULL
;
621 return dcesrv_bind_nak(call
, DCERPC_BIND_REASON_INVALID_AUTH_TYPE
);
624 /* setup a bind_ack */
625 dcesrv_init_hdr(&pkt
, lpcfg_rpc_big_endian(call
->conn
->dce_ctx
->lp_ctx
));
627 pkt
.call_id
= call
->pkt
.call_id
;
628 pkt
.ptype
= DCERPC_PKT_BIND_ACK
;
629 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
| extra_flags
;
630 pkt
.u
.bind_ack
.max_xmit_frag
= call
->conn
->cli_max_recv_frag
;
631 pkt
.u
.bind_ack
.max_recv_frag
= 0x2000;
634 make it possible for iface->bind() to specify the assoc_group_id
635 This helps the openchange mapiproxy plugin to work correctly.
640 pkt
.u
.bind_ack
.assoc_group_id
= call
->context
->assoc_group
->id
;
642 pkt
.u
.bind_ack
.assoc_group_id
= DUMMY_ASSOC_GROUP
;
646 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
647 pkt
.u
.bind_ack
.secondary_address
= talloc_asprintf(call
, "\\PIPE\\%s", iface
->name
);
649 pkt
.u
.bind_ack
.secondary_address
= "";
651 pkt
.u
.bind_ack
.num_results
= 1;
652 pkt
.u
.bind_ack
.ctx_list
= talloc(call
, struct dcerpc_ack_ctx
);
653 if (!pkt
.u
.bind_ack
.ctx_list
) {
654 talloc_free(call
->context
);
655 call
->context
= NULL
;
656 return NT_STATUS_NO_MEMORY
;
658 pkt
.u
.bind_ack
.ctx_list
[0].result
= result
;
659 pkt
.u
.bind_ack
.ctx_list
[0].reason
.value
= reason
;
660 pkt
.u
.bind_ack
.ctx_list
[0].syntax
= ndr_transfer_syntax_ndr
;
661 pkt
.u
.bind_ack
.auth_info
= data_blob(NULL
, 0);
663 status
= dcesrv_auth_bind_ack(call
, &pkt
);
664 if (!NT_STATUS_IS_OK(status
)) {
665 talloc_free(call
->context
);
666 call
->context
= NULL
;
667 return dcesrv_bind_nak(call
, 0);
670 rep
= talloc(call
, struct data_blob_list_item
);
672 talloc_free(call
->context
);
673 call
->context
= NULL
;
674 return NT_STATUS_NO_MEMORY
;
677 status
= ncacn_push_auth(&rep
->blob
, call
, &pkt
,
678 call
->conn
->auth_state
.auth_info
);
679 if (!NT_STATUS_IS_OK(status
)) {
680 talloc_free(call
->context
);
681 call
->context
= NULL
;
685 dcerpc_set_frag_length(&rep
->blob
, rep
->blob
.length
);
687 DLIST_ADD_END(call
->replies
, rep
, struct data_blob_list_item
*);
688 dcesrv_call_set_list(call
, DCESRV_LIST_CALL_LIST
);
690 if (call
->conn
->call_list
&& call
->conn
->call_list
->replies
) {
691 if (call
->conn
->transport
.report_output_data
) {
692 call
->conn
->transport
.report_output_data(call
->conn
);
701 handle a auth3 request
703 static NTSTATUS
dcesrv_auth3(struct dcesrv_call_state
*call
)
705 /* handle the auth3 in the auth code */
706 if (!dcesrv_auth_auth3(call
)) {
707 return dcesrv_fault(call
, DCERPC_FAULT_OTHER
);
712 /* we don't send a reply to a auth3 request, except by a
719 handle a bind request
721 static NTSTATUS
dcesrv_alter_new_context(struct dcesrv_call_state
*call
, uint32_t context_id
)
723 uint32_t if_version
, transfer_syntax_version
;
724 struct dcesrv_connection_context
*context
;
725 const struct dcesrv_interface
*iface
;
726 struct GUID uuid
, *transfer_syntax_uuid
;
729 if_version
= call
->pkt
.u
.alter
.ctx_list
[0].abstract_syntax
.if_version
;
730 uuid
= call
->pkt
.u
.alter
.ctx_list
[0].abstract_syntax
.uuid
;
732 transfer_syntax_version
= call
->pkt
.u
.alter
.ctx_list
[0].transfer_syntaxes
[0].if_version
;
733 transfer_syntax_uuid
= &call
->pkt
.u
.alter
.ctx_list
[0].transfer_syntaxes
[0].uuid
;
734 if (!GUID_equal(transfer_syntax_uuid
, &ndr_transfer_syntax_ndr
.uuid
) ||
735 ndr_transfer_syntax_ndr
.if_version
!= transfer_syntax_version
) {
736 /* we only do NDR encoded dcerpc */
737 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED
;
740 iface
= find_interface_by_uuid(call
->conn
->endpoint
, &uuid
, if_version
);
742 char *uuid_str
= GUID_string(call
, &uuid
);
743 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str
, if_version
));
744 talloc_free(uuid_str
);
745 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED
;
748 /* add this context to the list of available context_ids */
749 context
= talloc(call
->conn
, struct dcesrv_connection_context
);
750 if (context
== NULL
) {
751 return NT_STATUS_NO_MEMORY
;
753 context
->conn
= call
->conn
;
754 context
->iface
= iface
;
755 context
->context_id
= context_id
;
756 if (call
->pkt
.u
.alter
.assoc_group_id
!= 0) {
757 context
->assoc_group
= dcesrv_assoc_group_reference(context
,
759 call
->pkt
.u
.alter
.assoc_group_id
);
761 context
->assoc_group
= dcesrv_assoc_group_new(context
, call
->conn
->dce_ctx
);
763 if (context
->assoc_group
== NULL
) {
764 talloc_free(context
);
765 call
->context
= NULL
;
766 return NT_STATUS_NO_MEMORY
;
768 context
->private_data
= NULL
;
769 DLIST_ADD(call
->conn
->contexts
, context
);
770 call
->context
= context
;
771 talloc_set_destructor(context
, dcesrv_connection_context_destructor
);
773 status
= iface
->bind(call
, iface
, if_version
);
774 if (!NT_STATUS_IS_OK(status
)) {
775 /* we don't want to trigger the iface->unbind() hook */
776 context
->iface
= NULL
;
777 talloc_free(context
);
778 call
->context
= NULL
;
787 handle a alter context request
789 static NTSTATUS
dcesrv_alter(struct dcesrv_call_state
*call
)
791 struct ncacn_packet pkt
;
792 struct data_blob_list_item
*rep
;
794 uint32_t result
=0, reason
=0;
797 /* handle any authentication that is being requested */
798 if (!dcesrv_auth_alter(call
)) {
799 /* TODO: work out the right reject code */
800 result
= DCERPC_BIND_PROVIDER_REJECT
;
801 reason
= DCERPC_BIND_REASON_ASYNTAX
;
804 context_id
= call
->pkt
.u
.alter
.ctx_list
[0].context_id
;
806 /* see if they are asking for a new interface */
808 call
->context
= dcesrv_find_context(call
->conn
, context_id
);
809 if (!call
->context
) {
810 status
= dcesrv_alter_new_context(call
, context_id
);
811 if (!NT_STATUS_IS_OK(status
)) {
812 result
= DCERPC_BIND_PROVIDER_REJECT
;
813 reason
= DCERPC_BIND_REASON_ASYNTAX
;
819 call
->pkt
.u
.alter
.assoc_group_id
!= 0 &&
820 lpcfg_parm_bool(call
->conn
->dce_ctx
->lp_ctx
, NULL
, "dcesrv","assoc group checking", true) &&
821 call
->pkt
.u
.alter
.assoc_group_id
!= call
->context
->assoc_group
->id
) {
822 DEBUG(0,(__location__
": Failed attempt to use new assoc_group in alter context (0x%08x 0x%08x)\n",
823 call
->context
->assoc_group
->id
, call
->pkt
.u
.alter
.assoc_group_id
));
824 /* TODO: can they ask for a new association group? */
825 result
= DCERPC_BIND_PROVIDER_REJECT
;
826 reason
= DCERPC_BIND_REASON_ASYNTAX
;
829 /* setup a alter_resp */
830 dcesrv_init_hdr(&pkt
, lpcfg_rpc_big_endian(call
->conn
->dce_ctx
->lp_ctx
));
832 pkt
.call_id
= call
->pkt
.call_id
;
833 pkt
.ptype
= DCERPC_PKT_ALTER_RESP
;
834 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
835 pkt
.u
.alter_resp
.max_xmit_frag
= 0x2000;
836 pkt
.u
.alter_resp
.max_recv_frag
= 0x2000;
838 pkt
.u
.alter_resp
.assoc_group_id
= call
->context
->assoc_group
->id
;
840 pkt
.u
.alter_resp
.assoc_group_id
= 0;
842 pkt
.u
.alter_resp
.num_results
= 1;
843 pkt
.u
.alter_resp
.ctx_list
= talloc_array(call
, struct dcerpc_ack_ctx
, 1);
844 if (!pkt
.u
.alter_resp
.ctx_list
) {
845 return NT_STATUS_NO_MEMORY
;
847 pkt
.u
.alter_resp
.ctx_list
[0].result
= result
;
848 pkt
.u
.alter_resp
.ctx_list
[0].reason
.value
= reason
;
849 pkt
.u
.alter_resp
.ctx_list
[0].syntax
= ndr_transfer_syntax_ndr
;
850 pkt
.u
.alter_resp
.auth_info
= data_blob(NULL
, 0);
851 pkt
.u
.alter_resp
.secondary_address
= "";
853 status
= dcesrv_auth_alter_ack(call
, &pkt
);
854 if (!NT_STATUS_IS_OK(status
)) {
855 if (NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)
856 || NT_STATUS_EQUAL(status
, NT_STATUS_LOGON_FAILURE
)
857 || NT_STATUS_EQUAL(status
, NT_STATUS_NO_SUCH_USER
)
858 || NT_STATUS_EQUAL(status
, NT_STATUS_WRONG_PASSWORD
)) {
859 return dcesrv_fault(call
, DCERPC_FAULT_ACCESS_DENIED
);
861 return dcesrv_fault(call
, 0);
864 rep
= talloc(call
, struct data_blob_list_item
);
866 return NT_STATUS_NO_MEMORY
;
869 status
= ncacn_push_auth(&rep
->blob
, call
, &pkt
, call
->conn
->auth_state
.auth_info
);
870 if (!NT_STATUS_IS_OK(status
)) {
874 dcerpc_set_frag_length(&rep
->blob
, rep
->blob
.length
);
876 DLIST_ADD_END(call
->replies
, rep
, struct data_blob_list_item
*);
877 dcesrv_call_set_list(call
, DCESRV_LIST_CALL_LIST
);
879 if (call
->conn
->call_list
&& call
->conn
->call_list
->replies
) {
880 if (call
->conn
->transport
.report_output_data
) {
881 call
->conn
->transport
.report_output_data(call
->conn
);
889 possibly save the call for inspection with ndrdump
891 static void dcesrv_save_call(struct dcesrv_call_state
*call
, const char *why
)
895 const char *dump_dir
;
896 dump_dir
= lpcfg_parm_string(call
->conn
->dce_ctx
->lp_ctx
, NULL
, "dcesrv", "stubs directory");
900 fname
= talloc_asprintf(call
, "%s/RPC-%s-%u-%s.dat",
902 call
->context
->iface
->name
,
903 call
->pkt
.u
.request
.opnum
,
905 if (file_save(fname
, call
->pkt
.u
.request
.stub_and_verifier
.data
, call
->pkt
.u
.request
.stub_and_verifier
.length
)) {
906 DEBUG(0,("RPC SAVED %s\n", fname
));
912 static NTSTATUS
dcesrv_check_verification_trailer(struct dcesrv_call_state
*call
)
914 TALLOC_CTX
*frame
= talloc_stackframe();
915 const uint32_t bitmask1
= call
->conn
->auth_state
.client_hdr_signing
?
916 DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING
: 0;
917 const struct dcerpc_sec_vt_pcontext pcontext
= {
918 .abstract_syntax
= call
->context
->iface
->syntax_id
,
919 .transfer_syntax
= ndr_transfer_syntax_ndr
,
921 const struct dcerpc_sec_vt_header2 header2
=
922 dcerpc_sec_vt_header2_from_ncacn_packet(&call
->pkt
);
923 enum ndr_err_code ndr_err
;
924 struct dcerpc_sec_verification_trailer
*vt
= NULL
;
925 NTSTATUS status
= NT_STATUS_OK
;
928 SMB_ASSERT(call
->pkt
.ptype
== DCERPC_PKT_REQUEST
);
930 ndr_err
= ndr_pop_dcerpc_sec_verification_trailer(call
->ndr_pull
,
932 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
933 status
= ndr_map_error2ntstatus(ndr_err
);
937 ok
= dcerpc_sec_verification_trailer_check(vt
, &bitmask1
,
938 &pcontext
, &header2
);
940 status
= NT_STATUS_ACCESS_DENIED
;
949 handle a dcerpc request packet
951 static NTSTATUS
dcesrv_request(struct dcesrv_call_state
*call
)
953 struct ndr_pull
*pull
;
955 struct dcesrv_connection_context
*context
;
957 /* if authenticated, and the mech we use can't do async replies, don't use them... */
958 if (call
->conn
->auth_state
.gensec_security
&&
959 !gensec_have_feature(call
->conn
->auth_state
.gensec_security
, GENSEC_FEATURE_ASYNC_REPLIES
)) {
960 call
->state_flags
&= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC
;
963 context
= dcesrv_find_context(call
->conn
, call
->pkt
.u
.request
.context_id
);
964 if (context
== NULL
) {
965 return dcesrv_fault(call
, DCERPC_FAULT_UNK_IF
);
968 pull
= ndr_pull_init_blob(&call
->pkt
.u
.request
.stub_and_verifier
, call
);
969 NT_STATUS_HAVE_NO_MEMORY(pull
);
971 pull
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
973 call
->context
= context
;
974 call
->ndr_pull
= pull
;
976 if (!(call
->pkt
.drep
[0] & DCERPC_DREP_LE
)) {
977 pull
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
980 status
= dcesrv_check_verification_trailer(call
);
981 if (!NT_STATUS_IS_OK(status
)) {
982 uint32_t faultcode
= DCERPC_FAULT_OTHER
;
983 if (NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
984 faultcode
= DCERPC_FAULT_ACCESS_DENIED
;
986 DEBUG(10, ("dcesrv_check_verification_trailer failed: %s\n",
988 return dcesrv_fault(call
, faultcode
);
991 /* unravel the NDR for the packet */
992 status
= context
->iface
->ndr_pull(call
, call
, pull
, &call
->r
);
993 if (!NT_STATUS_IS_OK(status
)) {
994 if (call
->fault_code
== DCERPC_FAULT_OP_RNG_ERROR
) {
995 /* we got an unknown call */
996 DEBUG(3,(__location__
": Unknown RPC call %u on %s\n",
997 call
->pkt
.u
.request
.opnum
, context
->iface
->name
));
998 dcesrv_save_call(call
, "unknown");
1000 dcesrv_save_call(call
, "pullfail");
1002 return dcesrv_fault(call
, call
->fault_code
);
1005 if (pull
->offset
!= pull
->data_size
) {
1006 dcesrv_save_call(call
, "extrabytes");
1007 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
1008 pull
->data_size
- pull
->offset
));
1011 /* call the dispatch function */
1012 status
= context
->iface
->dispatch(call
, call
, call
->r
);
1013 if (!NT_STATUS_IS_OK(status
)) {
1014 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
1015 context
->iface
->name
,
1016 call
->pkt
.u
.request
.opnum
,
1017 dcerpc_errstr(pull
, call
->fault_code
)));
1018 return dcesrv_fault(call
, call
->fault_code
);
1021 /* add the call to the pending list */
1022 dcesrv_call_set_list(call
, DCESRV_LIST_PENDING_CALL_LIST
);
1024 if (call
->state_flags
& DCESRV_CALL_STATE_FLAG_ASYNC
) {
1025 return NT_STATUS_OK
;
1028 return dcesrv_reply(call
);
1033 remove the call from the right list when freed
1035 static int dcesrv_call_dequeue(struct dcesrv_call_state
*call
)
1037 dcesrv_call_set_list(call
, DCESRV_LIST_NONE
);
1041 _PUBLIC_
const struct tsocket_address
*dcesrv_connection_get_local_address(struct dcesrv_connection
*conn
)
1043 return conn
->local_address
;
1046 _PUBLIC_
const struct tsocket_address
*dcesrv_connection_get_remote_address(struct dcesrv_connection
*conn
)
1048 return conn
->remote_address
;
1052 process some input to a dcerpc endpoint server.
1054 NTSTATUS
dcesrv_process_ncacn_packet(struct dcesrv_connection
*dce_conn
,
1055 struct ncacn_packet
*pkt
,
1059 struct dcesrv_call_state
*call
;
1061 call
= talloc_zero(dce_conn
, struct dcesrv_call_state
);
1063 data_blob_free(&blob
);
1065 return NT_STATUS_NO_MEMORY
;
1067 call
->conn
= dce_conn
;
1068 call
->event_ctx
= dce_conn
->event_ctx
;
1069 call
->msg_ctx
= dce_conn
->msg_ctx
;
1070 call
->state_flags
= call
->conn
->state_flags
;
1071 call
->time
= timeval_current();
1072 call
->list
= DCESRV_LIST_NONE
;
1074 talloc_steal(call
, pkt
);
1075 talloc_steal(call
, blob
.data
);
1078 talloc_set_destructor(call
, dcesrv_call_dequeue
);
1080 /* we have to check the signing here, before combining the
1082 if (call
->pkt
.ptype
== DCERPC_PKT_REQUEST
&&
1083 !dcesrv_auth_request(call
, &blob
)) {
1084 return dcesrv_fault(call
, DCERPC_FAULT_ACCESS_DENIED
);
1087 /* see if this is a continued packet */
1088 if (call
->pkt
.ptype
== DCERPC_PKT_REQUEST
&&
1089 !(call
->pkt
.pfc_flags
& DCERPC_PFC_FLAG_FIRST
)) {
1090 struct dcesrv_call_state
*call2
= call
;
1091 uint32_t alloc_size
;
1093 /* we only allow fragmented requests, no other packet types */
1094 if (call
->pkt
.ptype
!= DCERPC_PKT_REQUEST
) {
1095 return dcesrv_fault(call2
, DCERPC_FAULT_OTHER
);
1098 /* this is a continuation of an existing call - find the call
1099 then tack it on the end */
1100 call
= dcesrv_find_fragmented_call(dce_conn
, call2
->pkt
.call_id
);
1102 return dcesrv_fault(call2
, DCERPC_FAULT_OTHER
);
1105 if (call
->pkt
.ptype
!= call2
->pkt
.ptype
) {
1106 /* trying to play silly buggers are we? */
1107 return dcesrv_fault(call2
, DCERPC_NCA_S_PROTO_ERROR
);
1109 if (memcmp(call
->pkt
.drep
, call2
->pkt
.drep
, sizeof(pkt
->drep
)) != 0) {
1110 return dcesrv_fault(call2
, DCERPC_NCA_S_PROTO_ERROR
);
1112 if (call
->pkt
.call_id
!= call2
->pkt
.call_id
) {
1113 return dcesrv_fault(call2
, DCERPC_NCA_S_PROTO_ERROR
);
1115 if (call
->pkt
.u
.request
.context_id
!= call2
->pkt
.u
.request
.context_id
) {
1116 return dcesrv_fault(call2
, DCERPC_NCA_S_PROTO_ERROR
);
1118 if (call
->pkt
.u
.request
.opnum
!= call2
->pkt
.u
.request
.opnum
) {
1119 return dcesrv_fault(call2
, DCERPC_NCA_S_PROTO_ERROR
);
1122 alloc_size
= call
->pkt
.u
.request
.stub_and_verifier
.length
+
1123 call2
->pkt
.u
.request
.stub_and_verifier
.length
;
1124 if (call
->pkt
.u
.request
.alloc_hint
> alloc_size
) {
1125 alloc_size
= call
->pkt
.u
.request
.alloc_hint
;
1128 call
->pkt
.u
.request
.stub_and_verifier
.data
=
1129 talloc_realloc(call
,
1130 call
->pkt
.u
.request
.stub_and_verifier
.data
,
1131 uint8_t, alloc_size
);
1132 if (!call
->pkt
.u
.request
.stub_and_verifier
.data
) {
1133 return dcesrv_fault(call2
, DCERPC_FAULT_OTHER
);
1135 memcpy(call
->pkt
.u
.request
.stub_and_verifier
.data
+
1136 call
->pkt
.u
.request
.stub_and_verifier
.length
,
1137 call2
->pkt
.u
.request
.stub_and_verifier
.data
,
1138 call2
->pkt
.u
.request
.stub_and_verifier
.length
);
1139 call
->pkt
.u
.request
.stub_and_verifier
.length
+=
1140 call2
->pkt
.u
.request
.stub_and_verifier
.length
;
1142 call
->pkt
.pfc_flags
|= (call2
->pkt
.pfc_flags
& DCERPC_PFC_FLAG_LAST
);
1147 /* this may not be the last pdu in the chain - if its isn't then
1148 just put it on the incoming_fragmented_call_list and wait for the rest */
1149 if (call
->pkt
.ptype
== DCERPC_PKT_REQUEST
&&
1150 !(call
->pkt
.pfc_flags
& DCERPC_PFC_FLAG_LAST
)) {
1151 dcesrv_call_set_list(call
, DCESRV_LIST_FRAGMENTED_CALL_LIST
);
1152 return NT_STATUS_OK
;
1155 /* This removes any fragments we may have had stashed away */
1156 dcesrv_call_set_list(call
, DCESRV_LIST_NONE
);
1158 switch (call
->pkt
.ptype
) {
1159 case DCERPC_PKT_BIND
:
1160 status
= dcesrv_bind(call
);
1162 case DCERPC_PKT_AUTH3
:
1163 status
= dcesrv_auth3(call
);
1165 case DCERPC_PKT_ALTER
:
1166 status
= dcesrv_alter(call
);
1168 case DCERPC_PKT_REQUEST
:
1169 status
= dcesrv_request(call
);
1172 status
= NT_STATUS_INVALID_PARAMETER
;
1176 /* if we are going to be sending a reply then add
1177 it to the list of pending calls. We add it to the end to keep the call
1178 list in the order we will answer */
1179 if (!NT_STATUS_IS_OK(status
)) {
1186 _PUBLIC_ NTSTATUS
dcesrv_init_context(TALLOC_CTX
*mem_ctx
,
1187 struct loadparm_context
*lp_ctx
,
1188 const char **endpoint_servers
, struct dcesrv_context
**_dce_ctx
)
1191 struct dcesrv_context
*dce_ctx
;
1194 if (!endpoint_servers
) {
1195 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1196 return NT_STATUS_INTERNAL_ERROR
;
1199 dce_ctx
= talloc(mem_ctx
, struct dcesrv_context
);
1200 NT_STATUS_HAVE_NO_MEMORY(dce_ctx
);
1201 dce_ctx
->initial_euid
= geteuid();
1202 dce_ctx
->endpoint_list
= NULL
;
1203 dce_ctx
->lp_ctx
= lp_ctx
;
1204 dce_ctx
->assoc_groups_idr
= idr_init(dce_ctx
);
1205 NT_STATUS_HAVE_NO_MEMORY(dce_ctx
->assoc_groups_idr
);
1206 dce_ctx
->broken_connections
= NULL
;
1208 for (i
=0;endpoint_servers
[i
];i
++) {
1209 const struct dcesrv_endpoint_server
*ep_server
;
1211 ep_server
= dcesrv_ep_server_byname(endpoint_servers
[i
]);
1213 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers
[i
]));
1214 return NT_STATUS_INTERNAL_ERROR
;
1217 status
= ep_server
->init_server(dce_ctx
, ep_server
);
1218 if (!NT_STATUS_IS_OK(status
)) {
1219 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers
[i
],
1220 nt_errstr(status
)));
1225 *_dce_ctx
= dce_ctx
;
1226 return NT_STATUS_OK
;
1229 /* the list of currently registered DCERPC endpoint servers.
1231 static struct ep_server
{
1232 struct dcesrv_endpoint_server
*ep_server
;
1233 } *ep_servers
= NULL
;
1234 static int num_ep_servers
;
1237 register a DCERPC endpoint server.
1239 The 'name' can be later used by other backends to find the operations
1240 structure for this backend.
1242 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1244 _PUBLIC_ NTSTATUS
dcerpc_register_ep_server(const void *_ep_server
)
1246 const struct dcesrv_endpoint_server
*ep_server
= _ep_server
;
1248 if (dcesrv_ep_server_byname(ep_server
->name
) != NULL
) {
1249 /* its already registered! */
1250 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1252 return NT_STATUS_OBJECT_NAME_COLLISION
;
1255 ep_servers
= realloc_p(ep_servers
, struct ep_server
, num_ep_servers
+1);
1257 smb_panic("out of memory in dcerpc_register");
1260 ep_servers
[num_ep_servers
].ep_server
= smb_xmemdup(ep_server
, sizeof(*ep_server
));
1261 ep_servers
[num_ep_servers
].ep_server
->name
= smb_xstrdup(ep_server
->name
);
1265 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1268 return NT_STATUS_OK
;
1272 return the operations structure for a named backend of the specified type
1274 const struct dcesrv_endpoint_server
*dcesrv_ep_server_byname(const char *name
)
1278 for (i
=0;i
<num_ep_servers
;i
++) {
1279 if (strcmp(ep_servers
[i
].ep_server
->name
, name
) == 0) {
1280 return ep_servers
[i
].ep_server
;
1287 void dcerpc_server_init(struct loadparm_context
*lp_ctx
)
1289 static bool initialized
;
1290 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
1291 STATIC_dcerpc_server_MODULES_PROTO
;
1292 init_module_fn static_init
[] = { STATIC_dcerpc_server_MODULES
};
1293 init_module_fn
*shared_init
;
1300 shared_init
= load_samba_modules(NULL
, "dcerpc_server");
1302 run_init_functions(static_init
);
1303 run_init_functions(shared_init
);
1305 talloc_free(shared_init
);
1309 return the DCERPC module version, and the size of some critical types
1310 This can be used by endpoint server modules to either detect compilation errors, or provide
1311 multiple implementations for different smbd compilation options in one module
1313 const struct dcesrv_critical_sizes
*dcerpc_module_version(void)
1315 static const struct dcesrv_critical_sizes critical_sizes
= {
1316 DCERPC_MODULE_VERSION
,
1317 sizeof(struct dcesrv_context
),
1318 sizeof(struct dcesrv_endpoint
),
1319 sizeof(struct dcesrv_endpoint_server
),
1320 sizeof(struct dcesrv_interface
),
1321 sizeof(struct dcesrv_if_list
),
1322 sizeof(struct dcesrv_connection
),
1323 sizeof(struct dcesrv_call_state
),
1324 sizeof(struct dcesrv_auth
),
1325 sizeof(struct dcesrv_handle
)
1328 return &critical_sizes
;
1331 static void dcesrv_terminate_connection(struct dcesrv_connection
*dce_conn
, const char *reason
)
1333 struct dcesrv_context
*dce_ctx
= dce_conn
->dce_ctx
;
1334 struct stream_connection
*srv_conn
;
1335 srv_conn
= talloc_get_type(dce_conn
->transport
.private_data
,
1336 struct stream_connection
);
1338 if (dce_conn
->pending_call_list
== NULL
) {
1339 char *full_reason
= talloc_asprintf(dce_conn
, "dcesrv: %s", reason
);
1341 DLIST_REMOVE(dce_ctx
->broken_connections
, dce_conn
);
1342 stream_terminate_connection(srv_conn
, full_reason
? full_reason
: reason
);
1346 if (dce_conn
->terminate
!= NULL
) {
1350 DEBUG(3,("dcesrv: terminating connection due to '%s' defered due to pending calls\n",
1352 dce_conn
->terminate
= talloc_strdup(dce_conn
, reason
);
1353 if (dce_conn
->terminate
== NULL
) {
1354 dce_conn
->terminate
= "dcesrv: defered terminating connection - no memory";
1356 DLIST_ADD_END(dce_ctx
->broken_connections
, dce_conn
, NULL
);
1359 static void dcesrv_cleanup_broken_connections(struct dcesrv_context
*dce_ctx
)
1361 struct dcesrv_connection
*cur
, *next
;
1363 next
= dce_ctx
->broken_connections
;
1364 while (next
!= NULL
) {
1368 dcesrv_terminate_connection(cur
, cur
->terminate
);
1372 /* We need this include to be able to compile on some plateforms
1373 * (ie. freebsd 7.2) as it seems that <sys/uio.h> is not included
1375 * It has to be that deep because otherwise we have a conflict on
1376 * const struct dcesrv_interface declaration.
1377 * This is mostly due to socket_wrapper defining #define bind swrap_bind
1378 * which conflict with the bind used before.
1380 #include "system/network.h"
1382 struct dcesrv_sock_reply_state
{
1383 struct dcesrv_connection
*dce_conn
;
1384 struct dcesrv_call_state
*call
;
1388 static void dcesrv_sock_reply_done(struct tevent_req
*subreq
);
1390 static void dcesrv_sock_report_output_data(struct dcesrv_connection
*dce_conn
)
1392 struct dcesrv_call_state
*call
;
1394 call
= dce_conn
->call_list
;
1395 if (!call
|| !call
->replies
) {
1399 while (call
->replies
) {
1400 struct data_blob_list_item
*rep
= call
->replies
;
1401 struct dcesrv_sock_reply_state
*substate
;
1402 struct tevent_req
*subreq
;
1404 substate
= talloc(call
, struct dcesrv_sock_reply_state
);
1406 dcesrv_terminate_connection(dce_conn
, "no memory");
1410 substate
->dce_conn
= dce_conn
;
1411 substate
->call
= NULL
;
1413 DLIST_REMOVE(call
->replies
, rep
);
1415 if (call
->replies
== NULL
) {
1416 substate
->call
= call
;
1419 substate
->iov
.iov_base
= (void *) rep
->blob
.data
;
1420 substate
->iov
.iov_len
= rep
->blob
.length
;
1422 subreq
= tstream_writev_queue_send(substate
,
1423 dce_conn
->event_ctx
,
1425 dce_conn
->send_queue
,
1428 dcesrv_terminate_connection(dce_conn
, "no memory");
1431 tevent_req_set_callback(subreq
, dcesrv_sock_reply_done
,
1435 DLIST_REMOVE(call
->conn
->call_list
, call
);
1436 call
->list
= DCESRV_LIST_NONE
;
1439 static void dcesrv_sock_reply_done(struct tevent_req
*subreq
)
1441 struct dcesrv_sock_reply_state
*substate
= tevent_req_callback_data(subreq
,
1442 struct dcesrv_sock_reply_state
);
1446 struct dcesrv_call_state
*call
= substate
->call
;
1448 ret
= tstream_writev_queue_recv(subreq
, &sys_errno
);
1449 TALLOC_FREE(subreq
);
1451 status
= map_nt_error_from_unix_common(sys_errno
);
1452 dcesrv_terminate_connection(substate
->dce_conn
, nt_errstr(status
));
1456 talloc_free(substate
);
1465 struct dcesrv_socket_context
{
1466 const struct dcesrv_endpoint
*endpoint
;
1467 struct dcesrv_context
*dcesrv_ctx
;
1471 static void dcesrv_read_fragment_done(struct tevent_req
*subreq
);
1473 static void dcesrv_sock_accept(struct stream_connection
*srv_conn
)
1476 struct dcesrv_socket_context
*dcesrv_sock
=
1477 talloc_get_type(srv_conn
->private_data
, struct dcesrv_socket_context
);
1478 enum dcerpc_transport_t transport
=
1479 dcerpc_binding_get_transport(dcesrv_sock
->endpoint
->ep_description
);
1480 struct dcesrv_connection
*dcesrv_conn
= NULL
;
1482 struct tevent_req
*subreq
;
1483 struct loadparm_context
*lp_ctx
= dcesrv_sock
->dcesrv_ctx
->lp_ctx
;
1485 dcesrv_cleanup_broken_connections(dcesrv_sock
->dcesrv_ctx
);
1487 if (!srv_conn
->session_info
) {
1488 status
= auth_anonymous_session_info(srv_conn
,
1490 &srv_conn
->session_info
);
1491 if (!NT_STATUS_IS_OK(status
)) {
1492 DEBUG(0,("dcesrv_sock_accept: auth_anonymous_session_info failed: %s\n",
1493 nt_errstr(status
)));
1494 stream_terminate_connection(srv_conn
, nt_errstr(status
));
1499 status
= dcesrv_endpoint_connect(dcesrv_sock
->dcesrv_ctx
,
1501 dcesrv_sock
->endpoint
,
1502 srv_conn
->session_info
,
1503 srv_conn
->event
.ctx
,
1505 srv_conn
->server_id
,
1506 DCESRV_CALL_STATE_FLAG_MAY_ASYNC
,
1508 if (!NT_STATUS_IS_OK(status
)) {
1509 DEBUG(0,("dcesrv_sock_accept: dcesrv_endpoint_connect failed: %s\n",
1510 nt_errstr(status
)));
1511 stream_terminate_connection(srv_conn
, nt_errstr(status
));
1515 dcesrv_conn
->transport
.private_data
= srv_conn
;
1516 dcesrv_conn
->transport
.report_output_data
= dcesrv_sock_report_output_data
;
1518 TALLOC_FREE(srv_conn
->event
.fde
);
1520 dcesrv_conn
->send_queue
= tevent_queue_create(dcesrv_conn
, "dcesrv send queue");
1521 if (!dcesrv_conn
->send_queue
) {
1522 status
= NT_STATUS_NO_MEMORY
;
1523 DEBUG(0,("dcesrv_sock_accept: tevent_queue_create(%s)\n",
1524 nt_errstr(status
)));
1525 stream_terminate_connection(srv_conn
, nt_errstr(status
));
1529 if (transport
== NCACN_NP
) {
1530 dcesrv_conn
->auth_state
.session_key
= dcesrv_inherited_session_key
;
1531 dcesrv_conn
->stream
= talloc_move(dcesrv_conn
,
1532 &srv_conn
->tstream
);
1534 ret
= tstream_bsd_existing_socket(dcesrv_conn
,
1535 socket_get_fd(srv_conn
->socket
),
1536 &dcesrv_conn
->stream
);
1538 status
= map_nt_error_from_unix_common(errno
);
1539 DEBUG(0, ("dcesrv_sock_accept: "
1540 "failed to setup tstream: %s\n",
1541 nt_errstr(status
)));
1542 stream_terminate_connection(srv_conn
, nt_errstr(status
));
1545 socket_set_flags(srv_conn
->socket
, SOCKET_FLAG_NOCLOSE
);
1548 dcesrv_conn
->local_address
= srv_conn
->local_address
;
1549 dcesrv_conn
->remote_address
= srv_conn
->remote_address
;
1551 if (transport
== NCALRPC
) {
1555 ret
= getpeereid(socket_get_fd(srv_conn
->socket
), &uid
, &gid
);
1557 status
= map_nt_error_from_unix_common(errno
);
1558 DEBUG(0, ("dcesrv_sock_accept: "
1559 "getpeereid() failed for NCALRPC: %s\n",
1560 nt_errstr(status
)));
1561 stream_terminate_connection(srv_conn
, nt_errstr(status
));
1564 if (uid
== dcesrv_conn
->dce_ctx
->initial_euid
) {
1565 struct tsocket_address
*r
= NULL
;
1567 ret
= tsocket_address_unix_from_path(dcesrv_conn
,
1568 "/root/ncalrpc_as_system",
1571 status
= map_nt_error_from_unix_common(errno
);
1572 DEBUG(0, ("dcesrv_sock_accept: "
1573 "tsocket_address_unix_from_path() failed for NCALRPC: %s\n",
1574 nt_errstr(status
)));
1575 stream_terminate_connection(srv_conn
, nt_errstr(status
));
1578 dcesrv_conn
->remote_address
= r
;
1582 srv_conn
->private_data
= dcesrv_conn
;
1584 irpc_add_name(srv_conn
->msg_ctx
, "rpc_server");
1586 subreq
= dcerpc_read_ncacn_packet_send(dcesrv_conn
,
1587 dcesrv_conn
->event_ctx
,
1588 dcesrv_conn
->stream
);
1590 status
= NT_STATUS_NO_MEMORY
;
1591 DEBUG(0,("dcesrv_sock_accept: dcerpc_read_fragment_buffer_send(%s)\n",
1592 nt_errstr(status
)));
1593 stream_terminate_connection(srv_conn
, nt_errstr(status
));
1596 tevent_req_set_callback(subreq
, dcesrv_read_fragment_done
, dcesrv_conn
);
1601 static void dcesrv_read_fragment_done(struct tevent_req
*subreq
)
1603 struct dcesrv_connection
*dce_conn
= tevent_req_callback_data(subreq
,
1604 struct dcesrv_connection
);
1605 struct dcesrv_context
*dce_ctx
= dce_conn
->dce_ctx
;
1606 struct ncacn_packet
*pkt
;
1610 if (dce_conn
->terminate
) {
1612 * if the current connection is broken
1613 * we need to clean it up before any other connection
1615 dcesrv_terminate_connection(dce_conn
, dce_conn
->terminate
);
1616 dcesrv_cleanup_broken_connections(dce_ctx
);
1620 dcesrv_cleanup_broken_connections(dce_ctx
);
1622 status
= dcerpc_read_ncacn_packet_recv(subreq
, dce_conn
,
1624 TALLOC_FREE(subreq
);
1625 if (!NT_STATUS_IS_OK(status
)) {
1626 dcesrv_terminate_connection(dce_conn
, nt_errstr(status
));
1630 status
= dcesrv_process_ncacn_packet(dce_conn
, pkt
, buffer
);
1631 if (!NT_STATUS_IS_OK(status
)) {
1632 dcesrv_terminate_connection(dce_conn
, nt_errstr(status
));
1636 subreq
= dcerpc_read_ncacn_packet_send(dce_conn
,
1637 dce_conn
->event_ctx
,
1640 status
= NT_STATUS_NO_MEMORY
;
1641 dcesrv_terminate_connection(dce_conn
, nt_errstr(status
));
1644 tevent_req_set_callback(subreq
, dcesrv_read_fragment_done
, dce_conn
);
1647 static void dcesrv_sock_recv(struct stream_connection
*conn
, uint16_t flags
)
1649 struct dcesrv_connection
*dce_conn
= talloc_get_type(conn
->private_data
,
1650 struct dcesrv_connection
);
1651 dcesrv_terminate_connection(dce_conn
, "dcesrv_sock_recv triggered");
1654 static void dcesrv_sock_send(struct stream_connection
*conn
, uint16_t flags
)
1656 struct dcesrv_connection
*dce_conn
= talloc_get_type(conn
->private_data
,
1657 struct dcesrv_connection
);
1658 dcesrv_terminate_connection(dce_conn
, "dcesrv_sock_send triggered");
1662 static const struct stream_server_ops dcesrv_stream_ops
= {
1664 .accept_connection
= dcesrv_sock_accept
,
1665 .recv_handler
= dcesrv_sock_recv
,
1666 .send_handler
= dcesrv_sock_send
,
1669 static NTSTATUS
dcesrv_add_ep_unix(struct dcesrv_context
*dce_ctx
,
1670 struct loadparm_context
*lp_ctx
,
1671 struct dcesrv_endpoint
*e
,
1672 struct tevent_context
*event_ctx
, const struct model_ops
*model_ops
)
1674 struct dcesrv_socket_context
*dcesrv_sock
;
1677 const char *endpoint
;
1679 dcesrv_sock
= talloc(event_ctx
, struct dcesrv_socket_context
);
1680 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock
);
1682 /* remember the endpoint of this socket */
1683 dcesrv_sock
->endpoint
= e
;
1684 dcesrv_sock
->dcesrv_ctx
= talloc_reference(dcesrv_sock
, dce_ctx
);
1686 endpoint
= dcerpc_binding_get_string_option(e
->ep_description
, "endpoint");
1688 status
= stream_setup_socket(dcesrv_sock
, event_ctx
, lp_ctx
,
1689 model_ops
, &dcesrv_stream_ops
,
1690 "unix", endpoint
, &port
,
1691 lpcfg_socket_options(lp_ctx
),
1693 if (!NT_STATUS_IS_OK(status
)) {
1694 DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n",
1695 endpoint
, nt_errstr(status
)));
1701 static NTSTATUS
dcesrv_add_ep_ncalrpc(struct dcesrv_context
*dce_ctx
,
1702 struct loadparm_context
*lp_ctx
,
1703 struct dcesrv_endpoint
*e
,
1704 struct tevent_context
*event_ctx
, const struct model_ops
*model_ops
)
1706 struct dcesrv_socket_context
*dcesrv_sock
;
1710 const char *endpoint
;
1712 endpoint
= dcerpc_binding_get_string_option(e
->ep_description
, "endpoint");
1714 if (endpoint
== NULL
) {
1716 * No identifier specified: use DEFAULT.
1718 * TODO: DO NOT hardcode this value anywhere else. Rather, specify
1719 * no endpoint and let the epmapper worry about it.
1721 endpoint
= "DEFAULT";
1722 status
= dcerpc_binding_set_string_option(e
->ep_description
,
1725 if (!NT_STATUS_IS_OK(status
)) {
1726 DEBUG(0,("dcerpc_binding_set_string_option() failed - %s\n",
1727 nt_errstr(status
)));
1732 full_path
= talloc_asprintf(dce_ctx
, "%s/%s", lpcfg_ncalrpc_dir(lp_ctx
),
1735 dcesrv_sock
= talloc(event_ctx
, struct dcesrv_socket_context
);
1736 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock
);
1738 /* remember the endpoint of this socket */
1739 dcesrv_sock
->endpoint
= e
;
1740 dcesrv_sock
->dcesrv_ctx
= talloc_reference(dcesrv_sock
, dce_ctx
);
1742 status
= stream_setup_socket(dcesrv_sock
, event_ctx
, lp_ctx
,
1743 model_ops
, &dcesrv_stream_ops
,
1744 "unix", full_path
, &port
,
1745 lpcfg_socket_options(lp_ctx
),
1747 if (!NT_STATUS_IS_OK(status
)) {
1748 DEBUG(0,("service_setup_stream_socket(identifier=%s,path=%s) failed - %s\n",
1749 endpoint
, full_path
, nt_errstr(status
)));
1754 static NTSTATUS
dcesrv_add_ep_np(struct dcesrv_context
*dce_ctx
,
1755 struct loadparm_context
*lp_ctx
,
1756 struct dcesrv_endpoint
*e
,
1757 struct tevent_context
*event_ctx
, const struct model_ops
*model_ops
)
1759 struct dcesrv_socket_context
*dcesrv_sock
;
1761 const char *endpoint
;
1763 endpoint
= dcerpc_binding_get_string_option(e
->ep_description
, "endpoint");
1764 if (endpoint
== NULL
) {
1765 DEBUG(0, ("Endpoint mandatory for named pipes\n"));
1766 return NT_STATUS_INVALID_PARAMETER
;
1769 dcesrv_sock
= talloc(event_ctx
, struct dcesrv_socket_context
);
1770 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock
);
1772 /* remember the endpoint of this socket */
1773 dcesrv_sock
->endpoint
= e
;
1774 dcesrv_sock
->dcesrv_ctx
= talloc_reference(dcesrv_sock
, dce_ctx
);
1776 status
= tstream_setup_named_pipe(dce_ctx
, event_ctx
, lp_ctx
,
1777 model_ops
, &dcesrv_stream_ops
,
1780 if (!NT_STATUS_IS_OK(status
)) {
1781 DEBUG(0,("stream_setup_named_pipe(pipe=%s) failed - %s\n",
1782 endpoint
, nt_errstr(status
)));
1786 return NT_STATUS_OK
;
1790 add a socket address to the list of events, one event per dcerpc endpoint
1792 static NTSTATUS
add_socket_rpc_tcp_iface(struct dcesrv_context
*dce_ctx
, struct dcesrv_endpoint
*e
,
1793 struct tevent_context
*event_ctx
, const struct model_ops
*model_ops
,
1794 const char *address
)
1796 struct dcesrv_socket_context
*dcesrv_sock
;
1799 const char *endpoint
;
1802 endpoint
= dcerpc_binding_get_string_option(e
->ep_description
, "endpoint");
1803 if (endpoint
!= NULL
) {
1804 port
= atoi(endpoint
);
1807 dcesrv_sock
= talloc(event_ctx
, struct dcesrv_socket_context
);
1808 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock
);
1810 /* remember the endpoint of this socket */
1811 dcesrv_sock
->endpoint
= e
;
1812 dcesrv_sock
->dcesrv_ctx
= talloc_reference(dcesrv_sock
, dce_ctx
);
1814 status
= stream_setup_socket(dcesrv_sock
, event_ctx
, dce_ctx
->lp_ctx
,
1815 model_ops
, &dcesrv_stream_ops
,
1816 "ip", address
, &port
,
1817 lpcfg_socket_options(dce_ctx
->lp_ctx
),
1819 if (!NT_STATUS_IS_OK(status
)) {
1820 DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) failed - %s\n",
1821 address
, port
, nt_errstr(status
)));
1825 snprintf(port_str
, sizeof(port_str
), "%u", port
);
1827 status
= dcerpc_binding_set_string_option(e
->ep_description
,
1828 "endpoint", port_str
);
1829 if (!NT_STATUS_IS_OK(status
)) {
1830 DEBUG(0,("dcerpc_binding_set_string_option(endpoint, %s) failed - %s\n",
1831 port_str
, nt_errstr(status
)));
1835 return NT_STATUS_OK
;
1838 #include "lib/socket/netif.h" /* Included here to work around the fact that socket_wrapper redefines bind() */
1840 static NTSTATUS
dcesrv_add_ep_tcp(struct dcesrv_context
*dce_ctx
,
1841 struct loadparm_context
*lp_ctx
,
1842 struct dcesrv_endpoint
*e
,
1843 struct tevent_context
*event_ctx
, const struct model_ops
*model_ops
)
1847 /* Add TCP/IP sockets */
1848 if (lpcfg_interfaces(lp_ctx
) && lpcfg_bind_interfaces_only(lp_ctx
)) {
1851 struct interface
*ifaces
;
1853 load_interface_list(dce_ctx
, lp_ctx
, &ifaces
);
1855 num_interfaces
= iface_list_count(ifaces
);
1856 for(i
= 0; i
< num_interfaces
; i
++) {
1857 const char *address
= iface_list_n_ip(ifaces
, i
);
1858 status
= add_socket_rpc_tcp_iface(dce_ctx
, e
, event_ctx
, model_ops
, address
);
1859 NT_STATUS_NOT_OK_RETURN(status
);
1865 wcard
= iface_list_wildcard(dce_ctx
);
1866 NT_STATUS_HAVE_NO_MEMORY(wcard
);
1867 for (i
=0; wcard
[i
]; i
++) {
1868 status
= add_socket_rpc_tcp_iface(dce_ctx
, e
, event_ctx
, model_ops
, wcard
[i
]);
1869 if (NT_STATUS_IS_OK(status
)) {
1874 if (num_binds
== 0) {
1875 return NT_STATUS_INVALID_PARAMETER_MIX
;
1879 return NT_STATUS_OK
;
1882 NTSTATUS
dcesrv_add_ep(struct dcesrv_context
*dce_ctx
,
1883 struct loadparm_context
*lp_ctx
,
1884 struct dcesrv_endpoint
*e
,
1885 struct tevent_context
*event_ctx
,
1886 const struct model_ops
*model_ops
)
1888 enum dcerpc_transport_t transport
=
1889 dcerpc_binding_get_transport(e
->ep_description
);
1891 switch (transport
) {
1892 case NCACN_UNIX_STREAM
:
1893 return dcesrv_add_ep_unix(dce_ctx
, lp_ctx
, e
, event_ctx
, model_ops
);
1896 return dcesrv_add_ep_ncalrpc(dce_ctx
, lp_ctx
, e
, event_ctx
, model_ops
);
1899 return dcesrv_add_ep_tcp(dce_ctx
, lp_ctx
, e
, event_ctx
, model_ops
);
1902 return dcesrv_add_ep_np(dce_ctx
, lp_ctx
, e
, event_ctx
, model_ops
);
1905 return NT_STATUS_NOT_SUPPORTED
;
1911 * retrieve credentials from a dce_call
1913 _PUBLIC_
struct cli_credentials
*dcesrv_call_credentials(struct dcesrv_call_state
*dce_call
)
1915 return dce_call
->conn
->auth_state
.session_info
->credentials
;
1919 * returns true if this is an authenticated call
1921 _PUBLIC_
bool dcesrv_call_authenticated(struct dcesrv_call_state
*dce_call
)
1923 enum security_user_level level
;
1924 level
= security_session_user_level(dce_call
->conn
->auth_state
.session_info
, NULL
);
1925 return level
>= SECURITY_USER
;
1929 * retrieve account_name for a dce_call
1931 _PUBLIC_
const char *dcesrv_call_account_name(struct dcesrv_call_state
*dce_call
)
1933 return dce_call
->context
->conn
->auth_state
.session_info
->info
->account_name
;