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"
44 /* this is only used when the client asks for an unknown interface */
45 #define DUMMY_ASSOC_GROUP 0x0FFFFFFF
47 extern const struct dcesrv_interface dcesrv_mgmt_interface
;
51 find an association group given a assoc_group_id
53 static struct dcesrv_assoc_group
*dcesrv_assoc_group_find(struct dcesrv_context
*dce_ctx
,
58 id_ptr
= idr_find(dce_ctx
->assoc_groups_idr
, id
);
62 return talloc_get_type_abort(id_ptr
, struct dcesrv_assoc_group
);
66 take a reference to an existing association group
68 static struct dcesrv_assoc_group
*dcesrv_assoc_group_reference(TALLOC_CTX
*mem_ctx
,
69 struct dcesrv_context
*dce_ctx
,
72 struct dcesrv_assoc_group
*assoc_group
;
74 assoc_group
= dcesrv_assoc_group_find(dce_ctx
, id
);
75 if (assoc_group
== NULL
) {
76 DEBUG(0,(__location__
": Failed to find assoc_group 0x%08x\n", id
));
79 return talloc_reference(mem_ctx
, assoc_group
);
82 static int dcesrv_assoc_group_destructor(struct dcesrv_assoc_group
*assoc_group
)
85 ret
= idr_remove(assoc_group
->dce_ctx
->assoc_groups_idr
, assoc_group
->id
);
87 DEBUG(0,(__location__
": Failed to remove assoc_group 0x%08x\n",
94 allocate a new association group
96 static struct dcesrv_assoc_group
*dcesrv_assoc_group_new(TALLOC_CTX
*mem_ctx
,
97 struct dcesrv_context
*dce_ctx
)
99 struct dcesrv_assoc_group
*assoc_group
;
102 assoc_group
= talloc_zero(mem_ctx
, struct dcesrv_assoc_group
);
103 if (assoc_group
== NULL
) {
107 id
= idr_get_new_random(dce_ctx
->assoc_groups_idr
, assoc_group
, UINT16_MAX
);
109 talloc_free(assoc_group
);
110 DEBUG(0,(__location__
": Out of association groups!\n"));
114 assoc_group
->id
= id
;
115 assoc_group
->dce_ctx
= dce_ctx
;
117 talloc_set_destructor(assoc_group
, dcesrv_assoc_group_destructor
);
124 see if two endpoints match
126 static bool endpoints_match(const struct dcerpc_binding
*ep1
,
127 const struct dcerpc_binding
*ep2
)
129 if (ep1
->transport
!= ep2
->transport
) {
133 if (!ep1
->endpoint
|| !ep2
->endpoint
) {
134 return ep1
->endpoint
== ep2
->endpoint
;
137 if (strcasecmp(ep1
->endpoint
, ep2
->endpoint
) != 0)
144 find an endpoint in the dcesrv_context
146 static struct dcesrv_endpoint
*find_endpoint(struct dcesrv_context
*dce_ctx
,
147 const struct dcerpc_binding
*ep_description
)
149 struct dcesrv_endpoint
*ep
;
150 for (ep
=dce_ctx
->endpoint_list
; ep
; ep
=ep
->next
) {
151 if (endpoints_match(ep
->ep_description
, ep_description
)) {
159 find a registered context_id from a bind or alter_context
161 static struct dcesrv_connection_context
*dcesrv_find_context(struct dcesrv_connection
*conn
,
164 struct dcesrv_connection_context
*c
;
165 for (c
=conn
->contexts
;c
;c
=c
->next
) {
166 if (c
->context_id
== context_id
) return c
;
172 see if a uuid and if_version match to an interface
174 static bool interface_match(const struct dcesrv_interface
*if1
,
175 const struct dcesrv_interface
*if2
)
177 return (if1
->syntax_id
.if_version
== if2
->syntax_id
.if_version
&&
178 GUID_equal(&if1
->syntax_id
.uuid
, &if2
->syntax_id
.uuid
));
182 find the interface operations on an endpoint
184 static const struct dcesrv_interface
*find_interface(const struct dcesrv_endpoint
*endpoint
,
185 const struct dcesrv_interface
*iface
)
187 struct dcesrv_if_list
*ifl
;
188 for (ifl
=endpoint
->interface_list
; ifl
; ifl
=ifl
->next
) {
189 if (interface_match(&(ifl
->iface
), iface
)) {
190 return &(ifl
->iface
);
197 see if a uuid and if_version match to an interface
199 static bool interface_match_by_uuid(const struct dcesrv_interface
*iface
,
200 const struct GUID
*uuid
, uint32_t if_version
)
202 return (iface
->syntax_id
.if_version
== if_version
&&
203 GUID_equal(&iface
->syntax_id
.uuid
, uuid
));
207 find the interface operations on an endpoint by uuid
209 static const struct dcesrv_interface
*find_interface_by_uuid(const struct dcesrv_endpoint
*endpoint
,
210 const struct GUID
*uuid
, uint32_t if_version
)
212 struct dcesrv_if_list
*ifl
;
213 for (ifl
=endpoint
->interface_list
; ifl
; ifl
=ifl
->next
) {
214 if (interface_match_by_uuid(&(ifl
->iface
), uuid
, if_version
)) {
215 return &(ifl
->iface
);
222 find the earlier parts of a fragmented call awaiting reassembily
224 static struct dcesrv_call_state
*dcesrv_find_fragmented_call(struct dcesrv_connection
*dce_conn
, uint16_t call_id
)
226 struct dcesrv_call_state
*c
;
227 for (c
=dce_conn
->incoming_fragmented_call_list
;c
;c
=c
->next
) {
228 if (c
->pkt
.call_id
== call_id
) {
236 register an interface on an endpoint
238 _PUBLIC_ NTSTATUS
dcesrv_interface_register(struct dcesrv_context
*dce_ctx
,
240 const struct dcesrv_interface
*iface
,
241 const struct security_descriptor
*sd
)
243 struct dcesrv_endpoint
*ep
;
244 struct dcesrv_if_list
*ifl
;
245 struct dcerpc_binding
*binding
;
249 status
= dcerpc_parse_binding(dce_ctx
, ep_name
, &binding
);
251 if (NT_STATUS_IS_ERR(status
)) {
252 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name
));
256 /* check if this endpoint exists
258 if ((ep
=find_endpoint(dce_ctx
, binding
))==NULL
) {
259 ep
= talloc(dce_ctx
, struct dcesrv_endpoint
);
261 return NT_STATUS_NO_MEMORY
;
264 ep
->ep_description
= talloc_reference(ep
, binding
);
267 /* add mgmt interface */
268 ifl
= talloc(dce_ctx
, struct dcesrv_if_list
);
270 return NT_STATUS_NO_MEMORY
;
273 memcpy(&(ifl
->iface
), &dcesrv_mgmt_interface
,
274 sizeof(struct dcesrv_interface
));
276 DLIST_ADD(ep
->interface_list
, ifl
);
279 /* see if the interface is already registered on te endpoint */
280 if (find_interface(ep
, iface
)!=NULL
) {
281 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
282 iface
->name
, ep_name
));
283 return NT_STATUS_OBJECT_NAME_COLLISION
;
286 /* talloc a new interface list element */
287 ifl
= talloc(dce_ctx
, struct dcesrv_if_list
);
289 return NT_STATUS_NO_MEMORY
;
292 /* copy the given interface struct to the one on the endpoints interface list */
293 memcpy(&(ifl
->iface
),iface
, sizeof(struct dcesrv_interface
));
295 /* if we have a security descriptor given,
296 * we should see if we can set it up on the endpoint
299 /* if there's currently no security descriptor given on the endpoint
302 if (ep
->sd
== NULL
) {
303 ep
->sd
= security_descriptor_copy(dce_ctx
, sd
);
306 /* if now there's no security descriptor given on the endpoint
307 * something goes wrong, either we failed to copy the security descriptor
308 * or there was already one on the endpoint
310 if (ep
->sd
!= NULL
) {
311 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
312 " on endpoint '%s'\n",
313 iface
->name
, ep_name
));
314 if (add_ep
) free(ep
);
316 return NT_STATUS_OBJECT_NAME_COLLISION
;
320 /* finally add the interface on the endpoint */
321 DLIST_ADD(ep
->interface_list
, ifl
);
323 /* if it's a new endpoint add it to the dcesrv_context */
325 DLIST_ADD(dce_ctx
->endpoint_list
, ep
);
328 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
329 iface
->name
, ep_name
));
334 NTSTATUS
dcesrv_inherited_session_key(struct dcesrv_connection
*p
,
335 DATA_BLOB
*session_key
)
337 if (p
->auth_state
.session_info
->session_key
.length
) {
338 *session_key
= p
->auth_state
.session_info
->session_key
;
341 return NT_STATUS_NO_USER_SESSION_KEY
;
345 fetch the user session key - may be default (above) or the SMB session key
347 The key is always truncated to 16 bytes
349 _PUBLIC_ NTSTATUS
dcesrv_fetch_session_key(struct dcesrv_connection
*p
,
350 DATA_BLOB
*session_key
)
352 NTSTATUS status
= p
->auth_state
.session_key(p
, session_key
);
353 if (!NT_STATUS_IS_OK(status
)) {
357 session_key
->length
= MIN(session_key
->length
, 16);
363 connect to a dcerpc endpoint
365 _PUBLIC_ NTSTATUS
dcesrv_endpoint_connect(struct dcesrv_context
*dce_ctx
,
367 const struct dcesrv_endpoint
*ep
,
368 struct auth_session_info
*session_info
,
369 struct tevent_context
*event_ctx
,
370 struct imessaging_context
*msg_ctx
,
371 struct server_id server_id
,
372 uint32_t state_flags
,
373 struct dcesrv_connection
**_p
)
375 struct dcesrv_connection
*p
;
378 return NT_STATUS_ACCESS_DENIED
;
381 p
= talloc_zero(mem_ctx
, struct dcesrv_connection
);
382 NT_STATUS_HAVE_NO_MEMORY(p
);
384 if (!talloc_reference(p
, session_info
)) {
386 return NT_STATUS_NO_MEMORY
;
389 p
->dce_ctx
= dce_ctx
;
391 p
->packet_log_dir
= lpcfg_lockdir(dce_ctx
->lp_ctx
);
392 p
->auth_state
.session_info
= session_info
;
393 p
->auth_state
.session_key
= dcesrv_generic_session_key
;
394 p
->event_ctx
= event_ctx
;
395 p
->msg_ctx
= msg_ctx
;
396 p
->server_id
= server_id
;
397 p
->state_flags
= state_flags
;
404 move a call from an existing linked list to the specified list. This
405 prevents bugs where we forget to remove the call from a previous
408 static void dcesrv_call_set_list(struct dcesrv_call_state
*call
,
409 enum dcesrv_call_list list
)
411 switch (call
->list
) {
412 case DCESRV_LIST_NONE
:
414 case DCESRV_LIST_CALL_LIST
:
415 DLIST_REMOVE(call
->conn
->call_list
, call
);
417 case DCESRV_LIST_FRAGMENTED_CALL_LIST
:
418 DLIST_REMOVE(call
->conn
->incoming_fragmented_call_list
, call
);
420 case DCESRV_LIST_PENDING_CALL_LIST
:
421 DLIST_REMOVE(call
->conn
->pending_call_list
, call
);
426 case DCESRV_LIST_NONE
:
428 case DCESRV_LIST_CALL_LIST
:
429 DLIST_ADD_END(call
->conn
->call_list
, call
, struct dcesrv_call_state
*);
431 case DCESRV_LIST_FRAGMENTED_CALL_LIST
:
432 DLIST_ADD_END(call
->conn
->incoming_fragmented_call_list
, call
, struct dcesrv_call_state
*);
434 case DCESRV_LIST_PENDING_CALL_LIST
:
435 DLIST_ADD_END(call
->conn
->pending_call_list
, call
, struct dcesrv_call_state
*);
442 return a dcerpc bind_nak
444 static NTSTATUS
dcesrv_bind_nak(struct dcesrv_call_state
*call
, uint32_t reason
)
446 struct ncacn_packet pkt
;
447 struct data_blob_list_item
*rep
;
450 /* setup a bind_nak */
451 dcesrv_init_hdr(&pkt
, lpcfg_rpc_big_endian(call
->conn
->dce_ctx
->lp_ctx
));
453 pkt
.call_id
= call
->pkt
.call_id
;
454 pkt
.ptype
= DCERPC_PKT_BIND_NAK
;
455 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
456 pkt
.u
.bind_nak
.reject_reason
= reason
;
457 if (pkt
.u
.bind_nak
.reject_reason
== DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED
) {
458 pkt
.u
.bind_nak
.versions
.v
.num_versions
= 0;
461 rep
= talloc(call
, struct data_blob_list_item
);
463 return NT_STATUS_NO_MEMORY
;
466 status
= ncacn_push_auth(&rep
->blob
, call
, &pkt
, NULL
);
467 if (!NT_STATUS_IS_OK(status
)) {
471 dcerpc_set_frag_length(&rep
->blob
, rep
->blob
.length
);
473 DLIST_ADD_END(call
->replies
, rep
, struct data_blob_list_item
*);
474 dcesrv_call_set_list(call
, DCESRV_LIST_CALL_LIST
);
476 if (call
->conn
->call_list
&& call
->conn
->call_list
->replies
) {
477 if (call
->conn
->transport
.report_output_data
) {
478 call
->conn
->transport
.report_output_data(call
->conn
);
485 static int dcesrv_connection_context_destructor(struct dcesrv_connection_context
*c
)
487 DLIST_REMOVE(c
->conn
->contexts
, c
);
489 if (c
->iface
&& c
->iface
->unbind
) {
490 c
->iface
->unbind(c
, c
->iface
);
497 handle a bind request
499 static NTSTATUS
dcesrv_bind(struct dcesrv_call_state
*call
)
501 uint32_t if_version
, transfer_syntax_version
;
502 struct GUID uuid
, *transfer_syntax_uuid
;
503 struct ncacn_packet pkt
;
504 struct data_blob_list_item
*rep
;
506 uint32_t result
=0, reason
=0;
508 const struct dcesrv_interface
*iface
;
509 uint32_t extra_flags
= 0;
512 if provided, check the assoc_group is valid
514 if (call
->pkt
.u
.bind
.assoc_group_id
!= 0 &&
515 lpcfg_parm_bool(call
->conn
->dce_ctx
->lp_ctx
, NULL
, "dcesrv","assoc group checking", true) &&
516 dcesrv_assoc_group_find(call
->conn
->dce_ctx
, call
->pkt
.u
.bind
.assoc_group_id
) == NULL
) {
517 return dcesrv_bind_nak(call
, 0);
520 if (call
->pkt
.u
.bind
.num_contexts
< 1 ||
521 call
->pkt
.u
.bind
.ctx_list
[0].num_transfer_syntaxes
< 1) {
522 return dcesrv_bind_nak(call
, 0);
525 context_id
= call
->pkt
.u
.bind
.ctx_list
[0].context_id
;
527 /* you can't bind twice on one context */
528 if (dcesrv_find_context(call
->conn
, context_id
) != NULL
) {
529 return dcesrv_bind_nak(call
, 0);
532 if_version
= call
->pkt
.u
.bind
.ctx_list
[0].abstract_syntax
.if_version
;
533 uuid
= call
->pkt
.u
.bind
.ctx_list
[0].abstract_syntax
.uuid
;
535 transfer_syntax_version
= call
->pkt
.u
.bind
.ctx_list
[0].transfer_syntaxes
[0].if_version
;
536 transfer_syntax_uuid
= &call
->pkt
.u
.bind
.ctx_list
[0].transfer_syntaxes
[0].uuid
;
537 if (!GUID_equal(&ndr_transfer_syntax_ndr
.uuid
, transfer_syntax_uuid
) != 0 ||
538 ndr_transfer_syntax_ndr
.if_version
!= transfer_syntax_version
) {
539 char *uuid_str
= GUID_string(call
, transfer_syntax_uuid
);
540 /* we only do NDR encoded dcerpc */
541 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str
));
542 talloc_free(uuid_str
);
543 return dcesrv_bind_nak(call
, 0);
546 iface
= find_interface_by_uuid(call
->conn
->endpoint
, &uuid
, if_version
);
548 char *uuid_str
= GUID_string(call
, &uuid
);
549 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str
, if_version
));
550 talloc_free(uuid_str
);
552 /* we don't know about that interface */
553 result
= DCERPC_BIND_PROVIDER_REJECT
;
554 reason
= DCERPC_BIND_REASON_ASYNTAX
;
558 /* add this context to the list of available context_ids */
559 struct dcesrv_connection_context
*context
= talloc(call
->conn
,
560 struct dcesrv_connection_context
);
561 if (context
== NULL
) {
562 return dcesrv_bind_nak(call
, 0);
564 context
->conn
= call
->conn
;
565 context
->iface
= iface
;
566 context
->context_id
= context_id
;
567 if (call
->pkt
.u
.bind
.assoc_group_id
!= 0) {
568 context
->assoc_group
= dcesrv_assoc_group_reference(context
,
570 call
->pkt
.u
.bind
.assoc_group_id
);
572 context
->assoc_group
= dcesrv_assoc_group_new(context
, call
->conn
->dce_ctx
);
574 if (context
->assoc_group
== NULL
) {
575 talloc_free(context
);
576 return dcesrv_bind_nak(call
, 0);
578 context
->private_data
= NULL
;
579 DLIST_ADD(call
->conn
->contexts
, context
);
580 call
->context
= context
;
581 talloc_set_destructor(context
, dcesrv_connection_context_destructor
);
583 status
= iface
->bind(call
, iface
, if_version
);
584 if (!NT_STATUS_IS_OK(status
)) {
585 char *uuid_str
= GUID_string(call
, &uuid
);
586 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
587 uuid_str
, if_version
, nt_errstr(status
)));
588 talloc_free(uuid_str
);
589 /* we don't want to trigger the iface->unbind() hook */
590 context
->iface
= NULL
;
591 talloc_free(call
->context
);
592 call
->context
= NULL
;
593 return dcesrv_bind_nak(call
, 0);
597 if (call
->conn
->cli_max_recv_frag
== 0) {
598 call
->conn
->cli_max_recv_frag
= MIN(0x2000, call
->pkt
.u
.bind
.max_recv_frag
);
601 /* handle any authentication that is being requested */
602 if (!dcesrv_auth_bind(call
)) {
603 talloc_free(call
->context
);
604 call
->context
= NULL
;
605 return dcesrv_bind_nak(call
, DCERPC_BIND_REASON_INVALID_AUTH_TYPE
);
608 /* setup a bind_ack */
609 dcesrv_init_hdr(&pkt
, lpcfg_rpc_big_endian(call
->conn
->dce_ctx
->lp_ctx
));
611 pkt
.call_id
= call
->pkt
.call_id
;
612 pkt
.ptype
= DCERPC_PKT_BIND_ACK
;
613 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
| extra_flags
;
614 pkt
.u
.bind_ack
.max_xmit_frag
= call
->conn
->cli_max_recv_frag
;
615 pkt
.u
.bind_ack
.max_recv_frag
= 0x2000;
618 make it possible for iface->bind() to specify the assoc_group_id
619 This helps the openchange mapiproxy plugin to work correctly.
624 pkt
.u
.bind_ack
.assoc_group_id
= call
->context
->assoc_group
->id
;
626 pkt
.u
.bind_ack
.assoc_group_id
= DUMMY_ASSOC_GROUP
;
630 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
631 pkt
.u
.bind_ack
.secondary_address
= talloc_asprintf(call
, "\\PIPE\\%s", iface
->name
);
633 pkt
.u
.bind_ack
.secondary_address
= "";
635 pkt
.u
.bind_ack
.num_results
= 1;
636 pkt
.u
.bind_ack
.ctx_list
= talloc(call
, struct dcerpc_ack_ctx
);
637 if (!pkt
.u
.bind_ack
.ctx_list
) {
638 talloc_free(call
->context
);
639 call
->context
= NULL
;
640 return NT_STATUS_NO_MEMORY
;
642 pkt
.u
.bind_ack
.ctx_list
[0].result
= result
;
643 pkt
.u
.bind_ack
.ctx_list
[0].reason
.value
= reason
;
644 pkt
.u
.bind_ack
.ctx_list
[0].syntax
= ndr_transfer_syntax_ndr
;
645 pkt
.u
.bind_ack
.auth_info
= data_blob(NULL
, 0);
647 status
= dcesrv_auth_bind_ack(call
, &pkt
);
648 if (!NT_STATUS_IS_OK(status
)) {
649 talloc_free(call
->context
);
650 call
->context
= NULL
;
651 return dcesrv_bind_nak(call
, 0);
654 rep
= talloc(call
, struct data_blob_list_item
);
656 talloc_free(call
->context
);
657 call
->context
= NULL
;
658 return NT_STATUS_NO_MEMORY
;
661 status
= ncacn_push_auth(&rep
->blob
, call
, &pkt
,
662 call
->conn
->auth_state
.auth_info
);
663 if (!NT_STATUS_IS_OK(status
)) {
664 talloc_free(call
->context
);
665 call
->context
= NULL
;
669 dcerpc_set_frag_length(&rep
->blob
, rep
->blob
.length
);
671 DLIST_ADD_END(call
->replies
, rep
, struct data_blob_list_item
*);
672 dcesrv_call_set_list(call
, DCESRV_LIST_CALL_LIST
);
674 if (call
->conn
->call_list
&& call
->conn
->call_list
->replies
) {
675 if (call
->conn
->transport
.report_output_data
) {
676 call
->conn
->transport
.report_output_data(call
->conn
);
685 handle a auth3 request
687 static NTSTATUS
dcesrv_auth3(struct dcesrv_call_state
*call
)
689 /* handle the auth3 in the auth code */
690 if (!dcesrv_auth_auth3(call
)) {
691 return dcesrv_fault(call
, DCERPC_FAULT_OTHER
);
696 /* we don't send a reply to a auth3 request, except by a
703 handle a bind request
705 static NTSTATUS
dcesrv_alter_new_context(struct dcesrv_call_state
*call
, uint32_t context_id
)
707 uint32_t if_version
, transfer_syntax_version
;
708 struct dcesrv_connection_context
*context
;
709 const struct dcesrv_interface
*iface
;
710 struct GUID uuid
, *transfer_syntax_uuid
;
713 if_version
= call
->pkt
.u
.alter
.ctx_list
[0].abstract_syntax
.if_version
;
714 uuid
= call
->pkt
.u
.alter
.ctx_list
[0].abstract_syntax
.uuid
;
716 transfer_syntax_version
= call
->pkt
.u
.alter
.ctx_list
[0].transfer_syntaxes
[0].if_version
;
717 transfer_syntax_uuid
= &call
->pkt
.u
.alter
.ctx_list
[0].transfer_syntaxes
[0].uuid
;
718 if (!GUID_equal(transfer_syntax_uuid
, &ndr_transfer_syntax_ndr
.uuid
) ||
719 ndr_transfer_syntax_ndr
.if_version
!= transfer_syntax_version
) {
720 /* we only do NDR encoded dcerpc */
721 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED
;
724 iface
= find_interface_by_uuid(call
->conn
->endpoint
, &uuid
, if_version
);
726 char *uuid_str
= GUID_string(call
, &uuid
);
727 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str
, if_version
));
728 talloc_free(uuid_str
);
729 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED
;
732 /* add this context to the list of available context_ids */
733 context
= talloc(call
->conn
, struct dcesrv_connection_context
);
734 if (context
== NULL
) {
735 return NT_STATUS_NO_MEMORY
;
737 context
->conn
= call
->conn
;
738 context
->iface
= iface
;
739 context
->context_id
= context_id
;
740 if (call
->pkt
.u
.alter
.assoc_group_id
!= 0) {
741 context
->assoc_group
= dcesrv_assoc_group_reference(context
,
743 call
->pkt
.u
.alter
.assoc_group_id
);
745 context
->assoc_group
= dcesrv_assoc_group_new(context
, call
->conn
->dce_ctx
);
747 if (context
->assoc_group
== NULL
) {
748 talloc_free(context
);
749 call
->context
= NULL
;
750 return NT_STATUS_NO_MEMORY
;
752 context
->private_data
= NULL
;
753 DLIST_ADD(call
->conn
->contexts
, context
);
754 call
->context
= context
;
755 talloc_set_destructor(context
, dcesrv_connection_context_destructor
);
757 status
= iface
->bind(call
, iface
, if_version
);
758 if (!NT_STATUS_IS_OK(status
)) {
759 /* we don't want to trigger the iface->unbind() hook */
760 context
->iface
= NULL
;
761 talloc_free(context
);
762 call
->context
= NULL
;
771 handle a alter context request
773 static NTSTATUS
dcesrv_alter(struct dcesrv_call_state
*call
)
775 struct ncacn_packet pkt
;
776 struct data_blob_list_item
*rep
;
778 uint32_t result
=0, reason
=0;
781 /* handle any authentication that is being requested */
782 if (!dcesrv_auth_alter(call
)) {
783 /* TODO: work out the right reject code */
784 result
= DCERPC_BIND_PROVIDER_REJECT
;
785 reason
= DCERPC_BIND_REASON_ASYNTAX
;
788 context_id
= call
->pkt
.u
.alter
.ctx_list
[0].context_id
;
790 /* see if they are asking for a new interface */
792 call
->context
= dcesrv_find_context(call
->conn
, context_id
);
793 if (!call
->context
) {
794 status
= dcesrv_alter_new_context(call
, context_id
);
795 if (!NT_STATUS_IS_OK(status
)) {
796 result
= DCERPC_BIND_PROVIDER_REJECT
;
797 reason
= DCERPC_BIND_REASON_ASYNTAX
;
803 call
->pkt
.u
.alter
.assoc_group_id
!= 0 &&
804 lpcfg_parm_bool(call
->conn
->dce_ctx
->lp_ctx
, NULL
, "dcesrv","assoc group checking", true) &&
805 call
->pkt
.u
.alter
.assoc_group_id
!= call
->context
->assoc_group
->id
) {
806 DEBUG(0,(__location__
": Failed attempt to use new assoc_group in alter context (0x%08x 0x%08x)\n",
807 call
->context
->assoc_group
->id
, call
->pkt
.u
.alter
.assoc_group_id
));
808 /* TODO: can they ask for a new association group? */
809 result
= DCERPC_BIND_PROVIDER_REJECT
;
810 reason
= DCERPC_BIND_REASON_ASYNTAX
;
813 /* setup a alter_resp */
814 dcesrv_init_hdr(&pkt
, lpcfg_rpc_big_endian(call
->conn
->dce_ctx
->lp_ctx
));
816 pkt
.call_id
= call
->pkt
.call_id
;
817 pkt
.ptype
= DCERPC_PKT_ALTER_RESP
;
818 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
819 pkt
.u
.alter_resp
.max_xmit_frag
= 0x2000;
820 pkt
.u
.alter_resp
.max_recv_frag
= 0x2000;
822 pkt
.u
.alter_resp
.assoc_group_id
= call
->context
->assoc_group
->id
;
824 pkt
.u
.alter_resp
.assoc_group_id
= 0;
826 pkt
.u
.alter_resp
.num_results
= 1;
827 pkt
.u
.alter_resp
.ctx_list
= talloc_array(call
, struct dcerpc_ack_ctx
, 1);
828 if (!pkt
.u
.alter_resp
.ctx_list
) {
829 return NT_STATUS_NO_MEMORY
;
831 pkt
.u
.alter_resp
.ctx_list
[0].result
= result
;
832 pkt
.u
.alter_resp
.ctx_list
[0].reason
.value
= reason
;
833 pkt
.u
.alter_resp
.ctx_list
[0].syntax
= ndr_transfer_syntax_ndr
;
834 pkt
.u
.alter_resp
.auth_info
= data_blob(NULL
, 0);
835 pkt
.u
.alter_resp
.secondary_address
= "";
837 status
= dcesrv_auth_alter_ack(call
, &pkt
);
838 if (!NT_STATUS_IS_OK(status
)) {
839 if (NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)
840 || NT_STATUS_EQUAL(status
, NT_STATUS_LOGON_FAILURE
)
841 || NT_STATUS_EQUAL(status
, NT_STATUS_NO_SUCH_USER
)
842 || NT_STATUS_EQUAL(status
, NT_STATUS_WRONG_PASSWORD
)) {
843 return dcesrv_fault(call
, DCERPC_FAULT_ACCESS_DENIED
);
845 return dcesrv_fault(call
, 0);
848 rep
= talloc(call
, struct data_blob_list_item
);
850 return NT_STATUS_NO_MEMORY
;
853 status
= ncacn_push_auth(&rep
->blob
, call
, &pkt
, call
->conn
->auth_state
.auth_info
);
854 if (!NT_STATUS_IS_OK(status
)) {
858 dcerpc_set_frag_length(&rep
->blob
, rep
->blob
.length
);
860 DLIST_ADD_END(call
->replies
, rep
, struct data_blob_list_item
*);
861 dcesrv_call_set_list(call
, DCESRV_LIST_CALL_LIST
);
863 if (call
->conn
->call_list
&& call
->conn
->call_list
->replies
) {
864 if (call
->conn
->transport
.report_output_data
) {
865 call
->conn
->transport
.report_output_data(call
->conn
);
873 possibly save the call for inspection with ndrdump
875 static void dcesrv_save_call(struct dcesrv_call_state
*call
, const char *why
)
879 const char *dump_dir
;
880 dump_dir
= lpcfg_parm_string(call
->conn
->dce_ctx
->lp_ctx
, NULL
, "dcesrv", "stubs directory");
884 fname
= talloc_asprintf(call
, "%s/RPC-%s-%u-%s.dat",
886 call
->context
->iface
->name
,
887 call
->pkt
.u
.request
.opnum
,
889 if (file_save(fname
, call
->pkt
.u
.request
.stub_and_verifier
.data
, call
->pkt
.u
.request
.stub_and_verifier
.length
)) {
890 DEBUG(0,("RPC SAVED %s\n", fname
));
897 handle a dcerpc request packet
899 static NTSTATUS
dcesrv_request(struct dcesrv_call_state
*call
)
901 struct ndr_pull
*pull
;
903 struct dcesrv_connection_context
*context
;
905 /* if authenticated, and the mech we use can't do async replies, don't use them... */
906 if (call
->conn
->auth_state
.gensec_security
&&
907 !gensec_have_feature(call
->conn
->auth_state
.gensec_security
, GENSEC_FEATURE_ASYNC_REPLIES
)) {
908 call
->state_flags
&= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC
;
911 context
= dcesrv_find_context(call
->conn
, call
->pkt
.u
.request
.context_id
);
912 if (context
== NULL
) {
913 return dcesrv_fault(call
, DCERPC_FAULT_UNK_IF
);
916 pull
= ndr_pull_init_blob(&call
->pkt
.u
.request
.stub_and_verifier
, call
);
917 NT_STATUS_HAVE_NO_MEMORY(pull
);
919 pull
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
921 call
->context
= context
;
922 call
->ndr_pull
= pull
;
924 if (!(call
->pkt
.drep
[0] & DCERPC_DREP_LE
)) {
925 pull
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
928 /* unravel the NDR for the packet */
929 status
= context
->iface
->ndr_pull(call
, call
, pull
, &call
->r
);
930 if (!NT_STATUS_IS_OK(status
)) {
931 if (call
->fault_code
== DCERPC_FAULT_OP_RNG_ERROR
) {
932 /* we got an unknown call */
933 DEBUG(3,(__location__
": Unknown RPC call %u on %s\n",
934 call
->pkt
.u
.request
.opnum
, context
->iface
->name
));
935 dcesrv_save_call(call
, "unknown");
937 dcesrv_save_call(call
, "pullfail");
939 return dcesrv_fault(call
, call
->fault_code
);
942 if (pull
->offset
!= pull
->data_size
) {
943 dcesrv_save_call(call
, "extrabytes");
944 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
945 pull
->data_size
- pull
->offset
));
948 /* call the dispatch function */
949 status
= context
->iface
->dispatch(call
, call
, call
->r
);
950 if (!NT_STATUS_IS_OK(status
)) {
951 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
952 context
->iface
->name
,
953 call
->pkt
.u
.request
.opnum
,
954 dcerpc_errstr(pull
, call
->fault_code
)));
955 return dcesrv_fault(call
, call
->fault_code
);
958 /* add the call to the pending list */
959 dcesrv_call_set_list(call
, DCESRV_LIST_PENDING_CALL_LIST
);
961 if (call
->state_flags
& DCESRV_CALL_STATE_FLAG_ASYNC
) {
965 return dcesrv_reply(call
);
970 remove the call from the right list when freed
972 static int dcesrv_call_dequeue(struct dcesrv_call_state
*call
)
974 dcesrv_call_set_list(call
, DCESRV_LIST_NONE
);
978 _PUBLIC_
const struct tsocket_address
*dcesrv_connection_get_local_address(struct dcesrv_connection
*conn
)
980 return conn
->local_address
;
983 _PUBLIC_
const struct tsocket_address
*dcesrv_connection_get_remote_address(struct dcesrv_connection
*conn
)
985 return conn
->remote_address
;
989 process some input to a dcerpc endpoint server.
991 NTSTATUS
dcesrv_process_ncacn_packet(struct dcesrv_connection
*dce_conn
,
992 struct ncacn_packet
*pkt
,
996 struct dcesrv_call_state
*call
;
998 call
= talloc_zero(dce_conn
, struct dcesrv_call_state
);
1000 data_blob_free(&blob
);
1002 return NT_STATUS_NO_MEMORY
;
1004 call
->conn
= dce_conn
;
1005 call
->event_ctx
= dce_conn
->event_ctx
;
1006 call
->msg_ctx
= dce_conn
->msg_ctx
;
1007 call
->state_flags
= call
->conn
->state_flags
;
1008 call
->time
= timeval_current();
1009 call
->list
= DCESRV_LIST_NONE
;
1011 talloc_steal(call
, pkt
);
1012 talloc_steal(call
, blob
.data
);
1015 talloc_set_destructor(call
, dcesrv_call_dequeue
);
1017 /* we have to check the signing here, before combining the
1019 if (call
->pkt
.ptype
== DCERPC_PKT_REQUEST
&&
1020 !dcesrv_auth_request(call
, &blob
)) {
1021 return dcesrv_fault(call
, DCERPC_FAULT_ACCESS_DENIED
);
1024 /* see if this is a continued packet */
1025 if (call
->pkt
.ptype
== DCERPC_PKT_REQUEST
&&
1026 !(call
->pkt
.pfc_flags
& DCERPC_PFC_FLAG_FIRST
)) {
1027 struct dcesrv_call_state
*call2
= call
;
1028 uint32_t alloc_size
;
1030 /* we only allow fragmented requests, no other packet types */
1031 if (call
->pkt
.ptype
!= DCERPC_PKT_REQUEST
) {
1032 return dcesrv_fault(call2
, DCERPC_FAULT_OTHER
);
1035 /* this is a continuation of an existing call - find the call
1036 then tack it on the end */
1037 call
= dcesrv_find_fragmented_call(dce_conn
, call2
->pkt
.call_id
);
1039 return dcesrv_fault(call2
, DCERPC_FAULT_OTHER
);
1042 if (call
->pkt
.ptype
!= call2
->pkt
.ptype
) {
1043 /* trying to play silly buggers are we? */
1044 return dcesrv_fault(call2
, DCERPC_FAULT_OTHER
);
1047 alloc_size
= call
->pkt
.u
.request
.stub_and_verifier
.length
+
1048 call2
->pkt
.u
.request
.stub_and_verifier
.length
;
1049 if (call
->pkt
.u
.request
.alloc_hint
> alloc_size
) {
1050 alloc_size
= call
->pkt
.u
.request
.alloc_hint
;
1053 call
->pkt
.u
.request
.stub_and_verifier
.data
=
1054 talloc_realloc(call
,
1055 call
->pkt
.u
.request
.stub_and_verifier
.data
,
1056 uint8_t, alloc_size
);
1057 if (!call
->pkt
.u
.request
.stub_and_verifier
.data
) {
1058 return dcesrv_fault(call2
, DCERPC_FAULT_OTHER
);
1060 memcpy(call
->pkt
.u
.request
.stub_and_verifier
.data
+
1061 call
->pkt
.u
.request
.stub_and_verifier
.length
,
1062 call2
->pkt
.u
.request
.stub_and_verifier
.data
,
1063 call2
->pkt
.u
.request
.stub_and_verifier
.length
);
1064 call
->pkt
.u
.request
.stub_and_verifier
.length
+=
1065 call2
->pkt
.u
.request
.stub_and_verifier
.length
;
1067 call
->pkt
.pfc_flags
|= (call2
->pkt
.pfc_flags
& DCERPC_PFC_FLAG_LAST
);
1072 /* this may not be the last pdu in the chain - if its isn't then
1073 just put it on the incoming_fragmented_call_list and wait for the rest */
1074 if (call
->pkt
.ptype
== DCERPC_PKT_REQUEST
&&
1075 !(call
->pkt
.pfc_flags
& DCERPC_PFC_FLAG_LAST
)) {
1076 dcesrv_call_set_list(call
, DCESRV_LIST_FRAGMENTED_CALL_LIST
);
1077 return NT_STATUS_OK
;
1080 /* This removes any fragments we may have had stashed away */
1081 dcesrv_call_set_list(call
, DCESRV_LIST_NONE
);
1083 switch (call
->pkt
.ptype
) {
1084 case DCERPC_PKT_BIND
:
1085 status
= dcesrv_bind(call
);
1087 case DCERPC_PKT_AUTH3
:
1088 status
= dcesrv_auth3(call
);
1090 case DCERPC_PKT_ALTER
:
1091 status
= dcesrv_alter(call
);
1093 case DCERPC_PKT_REQUEST
:
1094 status
= dcesrv_request(call
);
1097 status
= NT_STATUS_INVALID_PARAMETER
;
1101 /* if we are going to be sending a reply then add
1102 it to the list of pending calls. We add it to the end to keep the call
1103 list in the order we will answer */
1104 if (!NT_STATUS_IS_OK(status
)) {
1111 _PUBLIC_ NTSTATUS
dcesrv_init_context(TALLOC_CTX
*mem_ctx
,
1112 struct loadparm_context
*lp_ctx
,
1113 const char **endpoint_servers
, struct dcesrv_context
**_dce_ctx
)
1116 struct dcesrv_context
*dce_ctx
;
1119 if (!endpoint_servers
) {
1120 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1121 return NT_STATUS_INTERNAL_ERROR
;
1124 dce_ctx
= talloc(mem_ctx
, struct dcesrv_context
);
1125 NT_STATUS_HAVE_NO_MEMORY(dce_ctx
);
1126 dce_ctx
->endpoint_list
= NULL
;
1127 dce_ctx
->lp_ctx
= lp_ctx
;
1128 dce_ctx
->assoc_groups_idr
= idr_init(dce_ctx
);
1129 NT_STATUS_HAVE_NO_MEMORY(dce_ctx
->assoc_groups_idr
);
1130 dce_ctx
->broken_connections
= NULL
;
1132 for (i
=0;endpoint_servers
[i
];i
++) {
1133 const struct dcesrv_endpoint_server
*ep_server
;
1135 ep_server
= dcesrv_ep_server_byname(endpoint_servers
[i
]);
1137 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers
[i
]));
1138 return NT_STATUS_INTERNAL_ERROR
;
1141 status
= ep_server
->init_server(dce_ctx
, ep_server
);
1142 if (!NT_STATUS_IS_OK(status
)) {
1143 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers
[i
],
1144 nt_errstr(status
)));
1149 *_dce_ctx
= dce_ctx
;
1150 return NT_STATUS_OK
;
1153 /* the list of currently registered DCERPC endpoint servers.
1155 static struct ep_server
{
1156 struct dcesrv_endpoint_server
*ep_server
;
1157 } *ep_servers
= NULL
;
1158 static int num_ep_servers
;
1161 register a DCERPC endpoint server.
1163 The 'name' can be later used by other backends to find the operations
1164 structure for this backend.
1166 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1168 _PUBLIC_ NTSTATUS
dcerpc_register_ep_server(const void *_ep_server
)
1170 const struct dcesrv_endpoint_server
*ep_server
= _ep_server
;
1172 if (dcesrv_ep_server_byname(ep_server
->name
) != NULL
) {
1173 /* its already registered! */
1174 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1176 return NT_STATUS_OBJECT_NAME_COLLISION
;
1179 ep_servers
= realloc_p(ep_servers
, struct ep_server
, num_ep_servers
+1);
1181 smb_panic("out of memory in dcerpc_register");
1184 ep_servers
[num_ep_servers
].ep_server
= smb_xmemdup(ep_server
, sizeof(*ep_server
));
1185 ep_servers
[num_ep_servers
].ep_server
->name
= smb_xstrdup(ep_server
->name
);
1189 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1192 return NT_STATUS_OK
;
1196 return the operations structure for a named backend of the specified type
1198 const struct dcesrv_endpoint_server
*dcesrv_ep_server_byname(const char *name
)
1202 for (i
=0;i
<num_ep_servers
;i
++) {
1203 if (strcmp(ep_servers
[i
].ep_server
->name
, name
) == 0) {
1204 return ep_servers
[i
].ep_server
;
1211 void dcerpc_server_init(struct loadparm_context
*lp_ctx
)
1213 static bool initialized
;
1214 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
1215 STATIC_dcerpc_server_MODULES_PROTO
;
1216 init_module_fn static_init
[] = { STATIC_dcerpc_server_MODULES
};
1217 init_module_fn
*shared_init
;
1224 shared_init
= load_samba_modules(NULL
, "dcerpc_server");
1226 run_init_functions(static_init
);
1227 run_init_functions(shared_init
);
1229 talloc_free(shared_init
);
1233 return the DCERPC module version, and the size of some critical types
1234 This can be used by endpoint server modules to either detect compilation errors, or provide
1235 multiple implementations for different smbd compilation options in one module
1237 const struct dcesrv_critical_sizes
*dcerpc_module_version(void)
1239 static const struct dcesrv_critical_sizes critical_sizes
= {
1240 DCERPC_MODULE_VERSION
,
1241 sizeof(struct dcesrv_context
),
1242 sizeof(struct dcesrv_endpoint
),
1243 sizeof(struct dcesrv_endpoint_server
),
1244 sizeof(struct dcesrv_interface
),
1245 sizeof(struct dcesrv_if_list
),
1246 sizeof(struct dcesrv_connection
),
1247 sizeof(struct dcesrv_call_state
),
1248 sizeof(struct dcesrv_auth
),
1249 sizeof(struct dcesrv_handle
)
1252 return &critical_sizes
;
1255 static void dcesrv_terminate_connection(struct dcesrv_connection
*dce_conn
, const char *reason
)
1257 struct dcesrv_context
*dce_ctx
= dce_conn
->dce_ctx
;
1258 struct stream_connection
*srv_conn
;
1259 srv_conn
= talloc_get_type(dce_conn
->transport
.private_data
,
1260 struct stream_connection
);
1262 if (dce_conn
->pending_call_list
== NULL
) {
1263 char *full_reason
= talloc_asprintf(dce_conn
, "dcesrv: %s", reason
);
1265 DLIST_REMOVE(dce_ctx
->broken_connections
, dce_conn
);
1266 stream_terminate_connection(srv_conn
, full_reason
? full_reason
: reason
);
1270 if (dce_conn
->terminate
!= NULL
) {
1274 DEBUG(3,("dcesrv: terminating connection due to '%s' defered due to pending calls\n",
1276 dce_conn
->terminate
= talloc_strdup(dce_conn
, reason
);
1277 if (dce_conn
->terminate
== NULL
) {
1278 dce_conn
->terminate
= "dcesrv: defered terminating connection - no memory";
1280 DLIST_ADD_END(dce_ctx
->broken_connections
, dce_conn
, NULL
);
1283 static void dcesrv_cleanup_broken_connections(struct dcesrv_context
*dce_ctx
)
1285 struct dcesrv_connection
*cur
, *next
;
1287 next
= dce_ctx
->broken_connections
;
1288 while (next
!= NULL
) {
1292 dcesrv_terminate_connection(cur
, cur
->terminate
);
1296 /* We need this include to be able to compile on some plateforms
1297 * (ie. freebsd 7.2) as it seems that <sys/uio.h> is not included
1299 * It has to be that deep because otherwise we have a conflict on
1300 * const struct dcesrv_interface declaration.
1301 * This is mostly due to socket_wrapper defining #define bind swrap_bind
1302 * which conflict with the bind used before.
1304 #include "system/network.h"
1306 struct dcesrv_sock_reply_state
{
1307 struct dcesrv_connection
*dce_conn
;
1308 struct dcesrv_call_state
*call
;
1312 static void dcesrv_sock_reply_done(struct tevent_req
*subreq
);
1314 static void dcesrv_sock_report_output_data(struct dcesrv_connection
*dce_conn
)
1316 struct dcesrv_call_state
*call
;
1318 call
= dce_conn
->call_list
;
1319 if (!call
|| !call
->replies
) {
1323 while (call
->replies
) {
1324 struct data_blob_list_item
*rep
= call
->replies
;
1325 struct dcesrv_sock_reply_state
*substate
;
1326 struct tevent_req
*subreq
;
1328 substate
= talloc(call
, struct dcesrv_sock_reply_state
);
1330 dcesrv_terminate_connection(dce_conn
, "no memory");
1334 substate
->dce_conn
= dce_conn
;
1335 substate
->call
= NULL
;
1337 DLIST_REMOVE(call
->replies
, rep
);
1339 if (call
->replies
== NULL
) {
1340 substate
->call
= call
;
1343 substate
->iov
.iov_base
= (void *) rep
->blob
.data
;
1344 substate
->iov
.iov_len
= rep
->blob
.length
;
1346 subreq
= tstream_writev_queue_send(substate
,
1347 dce_conn
->event_ctx
,
1349 dce_conn
->send_queue
,
1352 dcesrv_terminate_connection(dce_conn
, "no memory");
1355 tevent_req_set_callback(subreq
, dcesrv_sock_reply_done
,
1359 DLIST_REMOVE(call
->conn
->call_list
, call
);
1360 call
->list
= DCESRV_LIST_NONE
;
1363 static void dcesrv_sock_reply_done(struct tevent_req
*subreq
)
1365 struct dcesrv_sock_reply_state
*substate
= tevent_req_callback_data(subreq
,
1366 struct dcesrv_sock_reply_state
);
1370 struct dcesrv_call_state
*call
= substate
->call
;
1372 ret
= tstream_writev_queue_recv(subreq
, &sys_errno
);
1373 TALLOC_FREE(subreq
);
1375 status
= map_nt_error_from_unix_common(sys_errno
);
1376 dcesrv_terminate_connection(substate
->dce_conn
, nt_errstr(status
));
1380 talloc_free(substate
);
1389 struct dcesrv_socket_context
{
1390 const struct dcesrv_endpoint
*endpoint
;
1391 struct dcesrv_context
*dcesrv_ctx
;
1395 static void dcesrv_read_fragment_done(struct tevent_req
*subreq
);
1397 static void dcesrv_sock_accept(struct stream_connection
*srv_conn
)
1400 struct dcesrv_socket_context
*dcesrv_sock
=
1401 talloc_get_type(srv_conn
->private_data
, struct dcesrv_socket_context
);
1402 struct dcesrv_connection
*dcesrv_conn
= NULL
;
1404 struct tevent_req
*subreq
;
1405 struct loadparm_context
*lp_ctx
= dcesrv_sock
->dcesrv_ctx
->lp_ctx
;
1407 dcesrv_cleanup_broken_connections(dcesrv_sock
->dcesrv_ctx
);
1409 if (!srv_conn
->session_info
) {
1410 status
= auth_anonymous_session_info(srv_conn
,
1412 &srv_conn
->session_info
);
1413 if (!NT_STATUS_IS_OK(status
)) {
1414 DEBUG(0,("dcesrv_sock_accept: auth_anonymous_session_info failed: %s\n",
1415 nt_errstr(status
)));
1416 stream_terminate_connection(srv_conn
, nt_errstr(status
));
1421 status
= dcesrv_endpoint_connect(dcesrv_sock
->dcesrv_ctx
,
1423 dcesrv_sock
->endpoint
,
1424 srv_conn
->session_info
,
1425 srv_conn
->event
.ctx
,
1427 srv_conn
->server_id
,
1428 DCESRV_CALL_STATE_FLAG_MAY_ASYNC
,
1430 if (!NT_STATUS_IS_OK(status
)) {
1431 DEBUG(0,("dcesrv_sock_accept: dcesrv_endpoint_connect failed: %s\n",
1432 nt_errstr(status
)));
1433 stream_terminate_connection(srv_conn
, nt_errstr(status
));
1437 dcesrv_conn
->transport
.private_data
= srv_conn
;
1438 dcesrv_conn
->transport
.report_output_data
= dcesrv_sock_report_output_data
;
1440 TALLOC_FREE(srv_conn
->event
.fde
);
1442 dcesrv_conn
->send_queue
= tevent_queue_create(dcesrv_conn
, "dcesrv send queue");
1443 if (!dcesrv_conn
->send_queue
) {
1444 status
= NT_STATUS_NO_MEMORY
;
1445 DEBUG(0,("dcesrv_sock_accept: tevent_queue_create(%s)\n",
1446 nt_errstr(status
)));
1447 stream_terminate_connection(srv_conn
, nt_errstr(status
));
1451 if (dcesrv_sock
->endpoint
->ep_description
->transport
== NCACN_NP
) {
1452 dcesrv_conn
->auth_state
.session_key
= dcesrv_inherited_session_key
;
1453 dcesrv_conn
->stream
= talloc_move(dcesrv_conn
,
1454 &srv_conn
->tstream
);
1456 ret
= tstream_bsd_existing_socket(dcesrv_conn
,
1457 socket_get_fd(srv_conn
->socket
),
1458 &dcesrv_conn
->stream
);
1460 status
= map_nt_error_from_unix_common(errno
);
1461 DEBUG(0, ("dcesrv_sock_accept: "
1462 "failed to setup tstream: %s\n",
1463 nt_errstr(status
)));
1464 stream_terminate_connection(srv_conn
, nt_errstr(status
));
1467 socket_set_flags(srv_conn
->socket
, SOCKET_FLAG_NOCLOSE
);
1470 dcesrv_conn
->local_address
= srv_conn
->local_address
;
1471 dcesrv_conn
->remote_address
= srv_conn
->remote_address
;
1473 srv_conn
->private_data
= dcesrv_conn
;
1475 irpc_add_name(srv_conn
->msg_ctx
, "rpc_server");
1477 subreq
= dcerpc_read_ncacn_packet_send(dcesrv_conn
,
1478 dcesrv_conn
->event_ctx
,
1479 dcesrv_conn
->stream
);
1481 status
= NT_STATUS_NO_MEMORY
;
1482 DEBUG(0,("dcesrv_sock_accept: dcerpc_read_fragment_buffer_send(%s)\n",
1483 nt_errstr(status
)));
1484 stream_terminate_connection(srv_conn
, nt_errstr(status
));
1487 tevent_req_set_callback(subreq
, dcesrv_read_fragment_done
, dcesrv_conn
);
1492 static void dcesrv_read_fragment_done(struct tevent_req
*subreq
)
1494 struct dcesrv_connection
*dce_conn
= tevent_req_callback_data(subreq
,
1495 struct dcesrv_connection
);
1496 struct dcesrv_context
*dce_ctx
= dce_conn
->dce_ctx
;
1497 struct ncacn_packet
*pkt
;
1501 if (dce_conn
->terminate
) {
1503 * if the current connection is broken
1504 * we need to clean it up before any other connection
1506 dcesrv_terminate_connection(dce_conn
, dce_conn
->terminate
);
1507 dcesrv_cleanup_broken_connections(dce_ctx
);
1511 dcesrv_cleanup_broken_connections(dce_ctx
);
1513 status
= dcerpc_read_ncacn_packet_recv(subreq
, dce_conn
,
1515 TALLOC_FREE(subreq
);
1516 if (!NT_STATUS_IS_OK(status
)) {
1517 dcesrv_terminate_connection(dce_conn
, nt_errstr(status
));
1521 status
= dcesrv_process_ncacn_packet(dce_conn
, pkt
, buffer
);
1522 if (!NT_STATUS_IS_OK(status
)) {
1523 dcesrv_terminate_connection(dce_conn
, nt_errstr(status
));
1527 subreq
= dcerpc_read_ncacn_packet_send(dce_conn
,
1528 dce_conn
->event_ctx
,
1531 status
= NT_STATUS_NO_MEMORY
;
1532 dcesrv_terminate_connection(dce_conn
, nt_errstr(status
));
1535 tevent_req_set_callback(subreq
, dcesrv_read_fragment_done
, dce_conn
);
1538 static void dcesrv_sock_recv(struct stream_connection
*conn
, uint16_t flags
)
1540 struct dcesrv_connection
*dce_conn
= talloc_get_type(conn
->private_data
,
1541 struct dcesrv_connection
);
1542 dcesrv_terminate_connection(dce_conn
, "dcesrv_sock_recv triggered");
1545 static void dcesrv_sock_send(struct stream_connection
*conn
, uint16_t flags
)
1547 struct dcesrv_connection
*dce_conn
= talloc_get_type(conn
->private_data
,
1548 struct dcesrv_connection
);
1549 dcesrv_terminate_connection(dce_conn
, "dcesrv_sock_send triggered");
1553 static const struct stream_server_ops dcesrv_stream_ops
= {
1555 .accept_connection
= dcesrv_sock_accept
,
1556 .recv_handler
= dcesrv_sock_recv
,
1557 .send_handler
= dcesrv_sock_send
,
1560 static NTSTATUS
dcesrv_add_ep_unix(struct dcesrv_context
*dce_ctx
,
1561 struct loadparm_context
*lp_ctx
,
1562 struct dcesrv_endpoint
*e
,
1563 struct tevent_context
*event_ctx
, const struct model_ops
*model_ops
)
1565 struct dcesrv_socket_context
*dcesrv_sock
;
1569 dcesrv_sock
= talloc(event_ctx
, struct dcesrv_socket_context
);
1570 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock
);
1572 /* remember the endpoint of this socket */
1573 dcesrv_sock
->endpoint
= e
;
1574 dcesrv_sock
->dcesrv_ctx
= talloc_reference(dcesrv_sock
, dce_ctx
);
1576 status
= stream_setup_socket(dcesrv_sock
, event_ctx
, lp_ctx
,
1577 model_ops
, &dcesrv_stream_ops
,
1578 "unix", e
->ep_description
->endpoint
, &port
,
1579 lpcfg_socket_options(lp_ctx
),
1581 if (!NT_STATUS_IS_OK(status
)) {
1582 DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n",
1583 e
->ep_description
->endpoint
, nt_errstr(status
)));
1589 static NTSTATUS
dcesrv_add_ep_ncalrpc(struct dcesrv_context
*dce_ctx
,
1590 struct loadparm_context
*lp_ctx
,
1591 struct dcesrv_endpoint
*e
,
1592 struct tevent_context
*event_ctx
, const struct model_ops
*model_ops
)
1594 struct dcesrv_socket_context
*dcesrv_sock
;
1599 if (!e
->ep_description
->endpoint
) {
1600 /* No identifier specified: use DEFAULT.
1601 * DO NOT hardcode this value anywhere else. Rather, specify
1602 * no endpoint and let the epmapper worry about it. */
1603 e
->ep_description
->endpoint
= talloc_strdup(dce_ctx
, "DEFAULT");
1606 full_path
= talloc_asprintf(dce_ctx
, "%s/%s", lpcfg_ncalrpc_dir(lp_ctx
),
1607 e
->ep_description
->endpoint
);
1609 dcesrv_sock
= talloc(event_ctx
, struct dcesrv_socket_context
);
1610 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock
);
1612 /* remember the endpoint of this socket */
1613 dcesrv_sock
->endpoint
= e
;
1614 dcesrv_sock
->dcesrv_ctx
= talloc_reference(dcesrv_sock
, dce_ctx
);
1616 status
= stream_setup_socket(dcesrv_sock
, event_ctx
, lp_ctx
,
1617 model_ops
, &dcesrv_stream_ops
,
1618 "unix", full_path
, &port
,
1619 lpcfg_socket_options(lp_ctx
),
1621 if (!NT_STATUS_IS_OK(status
)) {
1622 DEBUG(0,("service_setup_stream_socket(identifier=%s,path=%s) failed - %s\n",
1623 e
->ep_description
->endpoint
, full_path
, nt_errstr(status
)));
1628 static NTSTATUS
dcesrv_add_ep_np(struct dcesrv_context
*dce_ctx
,
1629 struct loadparm_context
*lp_ctx
,
1630 struct dcesrv_endpoint
*e
,
1631 struct tevent_context
*event_ctx
, const struct model_ops
*model_ops
)
1633 struct dcesrv_socket_context
*dcesrv_sock
;
1636 if (e
->ep_description
->endpoint
== NULL
) {
1637 DEBUG(0, ("Endpoint mandatory for named pipes\n"));
1638 return NT_STATUS_INVALID_PARAMETER
;
1641 dcesrv_sock
= talloc(event_ctx
, struct dcesrv_socket_context
);
1642 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock
);
1644 /* remember the endpoint of this socket */
1645 dcesrv_sock
->endpoint
= e
;
1646 dcesrv_sock
->dcesrv_ctx
= talloc_reference(dcesrv_sock
, dce_ctx
);
1648 status
= tstream_setup_named_pipe(dce_ctx
, event_ctx
, lp_ctx
,
1649 model_ops
, &dcesrv_stream_ops
,
1650 e
->ep_description
->endpoint
,
1652 if (!NT_STATUS_IS_OK(status
)) {
1653 DEBUG(0,("stream_setup_named_pipe(pipe=%s) failed - %s\n",
1654 e
->ep_description
->endpoint
, nt_errstr(status
)));
1658 return NT_STATUS_OK
;
1662 add a socket address to the list of events, one event per dcerpc endpoint
1664 static NTSTATUS
add_socket_rpc_tcp_iface(struct dcesrv_context
*dce_ctx
, struct dcesrv_endpoint
*e
,
1665 struct tevent_context
*event_ctx
, const struct model_ops
*model_ops
,
1666 const char *address
)
1668 struct dcesrv_socket_context
*dcesrv_sock
;
1672 if (e
->ep_description
->endpoint
) {
1673 port
= atoi(e
->ep_description
->endpoint
);
1676 dcesrv_sock
= talloc(event_ctx
, struct dcesrv_socket_context
);
1677 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock
);
1679 /* remember the endpoint of this socket */
1680 dcesrv_sock
->endpoint
= e
;
1681 dcesrv_sock
->dcesrv_ctx
= talloc_reference(dcesrv_sock
, dce_ctx
);
1683 status
= stream_setup_socket(dcesrv_sock
, event_ctx
, dce_ctx
->lp_ctx
,
1684 model_ops
, &dcesrv_stream_ops
,
1685 "ip", address
, &port
,
1686 lpcfg_socket_options(dce_ctx
->lp_ctx
),
1688 if (!NT_STATUS_IS_OK(status
)) {
1689 DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) failed - %s\n",
1690 address
, port
, nt_errstr(status
)));
1693 if (e
->ep_description
->endpoint
== NULL
) {
1694 e
->ep_description
->endpoint
= talloc_asprintf(dce_ctx
, "%d", port
);
1700 #include "lib/socket/netif.h" /* Included here to work around the fact that socket_wrapper redefines bind() */
1702 static NTSTATUS
dcesrv_add_ep_tcp(struct dcesrv_context
*dce_ctx
,
1703 struct loadparm_context
*lp_ctx
,
1704 struct dcesrv_endpoint
*e
,
1705 struct tevent_context
*event_ctx
, const struct model_ops
*model_ops
)
1709 /* Add TCP/IP sockets */
1710 if (lpcfg_interfaces(lp_ctx
) && lpcfg_bind_interfaces_only(lp_ctx
)) {
1713 struct interface
*ifaces
;
1715 load_interface_list(dce_ctx
, lp_ctx
, &ifaces
);
1717 num_interfaces
= iface_list_count(ifaces
);
1718 for(i
= 0; i
< num_interfaces
; i
++) {
1719 const char *address
= iface_list_n_ip(ifaces
, i
);
1720 status
= add_socket_rpc_tcp_iface(dce_ctx
, e
, event_ctx
, model_ops
, address
);
1721 NT_STATUS_NOT_OK_RETURN(status
);
1726 wcard
= iface_list_wildcard(dce_ctx
, lp_ctx
);
1727 NT_STATUS_HAVE_NO_MEMORY(wcard
);
1728 for (i
=0; wcard
[i
]; i
++) {
1729 status
= add_socket_rpc_tcp_iface(dce_ctx
, e
, event_ctx
, model_ops
, wcard
[i
]);
1730 NT_STATUS_NOT_OK_RETURN(status
);
1735 return NT_STATUS_OK
;
1738 NTSTATUS
dcesrv_add_ep(struct dcesrv_context
*dce_ctx
,
1739 struct loadparm_context
*lp_ctx
,
1740 struct dcesrv_endpoint
*e
,
1741 struct tevent_context
*event_ctx
,
1742 const struct model_ops
*model_ops
)
1744 switch (e
->ep_description
->transport
) {
1745 case NCACN_UNIX_STREAM
:
1746 return dcesrv_add_ep_unix(dce_ctx
, lp_ctx
, e
, event_ctx
, model_ops
);
1749 return dcesrv_add_ep_ncalrpc(dce_ctx
, lp_ctx
, e
, event_ctx
, model_ops
);
1752 return dcesrv_add_ep_tcp(dce_ctx
, lp_ctx
, e
, event_ctx
, model_ops
);
1755 return dcesrv_add_ep_np(dce_ctx
, lp_ctx
, e
, event_ctx
, model_ops
);
1758 return NT_STATUS_NOT_SUPPORTED
;
1764 * retrieve credentials from a dce_call
1766 _PUBLIC_
struct cli_credentials
*dcesrv_call_credentials(struct dcesrv_call_state
*dce_call
)
1768 return dce_call
->conn
->auth_state
.session_info
->credentials
;
1772 * returns true if this is an authenticated call
1774 _PUBLIC_
bool dcesrv_call_authenticated(struct dcesrv_call_state
*dce_call
)
1776 enum security_user_level level
;
1777 level
= security_session_user_level(dce_call
->conn
->auth_state
.session_info
, NULL
);
1778 return level
>= SECURITY_USER
;
1782 * retrieve account_name for a dce_call
1784 _PUBLIC_
const char *dcesrv_call_account_name(struct dcesrv_call_state
*dce_call
)
1786 return dce_call
->context
->conn
->auth_state
.session_info
->info
->account_name
;