ctdb-tests: Handle interactions with monitor events
[Samba.git] / source4 / rpc_server / dcerpc_server.c
blobbf91529ae1e792cd6a1a4db48f0a2a7a899e9bc7
1 /*
2 Unix SMB/CIFS implementation.
4 server side dcerpc core code
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) Stefan (metze) Metzmacher 2004-2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "auth/auth.h"
25 #include "auth/gensec/gensec.h"
26 #include "../lib/util/dlinklist.h"
27 #include "rpc_server/dcerpc_server.h"
28 #include "rpc_server/dcerpc_server_proto.h"
29 #include "rpc_server/common/proto.h"
30 #include "librpc/rpc/dcerpc_proto.h"
31 #include "system/filesys.h"
32 #include "libcli/security/security.h"
33 #include "param/param.h"
34 #include "../lib/tsocket/tsocket.h"
35 #include "../libcli/named_pipe_auth/npa_tstream.h"
36 #include "smbd/service_stream.h"
37 #include "../lib/tsocket/tsocket.h"
38 #include "lib/socket/socket.h"
39 #include "smbd/process_model.h"
40 #include "lib/messaging/irpc.h"
41 #include "librpc/rpc/rpc_common.h"
42 #include "lib/util/samba_modules.h"
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,
55 uint32_t id)
57 void *id_ptr;
59 id_ptr = idr_find(dce_ctx->assoc_groups_idr, id);
60 if (id_ptr == NULL) {
61 return NULL;
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,
71 uint32_t id)
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));
78 return NULL;
80 return talloc_reference(mem_ctx, assoc_group);
83 static int dcesrv_assoc_group_destructor(struct dcesrv_assoc_group *assoc_group)
85 int ret;
86 ret = idr_remove(assoc_group->dce_ctx->assoc_groups_idr, assoc_group->id);
87 if (ret != 0) {
88 DEBUG(0,(__location__ ": Failed to remove assoc_group 0x%08x\n",
89 assoc_group->id));
91 return 0;
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;
101 int id;
103 assoc_group = talloc_zero(mem_ctx, struct dcesrv_assoc_group);
104 if (assoc_group == NULL) {
105 return NULL;
108 id = idr_get_new_random(dce_ctx->assoc_groups_idr, assoc_group, UINT16_MAX);
109 if (id == -1) {
110 talloc_free(assoc_group);
111 DEBUG(0,(__location__ ": Out of association groups!\n"));
112 return NULL;
115 assoc_group->id = id;
116 assoc_group->dce_ctx = dce_ctx;
118 talloc_set_destructor(assoc_group, dcesrv_assoc_group_destructor);
120 return assoc_group;
125 see if two endpoints match
127 static bool endpoints_match(const struct dcerpc_binding *ep1,
128 const struct dcerpc_binding *ep2)
130 if (ep1->transport != ep2->transport) {
131 return false;
134 if (!ep1->endpoint || !ep2->endpoint) {
135 return ep1->endpoint == ep2->endpoint;
138 if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
139 return false;
141 return true;
145 find an endpoint in the dcesrv_context
147 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
148 const struct dcerpc_binding *ep_description)
150 struct dcesrv_endpoint *ep;
151 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
152 if (endpoints_match(ep->ep_description, ep_description)) {
153 return ep;
156 return NULL;
160 find a registered context_id from a bind or alter_context
162 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn,
163 uint32_t context_id)
165 struct dcesrv_connection_context *c;
166 for (c=conn->contexts;c;c=c->next) {
167 if (c->context_id == context_id) return c;
169 return NULL;
173 see if a uuid and if_version match to an interface
175 static bool interface_match(const struct dcesrv_interface *if1,
176 const struct dcesrv_interface *if2)
178 return (if1->syntax_id.if_version == if2->syntax_id.if_version &&
179 GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
183 find the interface operations on an endpoint
185 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
186 const struct dcesrv_interface *iface)
188 struct dcesrv_if_list *ifl;
189 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
190 if (interface_match(&(ifl->iface), iface)) {
191 return &(ifl->iface);
194 return NULL;
198 see if a uuid and if_version match to an interface
200 static bool interface_match_by_uuid(const struct dcesrv_interface *iface,
201 const struct GUID *uuid, uint32_t if_version)
203 return (iface->syntax_id.if_version == if_version &&
204 GUID_equal(&iface->syntax_id.uuid, uuid));
208 find the interface operations on an endpoint by uuid
210 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
211 const struct GUID *uuid, uint32_t if_version)
213 struct dcesrv_if_list *ifl;
214 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
215 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
216 return &(ifl->iface);
219 return NULL;
223 find the earlier parts of a fragmented call awaiting reassembily
225 static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
227 struct dcesrv_call_state *c;
228 for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
229 if (c->pkt.call_id == call_id) {
230 return c;
233 return NULL;
237 register an interface on an endpoint
239 _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
240 const char *ep_name,
241 const struct dcesrv_interface *iface,
242 const struct security_descriptor *sd)
244 struct dcesrv_endpoint *ep;
245 struct dcesrv_if_list *ifl;
246 struct dcerpc_binding *binding;
247 bool add_ep = false;
248 NTSTATUS status;
250 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
252 if (NT_STATUS_IS_ERR(status)) {
253 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
254 return status;
257 /* check if this endpoint exists
259 if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
260 ep = talloc(dce_ctx, struct dcesrv_endpoint);
261 if (!ep) {
262 return NT_STATUS_NO_MEMORY;
264 ZERO_STRUCTP(ep);
265 ep->ep_description = talloc_move(ep, &binding);
266 add_ep = true;
268 /* add mgmt interface */
269 ifl = talloc(ep, struct dcesrv_if_list);
270 if (!ifl) {
271 return NT_STATUS_NO_MEMORY;
274 memcpy(&(ifl->iface), &dcesrv_mgmt_interface,
275 sizeof(struct dcesrv_interface));
277 DLIST_ADD(ep->interface_list, ifl);
280 /* see if the interface is already registered on te endpoint */
281 if (find_interface(ep, iface)!=NULL) {
282 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
283 iface->name, ep_name));
284 return NT_STATUS_OBJECT_NAME_COLLISION;
287 /* talloc a new interface list element */
288 ifl = talloc(ep, struct dcesrv_if_list);
289 if (!ifl) {
290 return NT_STATUS_NO_MEMORY;
293 /* copy the given interface struct to the one on the endpoints interface list */
294 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
296 /* if we have a security descriptor given,
297 * we should see if we can set it up on the endpoint
299 if (sd != NULL) {
300 /* if there's currently no security descriptor given on the endpoint
301 * we try to set it
303 if (ep->sd == NULL) {
304 ep->sd = security_descriptor_copy(ep, sd);
307 /* if now there's no security descriptor given on the endpoint
308 * something goes wrong, either we failed to copy the security descriptor
309 * or there was already one on the endpoint
311 if (ep->sd != NULL) {
312 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
313 " on endpoint '%s'\n",
314 iface->name, ep_name));
315 if (add_ep) free(ep);
316 free(ifl);
317 return NT_STATUS_OBJECT_NAME_COLLISION;
321 /* finally add the interface on the endpoint */
322 DLIST_ADD(ep->interface_list, ifl);
324 /* if it's a new endpoint add it to the dcesrv_context */
325 if (add_ep) {
326 DLIST_ADD(dce_ctx->endpoint_list, ep);
329 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
330 iface->name, ep_name));
332 return NT_STATUS_OK;
335 NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
336 DATA_BLOB *session_key)
338 if (p->auth_state.session_info->session_key.length) {
339 *session_key = p->auth_state.session_info->session_key;
340 return NT_STATUS_OK;
342 return NT_STATUS_NO_USER_SESSION_KEY;
346 fetch the user session key - may be default (above) or the SMB session key
348 The key is always truncated to 16 bytes
350 _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
351 DATA_BLOB *session_key)
353 NTSTATUS status = p->auth_state.session_key(p, session_key);
354 if (!NT_STATUS_IS_OK(status)) {
355 return status;
358 session_key->length = MIN(session_key->length, 16);
360 return NT_STATUS_OK;
364 connect to a dcerpc endpoint
366 _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
367 TALLOC_CTX *mem_ctx,
368 const struct dcesrv_endpoint *ep,
369 struct auth_session_info *session_info,
370 struct tevent_context *event_ctx,
371 struct imessaging_context *msg_ctx,
372 struct server_id server_id,
373 uint32_t state_flags,
374 struct dcesrv_connection **_p)
376 struct dcesrv_connection *p;
378 if (!session_info) {
379 return NT_STATUS_ACCESS_DENIED;
382 p = talloc_zero(mem_ctx, struct dcesrv_connection);
383 NT_STATUS_HAVE_NO_MEMORY(p);
385 if (!talloc_reference(p, session_info)) {
386 talloc_free(p);
387 return NT_STATUS_NO_MEMORY;
390 p->dce_ctx = dce_ctx;
391 p->endpoint = ep;
392 p->packet_log_dir = lpcfg_lock_directory(dce_ctx->lp_ctx);
393 p->auth_state.session_info = session_info;
394 p->auth_state.session_key = dcesrv_generic_session_key;
395 p->event_ctx = event_ctx;
396 p->msg_ctx = msg_ctx;
397 p->server_id = server_id;
398 p->state_flags = state_flags;
400 *_p = p;
401 return NT_STATUS_OK;
405 move a call from an existing linked list to the specified list. This
406 prevents bugs where we forget to remove the call from a previous
407 list when moving it.
409 static void dcesrv_call_set_list(struct dcesrv_call_state *call,
410 enum dcesrv_call_list list)
412 switch (call->list) {
413 case DCESRV_LIST_NONE:
414 break;
415 case DCESRV_LIST_CALL_LIST:
416 DLIST_REMOVE(call->conn->call_list, call);
417 break;
418 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
419 DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
420 break;
421 case DCESRV_LIST_PENDING_CALL_LIST:
422 DLIST_REMOVE(call->conn->pending_call_list, call);
423 break;
425 call->list = list;
426 switch (list) {
427 case DCESRV_LIST_NONE:
428 break;
429 case DCESRV_LIST_CALL_LIST:
430 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
431 break;
432 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
433 DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
434 break;
435 case DCESRV_LIST_PENDING_CALL_LIST:
436 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
437 break;
443 return a dcerpc bind_nak
445 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
447 struct ncacn_packet pkt;
448 struct data_blob_list_item *rep;
449 NTSTATUS status;
451 /* setup a bind_nak */
452 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
453 pkt.auth_length = 0;
454 pkt.call_id = call->pkt.call_id;
455 pkt.ptype = DCERPC_PKT_BIND_NAK;
456 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
457 pkt.u.bind_nak.reject_reason = reason;
458 if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
459 pkt.u.bind_nak.versions.v.num_versions = 0;
462 rep = talloc(call, struct data_blob_list_item);
463 if (!rep) {
464 return NT_STATUS_NO_MEMORY;
467 status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
468 if (!NT_STATUS_IS_OK(status)) {
469 return status;
472 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
474 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
475 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
477 if (call->conn->call_list && call->conn->call_list->replies) {
478 if (call->conn->transport.report_output_data) {
479 call->conn->transport.report_output_data(call->conn);
483 return NT_STATUS_OK;
486 static int dcesrv_connection_context_destructor(struct dcesrv_connection_context *c)
488 DLIST_REMOVE(c->conn->contexts, c);
490 if (c->iface && c->iface->unbind) {
491 c->iface->unbind(c, c->iface);
494 return 0;
498 handle a bind request
500 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
502 uint32_t if_version, transfer_syntax_version;
503 struct GUID uuid, *transfer_syntax_uuid;
504 struct ncacn_packet pkt;
505 struct data_blob_list_item *rep;
506 NTSTATUS status;
507 uint32_t result=0, reason=0;
508 uint32_t context_id;
509 const struct dcesrv_interface *iface;
510 uint32_t extra_flags = 0;
513 if provided, check the assoc_group is valid
515 if (call->pkt.u.bind.assoc_group_id != 0 &&
516 lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
517 dcesrv_assoc_group_find(call->conn->dce_ctx, call->pkt.u.bind.assoc_group_id) == NULL) {
518 return dcesrv_bind_nak(call, 0);
521 if (call->pkt.u.bind.num_contexts < 1 ||
522 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
523 return dcesrv_bind_nak(call, 0);
526 context_id = call->pkt.u.bind.ctx_list[0].context_id;
528 /* you can't bind twice on one context */
529 if (dcesrv_find_context(call->conn, context_id) != NULL) {
530 return dcesrv_bind_nak(call, 0);
533 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
534 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
536 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
537 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
538 if (!GUID_equal(&ndr_transfer_syntax_ndr.uuid, transfer_syntax_uuid) != 0 ||
539 ndr_transfer_syntax_ndr.if_version != transfer_syntax_version) {
540 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
541 /* we only do NDR encoded dcerpc */
542 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
543 talloc_free(uuid_str);
544 return dcesrv_bind_nak(call, 0);
547 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
548 if (iface == NULL) {
549 char *uuid_str = GUID_string(call, &uuid);
550 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
551 talloc_free(uuid_str);
553 /* we don't know about that interface */
554 result = DCERPC_BIND_PROVIDER_REJECT;
555 reason = DCERPC_BIND_REASON_ASYNTAX;
558 if (iface) {
559 /* add this context to the list of available context_ids */
560 struct dcesrv_connection_context *context = talloc(call->conn,
561 struct dcesrv_connection_context);
562 if (context == NULL) {
563 return dcesrv_bind_nak(call, 0);
565 context->conn = call->conn;
566 context->iface = iface;
567 context->context_id = context_id;
568 if (call->pkt.u.bind.assoc_group_id != 0) {
569 context->assoc_group = dcesrv_assoc_group_reference(context,
570 call->conn->dce_ctx,
571 call->pkt.u.bind.assoc_group_id);
572 } else {
573 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
575 if (context->assoc_group == NULL) {
576 talloc_free(context);
577 return dcesrv_bind_nak(call, 0);
579 context->private_data = NULL;
580 DLIST_ADD(call->conn->contexts, context);
581 call->context = context;
582 talloc_set_destructor(context, dcesrv_connection_context_destructor);
584 status = iface->bind(call, iface, if_version);
585 if (!NT_STATUS_IS_OK(status)) {
586 char *uuid_str = GUID_string(call, &uuid);
587 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
588 uuid_str, if_version, nt_errstr(status)));
589 talloc_free(uuid_str);
590 /* we don't want to trigger the iface->unbind() hook */
591 context->iface = NULL;
592 talloc_free(call->context);
593 call->context = NULL;
594 return dcesrv_bind_nak(call, 0);
598 if (call->conn->cli_max_recv_frag == 0) {
599 call->conn->cli_max_recv_frag = MIN(0x2000, call->pkt.u.bind.max_recv_frag);
602 /* handle any authentication that is being requested */
603 if (!dcesrv_auth_bind(call)) {
604 talloc_free(call->context);
605 call->context = NULL;
606 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
609 /* setup a bind_ack */
610 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
611 pkt.auth_length = 0;
612 pkt.call_id = call->pkt.call_id;
613 pkt.ptype = DCERPC_PKT_BIND_ACK;
614 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
615 pkt.u.bind_ack.max_xmit_frag = call->conn->cli_max_recv_frag;
616 pkt.u.bind_ack.max_recv_frag = 0x2000;
619 make it possible for iface->bind() to specify the assoc_group_id
620 This helps the openchange mapiproxy plugin to work correctly.
622 metze
624 if (call->context) {
625 pkt.u.bind_ack.assoc_group_id = call->context->assoc_group->id;
626 } else {
627 pkt.u.bind_ack.assoc_group_id = DUMMY_ASSOC_GROUP;
630 if (iface) {
631 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
632 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
633 } else {
634 pkt.u.bind_ack.secondary_address = "";
636 pkt.u.bind_ack.num_results = 1;
637 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
638 if (!pkt.u.bind_ack.ctx_list) {
639 talloc_free(call->context);
640 call->context = NULL;
641 return NT_STATUS_NO_MEMORY;
643 pkt.u.bind_ack.ctx_list[0].result = result;
644 pkt.u.bind_ack.ctx_list[0].reason.value = reason;
645 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax_ndr;
646 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
648 status = dcesrv_auth_bind_ack(call, &pkt);
649 if (!NT_STATUS_IS_OK(status)) {
650 talloc_free(call->context);
651 call->context = NULL;
652 return dcesrv_bind_nak(call, 0);
655 rep = talloc(call, struct data_blob_list_item);
656 if (!rep) {
657 talloc_free(call->context);
658 call->context = NULL;
659 return NT_STATUS_NO_MEMORY;
662 status = ncacn_push_auth(&rep->blob, call, &pkt,
663 call->conn->auth_state.auth_info);
664 if (!NT_STATUS_IS_OK(status)) {
665 talloc_free(call->context);
666 call->context = NULL;
667 return status;
670 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
672 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
673 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
675 if (call->conn->call_list && call->conn->call_list->replies) {
676 if (call->conn->transport.report_output_data) {
677 call->conn->transport.report_output_data(call->conn);
681 return NT_STATUS_OK;
686 handle a auth3 request
688 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
690 /* handle the auth3 in the auth code */
691 if (!dcesrv_auth_auth3(call)) {
692 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
695 talloc_free(call);
697 /* we don't send a reply to a auth3 request, except by a
698 fault */
699 return NT_STATUS_OK;
704 handle a bind request
706 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
708 uint32_t if_version, transfer_syntax_version;
709 struct dcesrv_connection_context *context;
710 const struct dcesrv_interface *iface;
711 struct GUID uuid, *transfer_syntax_uuid;
712 NTSTATUS status;
714 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
715 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
717 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
718 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
719 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax_ndr.uuid) ||
720 ndr_transfer_syntax_ndr.if_version != transfer_syntax_version) {
721 /* we only do NDR encoded dcerpc */
722 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
725 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
726 if (iface == NULL) {
727 char *uuid_str = GUID_string(call, &uuid);
728 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
729 talloc_free(uuid_str);
730 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
733 /* add this context to the list of available context_ids */
734 context = talloc(call->conn, struct dcesrv_connection_context);
735 if (context == NULL) {
736 return NT_STATUS_NO_MEMORY;
738 context->conn = call->conn;
739 context->iface = iface;
740 context->context_id = context_id;
741 if (call->pkt.u.alter.assoc_group_id != 0) {
742 context->assoc_group = dcesrv_assoc_group_reference(context,
743 call->conn->dce_ctx,
744 call->pkt.u.alter.assoc_group_id);
745 } else {
746 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
748 if (context->assoc_group == NULL) {
749 talloc_free(context);
750 call->context = NULL;
751 return NT_STATUS_NO_MEMORY;
753 context->private_data = NULL;
754 DLIST_ADD(call->conn->contexts, context);
755 call->context = context;
756 talloc_set_destructor(context, dcesrv_connection_context_destructor);
758 status = iface->bind(call, iface, if_version);
759 if (!NT_STATUS_IS_OK(status)) {
760 /* we don't want to trigger the iface->unbind() hook */
761 context->iface = NULL;
762 talloc_free(context);
763 call->context = NULL;
764 return status;
767 return NT_STATUS_OK;
772 handle a alter context request
774 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
776 struct ncacn_packet pkt;
777 struct data_blob_list_item *rep;
778 NTSTATUS status;
779 uint32_t result=0, reason=0;
780 uint32_t context_id;
782 /* handle any authentication that is being requested */
783 if (!dcesrv_auth_alter(call)) {
784 /* TODO: work out the right reject code */
785 result = DCERPC_BIND_PROVIDER_REJECT;
786 reason = DCERPC_BIND_REASON_ASYNTAX;
789 context_id = call->pkt.u.alter.ctx_list[0].context_id;
791 /* see if they are asking for a new interface */
792 if (result == 0) {
793 call->context = dcesrv_find_context(call->conn, context_id);
794 if (!call->context) {
795 status = dcesrv_alter_new_context(call, context_id);
796 if (!NT_STATUS_IS_OK(status)) {
797 result = DCERPC_BIND_PROVIDER_REJECT;
798 reason = DCERPC_BIND_REASON_ASYNTAX;
803 if (result == 0 &&
804 call->pkt.u.alter.assoc_group_id != 0 &&
805 lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
806 call->pkt.u.alter.assoc_group_id != call->context->assoc_group->id) {
807 DEBUG(0,(__location__ ": Failed attempt to use new assoc_group in alter context (0x%08x 0x%08x)\n",
808 call->context->assoc_group->id, call->pkt.u.alter.assoc_group_id));
809 /* TODO: can they ask for a new association group? */
810 result = DCERPC_BIND_PROVIDER_REJECT;
811 reason = DCERPC_BIND_REASON_ASYNTAX;
814 /* setup a alter_resp */
815 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
816 pkt.auth_length = 0;
817 pkt.call_id = call->pkt.call_id;
818 pkt.ptype = DCERPC_PKT_ALTER_RESP;
819 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
820 pkt.u.alter_resp.max_xmit_frag = 0x2000;
821 pkt.u.alter_resp.max_recv_frag = 0x2000;
822 if (result == 0) {
823 pkt.u.alter_resp.assoc_group_id = call->context->assoc_group->id;
824 } else {
825 pkt.u.alter_resp.assoc_group_id = 0;
827 pkt.u.alter_resp.num_results = 1;
828 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
829 if (!pkt.u.alter_resp.ctx_list) {
830 return NT_STATUS_NO_MEMORY;
832 pkt.u.alter_resp.ctx_list[0].result = result;
833 pkt.u.alter_resp.ctx_list[0].reason.value = reason;
834 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax_ndr;
835 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
836 pkt.u.alter_resp.secondary_address = "";
838 status = dcesrv_auth_alter_ack(call, &pkt);
839 if (!NT_STATUS_IS_OK(status)) {
840 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
841 || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
842 || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
843 || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
844 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
846 return dcesrv_fault(call, 0);
849 rep = talloc(call, struct data_blob_list_item);
850 if (!rep) {
851 return NT_STATUS_NO_MEMORY;
854 status = ncacn_push_auth(&rep->blob, call, &pkt, call->conn->auth_state.auth_info);
855 if (!NT_STATUS_IS_OK(status)) {
856 return status;
859 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
861 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
862 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
864 if (call->conn->call_list && call->conn->call_list->replies) {
865 if (call->conn->transport.report_output_data) {
866 call->conn->transport.report_output_data(call->conn);
870 return NT_STATUS_OK;
874 possibly save the call for inspection with ndrdump
876 static void dcesrv_save_call(struct dcesrv_call_state *call, const char *why)
878 #ifdef DEVELOPER
879 char *fname;
880 const char *dump_dir;
881 dump_dir = lpcfg_parm_string(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv", "stubs directory");
882 if (!dump_dir) {
883 return;
885 fname = talloc_asprintf(call, "%s/RPC-%s-%u-%s.dat",
886 dump_dir,
887 call->context->iface->name,
888 call->pkt.u.request.opnum,
889 why);
890 if (file_save(fname, call->pkt.u.request.stub_and_verifier.data, call->pkt.u.request.stub_and_verifier.length)) {
891 DEBUG(0,("RPC SAVED %s\n", fname));
893 talloc_free(fname);
894 #endif
897 static NTSTATUS dcesrv_check_verification_trailer(struct dcesrv_call_state *call)
899 TALLOC_CTX *frame = talloc_stackframe();
900 const uint32_t bitmask1 = call->conn->auth_state.client_hdr_signing ?
901 DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING : 0;
902 const struct dcerpc_sec_vt_pcontext pcontext = {
903 .abstract_syntax = call->context->iface->syntax_id,
904 .transfer_syntax = ndr_transfer_syntax_ndr,
906 const struct dcerpc_sec_vt_header2 header2 =
907 dcerpc_sec_vt_header2_from_ncacn_packet(&call->pkt);
908 enum ndr_err_code ndr_err;
909 struct dcerpc_sec_verification_trailer *vt = NULL;
910 NTSTATUS status = NT_STATUS_OK;
911 bool ok;
913 SMB_ASSERT(call->pkt.ptype == DCERPC_PKT_REQUEST);
915 ndr_err = ndr_pop_dcerpc_sec_verification_trailer(call->ndr_pull,
916 frame, &vt);
917 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
918 status = ndr_map_error2ntstatus(ndr_err);
919 goto done;
922 ok = dcerpc_sec_verification_trailer_check(vt, &bitmask1,
923 &pcontext, &header2);
924 if (!ok) {
925 status = NT_STATUS_ACCESS_DENIED;
926 goto done;
928 done:
929 TALLOC_FREE(frame);
930 return status;
934 handle a dcerpc request packet
936 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
938 struct ndr_pull *pull;
939 NTSTATUS status;
940 struct dcesrv_connection_context *context;
942 /* if authenticated, and the mech we use can't do async replies, don't use them... */
943 if (call->conn->auth_state.gensec_security &&
944 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
945 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
948 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
949 if (context == NULL) {
950 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
953 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
954 NT_STATUS_HAVE_NO_MEMORY(pull);
956 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
958 call->context = context;
959 call->ndr_pull = pull;
961 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
962 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
965 status = dcesrv_check_verification_trailer(call);
966 if (!NT_STATUS_IS_OK(status)) {
967 uint32_t faultcode = DCERPC_FAULT_OTHER;
968 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
969 faultcode = DCERPC_FAULT_ACCESS_DENIED;
971 DEBUG(10, ("dcesrv_check_verification_trailer failed: %s\n",
972 nt_errstr(status)));
973 return dcesrv_fault(call, faultcode);
976 /* unravel the NDR for the packet */
977 status = context->iface->ndr_pull(call, call, pull, &call->r);
978 if (!NT_STATUS_IS_OK(status)) {
979 if (call->fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
980 /* we got an unknown call */
981 DEBUG(3,(__location__ ": Unknown RPC call %u on %s\n",
982 call->pkt.u.request.opnum, context->iface->name));
983 dcesrv_save_call(call, "unknown");
984 } else {
985 dcesrv_save_call(call, "pullfail");
987 return dcesrv_fault(call, call->fault_code);
990 if (pull->offset != pull->data_size) {
991 dcesrv_save_call(call, "extrabytes");
992 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
993 pull->data_size - pull->offset));
996 /* call the dispatch function */
997 status = context->iface->dispatch(call, call, call->r);
998 if (!NT_STATUS_IS_OK(status)) {
999 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
1000 context->iface->name,
1001 call->pkt.u.request.opnum,
1002 dcerpc_errstr(pull, call->fault_code)));
1003 return dcesrv_fault(call, call->fault_code);
1006 /* add the call to the pending list */
1007 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
1009 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
1010 return NT_STATUS_OK;
1013 return dcesrv_reply(call);
1018 remove the call from the right list when freed
1020 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1022 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1023 return 0;
1026 _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_local_address(struct dcesrv_connection *conn)
1028 return conn->local_address;
1031 _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_remote_address(struct dcesrv_connection *conn)
1033 return conn->remote_address;
1037 process some input to a dcerpc endpoint server.
1039 NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
1040 struct ncacn_packet *pkt,
1041 DATA_BLOB blob)
1043 NTSTATUS status;
1044 struct dcesrv_call_state *call;
1046 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1047 if (!call) {
1048 data_blob_free(&blob);
1049 talloc_free(pkt);
1050 return NT_STATUS_NO_MEMORY;
1052 call->conn = dce_conn;
1053 call->event_ctx = dce_conn->event_ctx;
1054 call->msg_ctx = dce_conn->msg_ctx;
1055 call->state_flags = call->conn->state_flags;
1056 call->time = timeval_current();
1057 call->list = DCESRV_LIST_NONE;
1059 talloc_steal(call, pkt);
1060 talloc_steal(call, blob.data);
1061 call->pkt = *pkt;
1063 talloc_set_destructor(call, dcesrv_call_dequeue);
1065 /* we have to check the signing here, before combining the
1066 pdus */
1067 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1068 !dcesrv_auth_request(call, &blob)) {
1069 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1072 /* see if this is a continued packet */
1073 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1074 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1075 struct dcesrv_call_state *call2 = call;
1076 uint32_t alloc_size;
1078 /* we only allow fragmented requests, no other packet types */
1079 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1080 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1083 /* this is a continuation of an existing call - find the call
1084 then tack it on the end */
1085 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1086 if (!call) {
1087 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1090 if (call->pkt.ptype != call2->pkt.ptype) {
1091 /* trying to play silly buggers are we? */
1092 return dcesrv_fault(call2, DCERPC_NCA_S_PROTO_ERROR);
1094 if (memcmp(call->pkt.drep, call2->pkt.drep, sizeof(pkt->drep)) != 0) {
1095 return dcesrv_fault(call2, DCERPC_NCA_S_PROTO_ERROR);
1097 if (call->pkt.call_id != call2->pkt.call_id) {
1098 return dcesrv_fault(call2, DCERPC_NCA_S_PROTO_ERROR);
1100 if (call->pkt.u.request.context_id != call2->pkt.u.request.context_id) {
1101 return dcesrv_fault(call2, DCERPC_NCA_S_PROTO_ERROR);
1103 if (call->pkt.u.request.opnum != call2->pkt.u.request.opnum) {
1104 return dcesrv_fault(call2, DCERPC_NCA_S_PROTO_ERROR);
1107 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1108 call2->pkt.u.request.stub_and_verifier.length;
1109 if (call->pkt.u.request.alloc_hint > alloc_size) {
1110 alloc_size = call->pkt.u.request.alloc_hint;
1113 call->pkt.u.request.stub_and_verifier.data =
1114 talloc_realloc(call,
1115 call->pkt.u.request.stub_and_verifier.data,
1116 uint8_t, alloc_size);
1117 if (!call->pkt.u.request.stub_and_verifier.data) {
1118 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1120 memcpy(call->pkt.u.request.stub_and_verifier.data +
1121 call->pkt.u.request.stub_and_verifier.length,
1122 call2->pkt.u.request.stub_and_verifier.data,
1123 call2->pkt.u.request.stub_and_verifier.length);
1124 call->pkt.u.request.stub_and_verifier.length +=
1125 call2->pkt.u.request.stub_and_verifier.length;
1127 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1129 talloc_free(call2);
1132 /* this may not be the last pdu in the chain - if its isn't then
1133 just put it on the incoming_fragmented_call_list and wait for the rest */
1134 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1135 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1136 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1137 return NT_STATUS_OK;
1140 /* This removes any fragments we may have had stashed away */
1141 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1143 switch (call->pkt.ptype) {
1144 case DCERPC_PKT_BIND:
1145 status = dcesrv_bind(call);
1146 break;
1147 case DCERPC_PKT_AUTH3:
1148 status = dcesrv_auth3(call);
1149 break;
1150 case DCERPC_PKT_ALTER:
1151 status = dcesrv_alter(call);
1152 break;
1153 case DCERPC_PKT_REQUEST:
1154 status = dcesrv_request(call);
1155 break;
1156 default:
1157 status = NT_STATUS_INVALID_PARAMETER;
1158 break;
1161 /* if we are going to be sending a reply then add
1162 it to the list of pending calls. We add it to the end to keep the call
1163 list in the order we will answer */
1164 if (!NT_STATUS_IS_OK(status)) {
1165 talloc_free(call);
1168 return status;
1171 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1172 struct loadparm_context *lp_ctx,
1173 const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1175 NTSTATUS status;
1176 struct dcesrv_context *dce_ctx;
1177 int i;
1179 if (!endpoint_servers) {
1180 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1181 return NT_STATUS_INTERNAL_ERROR;
1184 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1185 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1186 dce_ctx->endpoint_list = NULL;
1187 dce_ctx->lp_ctx = lp_ctx;
1188 dce_ctx->assoc_groups_idr = idr_init(dce_ctx);
1189 NT_STATUS_HAVE_NO_MEMORY(dce_ctx->assoc_groups_idr);
1190 dce_ctx->broken_connections = NULL;
1192 for (i=0;endpoint_servers[i];i++) {
1193 const struct dcesrv_endpoint_server *ep_server;
1195 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1196 if (!ep_server) {
1197 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1198 return NT_STATUS_INTERNAL_ERROR;
1201 status = ep_server->init_server(dce_ctx, ep_server);
1202 if (!NT_STATUS_IS_OK(status)) {
1203 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1204 nt_errstr(status)));
1205 return status;
1209 *_dce_ctx = dce_ctx;
1210 return NT_STATUS_OK;
1213 /* the list of currently registered DCERPC endpoint servers.
1215 static struct ep_server {
1216 struct dcesrv_endpoint_server *ep_server;
1217 } *ep_servers = NULL;
1218 static int num_ep_servers;
1221 register a DCERPC endpoint server.
1223 The 'name' can be later used by other backends to find the operations
1224 structure for this backend.
1226 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1228 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1230 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1232 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1233 /* its already registered! */
1234 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1235 ep_server->name));
1236 return NT_STATUS_OBJECT_NAME_COLLISION;
1239 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1240 if (!ep_servers) {
1241 smb_panic("out of memory in dcerpc_register");
1244 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1245 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1247 num_ep_servers++;
1249 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1250 ep_server->name));
1252 return NT_STATUS_OK;
1256 return the operations structure for a named backend of the specified type
1258 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1260 int i;
1262 for (i=0;i<num_ep_servers;i++) {
1263 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1264 return ep_servers[i].ep_server;
1268 return NULL;
1271 void dcerpc_server_init(struct loadparm_context *lp_ctx)
1273 static bool initialized;
1274 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
1275 STATIC_dcerpc_server_MODULES_PROTO;
1276 init_module_fn static_init[] = { STATIC_dcerpc_server_MODULES };
1277 init_module_fn *shared_init;
1279 if (initialized) {
1280 return;
1282 initialized = true;
1284 shared_init = load_samba_modules(NULL, "dcerpc_server");
1286 run_init_functions(static_init);
1287 run_init_functions(shared_init);
1289 talloc_free(shared_init);
1293 return the DCERPC module version, and the size of some critical types
1294 This can be used by endpoint server modules to either detect compilation errors, or provide
1295 multiple implementations for different smbd compilation options in one module
1297 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1299 static const struct dcesrv_critical_sizes critical_sizes = {
1300 DCERPC_MODULE_VERSION,
1301 sizeof(struct dcesrv_context),
1302 sizeof(struct dcesrv_endpoint),
1303 sizeof(struct dcesrv_endpoint_server),
1304 sizeof(struct dcesrv_interface),
1305 sizeof(struct dcesrv_if_list),
1306 sizeof(struct dcesrv_connection),
1307 sizeof(struct dcesrv_call_state),
1308 sizeof(struct dcesrv_auth),
1309 sizeof(struct dcesrv_handle)
1312 return &critical_sizes;
1315 static void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, const char *reason)
1317 struct dcesrv_context *dce_ctx = dce_conn->dce_ctx;
1318 struct stream_connection *srv_conn;
1319 srv_conn = talloc_get_type(dce_conn->transport.private_data,
1320 struct stream_connection);
1322 if (dce_conn->pending_call_list == NULL) {
1323 char *full_reason = talloc_asprintf(dce_conn, "dcesrv: %s", reason);
1325 DLIST_REMOVE(dce_ctx->broken_connections, dce_conn);
1326 stream_terminate_connection(srv_conn, full_reason ? full_reason : reason);
1327 return;
1330 if (dce_conn->terminate != NULL) {
1331 return;
1334 DEBUG(3,("dcesrv: terminating connection due to '%s' defered due to pending calls\n",
1335 reason));
1336 dce_conn->terminate = talloc_strdup(dce_conn, reason);
1337 if (dce_conn->terminate == NULL) {
1338 dce_conn->terminate = "dcesrv: defered terminating connection - no memory";
1340 DLIST_ADD_END(dce_ctx->broken_connections, dce_conn, NULL);
1343 static void dcesrv_cleanup_broken_connections(struct dcesrv_context *dce_ctx)
1345 struct dcesrv_connection *cur, *next;
1347 next = dce_ctx->broken_connections;
1348 while (next != NULL) {
1349 cur = next;
1350 next = cur->next;
1352 dcesrv_terminate_connection(cur, cur->terminate);
1356 /* We need this include to be able to compile on some plateforms
1357 * (ie. freebsd 7.2) as it seems that <sys/uio.h> is not included
1358 * correctly.
1359 * It has to be that deep because otherwise we have a conflict on
1360 * const struct dcesrv_interface declaration.
1361 * This is mostly due to socket_wrapper defining #define bind swrap_bind
1362 * which conflict with the bind used before.
1364 #include "system/network.h"
1366 struct dcesrv_sock_reply_state {
1367 struct dcesrv_connection *dce_conn;
1368 struct dcesrv_call_state *call;
1369 struct iovec iov;
1372 static void dcesrv_sock_reply_done(struct tevent_req *subreq);
1374 static void dcesrv_sock_report_output_data(struct dcesrv_connection *dce_conn)
1376 struct dcesrv_call_state *call;
1378 call = dce_conn->call_list;
1379 if (!call || !call->replies) {
1380 return;
1383 while (call->replies) {
1384 struct data_blob_list_item *rep = call->replies;
1385 struct dcesrv_sock_reply_state *substate;
1386 struct tevent_req *subreq;
1388 substate = talloc(call, struct dcesrv_sock_reply_state);
1389 if (!substate) {
1390 dcesrv_terminate_connection(dce_conn, "no memory");
1391 return;
1394 substate->dce_conn = dce_conn;
1395 substate->call = NULL;
1397 DLIST_REMOVE(call->replies, rep);
1399 if (call->replies == NULL) {
1400 substate->call = call;
1403 substate->iov.iov_base = (void *) rep->blob.data;
1404 substate->iov.iov_len = rep->blob.length;
1406 subreq = tstream_writev_queue_send(substate,
1407 dce_conn->event_ctx,
1408 dce_conn->stream,
1409 dce_conn->send_queue,
1410 &substate->iov, 1);
1411 if (!subreq) {
1412 dcesrv_terminate_connection(dce_conn, "no memory");
1413 return;
1415 tevent_req_set_callback(subreq, dcesrv_sock_reply_done,
1416 substate);
1419 DLIST_REMOVE(call->conn->call_list, call);
1420 call->list = DCESRV_LIST_NONE;
1423 static void dcesrv_sock_reply_done(struct tevent_req *subreq)
1425 struct dcesrv_sock_reply_state *substate = tevent_req_callback_data(subreq,
1426 struct dcesrv_sock_reply_state);
1427 int ret;
1428 int sys_errno;
1429 NTSTATUS status;
1430 struct dcesrv_call_state *call = substate->call;
1432 ret = tstream_writev_queue_recv(subreq, &sys_errno);
1433 TALLOC_FREE(subreq);
1434 if (ret == -1) {
1435 status = map_nt_error_from_unix_common(sys_errno);
1436 dcesrv_terminate_connection(substate->dce_conn, nt_errstr(status));
1437 return;
1440 talloc_free(substate);
1441 if (call) {
1442 talloc_free(call);
1449 struct dcesrv_socket_context {
1450 const struct dcesrv_endpoint *endpoint;
1451 struct dcesrv_context *dcesrv_ctx;
1455 static void dcesrv_read_fragment_done(struct tevent_req *subreq);
1457 static void dcesrv_sock_accept(struct stream_connection *srv_conn)
1459 NTSTATUS status;
1460 struct dcesrv_socket_context *dcesrv_sock =
1461 talloc_get_type(srv_conn->private_data, struct dcesrv_socket_context);
1462 struct dcesrv_connection *dcesrv_conn = NULL;
1463 int ret;
1464 struct tevent_req *subreq;
1465 struct loadparm_context *lp_ctx = dcesrv_sock->dcesrv_ctx->lp_ctx;
1467 dcesrv_cleanup_broken_connections(dcesrv_sock->dcesrv_ctx);
1469 if (!srv_conn->session_info) {
1470 status = auth_anonymous_session_info(srv_conn,
1471 lp_ctx,
1472 &srv_conn->session_info);
1473 if (!NT_STATUS_IS_OK(status)) {
1474 DEBUG(0,("dcesrv_sock_accept: auth_anonymous_session_info failed: %s\n",
1475 nt_errstr(status)));
1476 stream_terminate_connection(srv_conn, nt_errstr(status));
1477 return;
1481 status = dcesrv_endpoint_connect(dcesrv_sock->dcesrv_ctx,
1482 srv_conn,
1483 dcesrv_sock->endpoint,
1484 srv_conn->session_info,
1485 srv_conn->event.ctx,
1486 srv_conn->msg_ctx,
1487 srv_conn->server_id,
1488 DCESRV_CALL_STATE_FLAG_MAY_ASYNC,
1489 &dcesrv_conn);
1490 if (!NT_STATUS_IS_OK(status)) {
1491 DEBUG(0,("dcesrv_sock_accept: dcesrv_endpoint_connect failed: %s\n",
1492 nt_errstr(status)));
1493 stream_terminate_connection(srv_conn, nt_errstr(status));
1494 return;
1497 dcesrv_conn->transport.private_data = srv_conn;
1498 dcesrv_conn->transport.report_output_data = dcesrv_sock_report_output_data;
1500 TALLOC_FREE(srv_conn->event.fde);
1502 dcesrv_conn->send_queue = tevent_queue_create(dcesrv_conn, "dcesrv send queue");
1503 if (!dcesrv_conn->send_queue) {
1504 status = NT_STATUS_NO_MEMORY;
1505 DEBUG(0,("dcesrv_sock_accept: tevent_queue_create(%s)\n",
1506 nt_errstr(status)));
1507 stream_terminate_connection(srv_conn, nt_errstr(status));
1508 return;
1511 if (dcesrv_sock->endpoint->ep_description->transport == NCACN_NP) {
1512 dcesrv_conn->auth_state.session_key = dcesrv_inherited_session_key;
1513 dcesrv_conn->stream = talloc_move(dcesrv_conn,
1514 &srv_conn->tstream);
1515 } else {
1516 ret = tstream_bsd_existing_socket(dcesrv_conn,
1517 socket_get_fd(srv_conn->socket),
1518 &dcesrv_conn->stream);
1519 if (ret == -1) {
1520 status = map_nt_error_from_unix_common(errno);
1521 DEBUG(0, ("dcesrv_sock_accept: "
1522 "failed to setup tstream: %s\n",
1523 nt_errstr(status)));
1524 stream_terminate_connection(srv_conn, nt_errstr(status));
1525 return;
1527 socket_set_flags(srv_conn->socket, SOCKET_FLAG_NOCLOSE);
1530 dcesrv_conn->local_address = srv_conn->local_address;
1531 dcesrv_conn->remote_address = srv_conn->remote_address;
1533 srv_conn->private_data = dcesrv_conn;
1535 irpc_add_name(srv_conn->msg_ctx, "rpc_server");
1537 subreq = dcerpc_read_ncacn_packet_send(dcesrv_conn,
1538 dcesrv_conn->event_ctx,
1539 dcesrv_conn->stream);
1540 if (!subreq) {
1541 status = NT_STATUS_NO_MEMORY;
1542 DEBUG(0,("dcesrv_sock_accept: dcerpc_read_fragment_buffer_send(%s)\n",
1543 nt_errstr(status)));
1544 stream_terminate_connection(srv_conn, nt_errstr(status));
1545 return;
1547 tevent_req_set_callback(subreq, dcesrv_read_fragment_done, dcesrv_conn);
1549 return;
1552 static void dcesrv_read_fragment_done(struct tevent_req *subreq)
1554 struct dcesrv_connection *dce_conn = tevent_req_callback_data(subreq,
1555 struct dcesrv_connection);
1556 struct dcesrv_context *dce_ctx = dce_conn->dce_ctx;
1557 struct ncacn_packet *pkt;
1558 DATA_BLOB buffer;
1559 NTSTATUS status;
1561 if (dce_conn->terminate) {
1563 * if the current connection is broken
1564 * we need to clean it up before any other connection
1566 dcesrv_terminate_connection(dce_conn, dce_conn->terminate);
1567 dcesrv_cleanup_broken_connections(dce_ctx);
1568 return;
1571 dcesrv_cleanup_broken_connections(dce_ctx);
1573 status = dcerpc_read_ncacn_packet_recv(subreq, dce_conn,
1574 &pkt, &buffer);
1575 TALLOC_FREE(subreq);
1576 if (!NT_STATUS_IS_OK(status)) {
1577 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1578 return;
1581 status = dcesrv_process_ncacn_packet(dce_conn, pkt, buffer);
1582 if (!NT_STATUS_IS_OK(status)) {
1583 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1584 return;
1587 subreq = dcerpc_read_ncacn_packet_send(dce_conn,
1588 dce_conn->event_ctx,
1589 dce_conn->stream);
1590 if (!subreq) {
1591 status = NT_STATUS_NO_MEMORY;
1592 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1593 return;
1595 tevent_req_set_callback(subreq, dcesrv_read_fragment_done, dce_conn);
1598 static void dcesrv_sock_recv(struct stream_connection *conn, uint16_t flags)
1600 struct dcesrv_connection *dce_conn = talloc_get_type(conn->private_data,
1601 struct dcesrv_connection);
1602 dcesrv_terminate_connection(dce_conn, "dcesrv_sock_recv triggered");
1605 static void dcesrv_sock_send(struct stream_connection *conn, uint16_t flags)
1607 struct dcesrv_connection *dce_conn = talloc_get_type(conn->private_data,
1608 struct dcesrv_connection);
1609 dcesrv_terminate_connection(dce_conn, "dcesrv_sock_send triggered");
1613 static const struct stream_server_ops dcesrv_stream_ops = {
1614 .name = "rpc",
1615 .accept_connection = dcesrv_sock_accept,
1616 .recv_handler = dcesrv_sock_recv,
1617 .send_handler = dcesrv_sock_send,
1620 static NTSTATUS dcesrv_add_ep_unix(struct dcesrv_context *dce_ctx,
1621 struct loadparm_context *lp_ctx,
1622 struct dcesrv_endpoint *e,
1623 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1625 struct dcesrv_socket_context *dcesrv_sock;
1626 uint16_t port = 1;
1627 NTSTATUS status;
1629 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1630 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1632 /* remember the endpoint of this socket */
1633 dcesrv_sock->endpoint = e;
1634 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1636 status = stream_setup_socket(dcesrv_sock, event_ctx, lp_ctx,
1637 model_ops, &dcesrv_stream_ops,
1638 "unix", e->ep_description->endpoint, &port,
1639 lpcfg_socket_options(lp_ctx),
1640 dcesrv_sock);
1641 if (!NT_STATUS_IS_OK(status)) {
1642 DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n",
1643 e->ep_description->endpoint, nt_errstr(status)));
1646 return status;
1649 static NTSTATUS dcesrv_add_ep_ncalrpc(struct dcesrv_context *dce_ctx,
1650 struct loadparm_context *lp_ctx,
1651 struct dcesrv_endpoint *e,
1652 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1654 struct dcesrv_socket_context *dcesrv_sock;
1655 uint16_t port = 1;
1656 char *full_path;
1657 NTSTATUS status;
1659 if (!e->ep_description->endpoint) {
1660 /* No identifier specified: use DEFAULT.
1661 * DO NOT hardcode this value anywhere else. Rather, specify
1662 * no endpoint and let the epmapper worry about it. */
1663 e->ep_description->endpoint = talloc_strdup(dce_ctx, "DEFAULT");
1666 full_path = talloc_asprintf(dce_ctx, "%s/%s", lpcfg_ncalrpc_dir(lp_ctx),
1667 e->ep_description->endpoint);
1669 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1670 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1672 /* remember the endpoint of this socket */
1673 dcesrv_sock->endpoint = e;
1674 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1676 status = stream_setup_socket(dcesrv_sock, event_ctx, lp_ctx,
1677 model_ops, &dcesrv_stream_ops,
1678 "unix", full_path, &port,
1679 lpcfg_socket_options(lp_ctx),
1680 dcesrv_sock);
1681 if (!NT_STATUS_IS_OK(status)) {
1682 DEBUG(0,("service_setup_stream_socket(identifier=%s,path=%s) failed - %s\n",
1683 e->ep_description->endpoint, full_path, nt_errstr(status)));
1685 return status;
1688 static NTSTATUS dcesrv_add_ep_np(struct dcesrv_context *dce_ctx,
1689 struct loadparm_context *lp_ctx,
1690 struct dcesrv_endpoint *e,
1691 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1693 struct dcesrv_socket_context *dcesrv_sock;
1694 NTSTATUS status;
1696 if (e->ep_description->endpoint == NULL) {
1697 DEBUG(0, ("Endpoint mandatory for named pipes\n"));
1698 return NT_STATUS_INVALID_PARAMETER;
1701 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1702 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1704 /* remember the endpoint of this socket */
1705 dcesrv_sock->endpoint = e;
1706 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1708 status = tstream_setup_named_pipe(dce_ctx, event_ctx, lp_ctx,
1709 model_ops, &dcesrv_stream_ops,
1710 e->ep_description->endpoint,
1711 dcesrv_sock);
1712 if (!NT_STATUS_IS_OK(status)) {
1713 DEBUG(0,("stream_setup_named_pipe(pipe=%s) failed - %s\n",
1714 e->ep_description->endpoint, nt_errstr(status)));
1715 return status;
1718 return NT_STATUS_OK;
1722 add a socket address to the list of events, one event per dcerpc endpoint
1724 static NTSTATUS add_socket_rpc_tcp_iface(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e,
1725 struct tevent_context *event_ctx, const struct model_ops *model_ops,
1726 const char *address)
1728 struct dcesrv_socket_context *dcesrv_sock;
1729 uint16_t port = 0;
1730 NTSTATUS status;
1732 if (e->ep_description->endpoint) {
1733 port = atoi(e->ep_description->endpoint);
1736 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1737 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1739 /* remember the endpoint of this socket */
1740 dcesrv_sock->endpoint = e;
1741 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1743 status = stream_setup_socket(dcesrv_sock, event_ctx, dce_ctx->lp_ctx,
1744 model_ops, &dcesrv_stream_ops,
1745 "ip", address, &port,
1746 lpcfg_socket_options(dce_ctx->lp_ctx),
1747 dcesrv_sock);
1748 if (!NT_STATUS_IS_OK(status)) {
1749 DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) failed - %s\n",
1750 address, port, nt_errstr(status)));
1753 if (e->ep_description->endpoint == NULL) {
1754 e->ep_description->endpoint = talloc_asprintf(dce_ctx, "%d", port);
1757 return status;
1760 #include "lib/socket/netif.h" /* Included here to work around the fact that socket_wrapper redefines bind() */
1762 static NTSTATUS dcesrv_add_ep_tcp(struct dcesrv_context *dce_ctx,
1763 struct loadparm_context *lp_ctx,
1764 struct dcesrv_endpoint *e,
1765 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1767 NTSTATUS status;
1769 /* Add TCP/IP sockets */
1770 if (lpcfg_interfaces(lp_ctx) && lpcfg_bind_interfaces_only(lp_ctx)) {
1771 int num_interfaces;
1772 int i;
1773 struct interface *ifaces;
1775 load_interface_list(dce_ctx, lp_ctx, &ifaces);
1777 num_interfaces = iface_list_count(ifaces);
1778 for(i = 0; i < num_interfaces; i++) {
1779 const char *address = iface_list_n_ip(ifaces, i);
1780 status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, address);
1781 NT_STATUS_NOT_OK_RETURN(status);
1783 } else {
1784 const char **wcard;
1785 int i;
1786 wcard = iface_list_wildcard(dce_ctx, lp_ctx);
1787 NT_STATUS_HAVE_NO_MEMORY(wcard);
1788 for (i=0; wcard[i]; i++) {
1789 status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, wcard[i]);
1790 NT_STATUS_NOT_OK_RETURN(status);
1792 talloc_free(wcard);
1795 return NT_STATUS_OK;
1798 NTSTATUS dcesrv_add_ep(struct dcesrv_context *dce_ctx,
1799 struct loadparm_context *lp_ctx,
1800 struct dcesrv_endpoint *e,
1801 struct tevent_context *event_ctx,
1802 const struct model_ops *model_ops)
1804 switch (e->ep_description->transport) {
1805 case NCACN_UNIX_STREAM:
1806 return dcesrv_add_ep_unix(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1808 case NCALRPC:
1809 return dcesrv_add_ep_ncalrpc(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1811 case NCACN_IP_TCP:
1812 return dcesrv_add_ep_tcp(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1814 case NCACN_NP:
1815 return dcesrv_add_ep_np(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1817 default:
1818 return NT_STATUS_NOT_SUPPORTED;
1824 * retrieve credentials from a dce_call
1826 _PUBLIC_ struct cli_credentials *dcesrv_call_credentials(struct dcesrv_call_state *dce_call)
1828 return dce_call->conn->auth_state.session_info->credentials;
1832 * returns true if this is an authenticated call
1834 _PUBLIC_ bool dcesrv_call_authenticated(struct dcesrv_call_state *dce_call)
1836 enum security_user_level level;
1837 level = security_session_user_level(dce_call->conn->auth_state.session_info, NULL);
1838 return level >= SECURITY_USER;
1842 * retrieve account_name for a dce_call
1844 _PUBLIC_ const char *dcesrv_call_account_name(struct dcesrv_call_state *dce_call)
1846 return dce_call->context->conn->auth_state.session_info->info->account_name;