WHATSNEW: Start release notes for Samba 3.6.18.
[Samba.git] / source4 / rpc_server / dcerpc_server.c
blobcd079da5c969ad9e8bbe99f05b2c242eacc49d18
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"
43 /* this is only used when the client asks for an unknown interface */
44 #define DUMMY_ASSOC_GROUP 0x0FFFFFFF
46 extern const struct dcesrv_interface dcesrv_mgmt_interface;
50 find an association group given a assoc_group_id
52 static struct dcesrv_assoc_group *dcesrv_assoc_group_find(struct dcesrv_context *dce_ctx,
53 uint32_t id)
55 void *id_ptr;
57 id_ptr = idr_find(dce_ctx->assoc_groups_idr, id);
58 if (id_ptr == NULL) {
59 return NULL;
61 return talloc_get_type_abort(id_ptr, struct dcesrv_assoc_group);
65 take a reference to an existing association group
67 static struct dcesrv_assoc_group *dcesrv_assoc_group_reference(TALLOC_CTX *mem_ctx,
68 struct dcesrv_context *dce_ctx,
69 uint32_t id)
71 struct dcesrv_assoc_group *assoc_group;
73 assoc_group = dcesrv_assoc_group_find(dce_ctx, id);
74 if (assoc_group == NULL) {
75 DEBUG(0,(__location__ ": Failed to find assoc_group 0x%08x\n", id));
76 return NULL;
78 return talloc_reference(mem_ctx, assoc_group);
81 static int dcesrv_assoc_group_destructor(struct dcesrv_assoc_group *assoc_group)
83 int ret;
84 ret = idr_remove(assoc_group->dce_ctx->assoc_groups_idr, assoc_group->id);
85 if (ret != 0) {
86 DEBUG(0,(__location__ ": Failed to remove assoc_group 0x%08x\n",
87 assoc_group->id));
89 return 0;
93 allocate a new association group
95 static struct dcesrv_assoc_group *dcesrv_assoc_group_new(TALLOC_CTX *mem_ctx,
96 struct dcesrv_context *dce_ctx)
98 struct dcesrv_assoc_group *assoc_group;
99 int id;
101 assoc_group = talloc_zero(mem_ctx, struct dcesrv_assoc_group);
102 if (assoc_group == NULL) {
103 return NULL;
106 id = idr_get_new_random(dce_ctx->assoc_groups_idr, assoc_group, UINT16_MAX);
107 if (id == -1) {
108 talloc_free(assoc_group);
109 DEBUG(0,(__location__ ": Out of association groups!\n"));
110 return NULL;
113 assoc_group->id = id;
114 assoc_group->dce_ctx = dce_ctx;
116 talloc_set_destructor(assoc_group, dcesrv_assoc_group_destructor);
118 return assoc_group;
123 see if two endpoints match
125 static bool endpoints_match(const struct dcerpc_binding *ep1,
126 const struct dcerpc_binding *ep2)
128 if (ep1->transport != ep2->transport) {
129 return false;
132 if (!ep1->endpoint || !ep2->endpoint) {
133 return ep1->endpoint == ep2->endpoint;
136 if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
137 return false;
139 return true;
143 find an endpoint in the dcesrv_context
145 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
146 const struct dcerpc_binding *ep_description)
148 struct dcesrv_endpoint *ep;
149 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
150 if (endpoints_match(ep->ep_description, ep_description)) {
151 return ep;
154 return NULL;
158 find a registered context_id from a bind or alter_context
160 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn,
161 uint32_t context_id)
163 struct dcesrv_connection_context *c;
164 for (c=conn->contexts;c;c=c->next) {
165 if (c->context_id == context_id) return c;
167 return NULL;
171 see if a uuid and if_version match to an interface
173 static bool interface_match(const struct dcesrv_interface *if1,
174 const struct dcesrv_interface *if2)
176 return (if1->syntax_id.if_version == if2->syntax_id.if_version &&
177 GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
181 find the interface operations on an endpoint
183 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
184 const struct dcesrv_interface *iface)
186 struct dcesrv_if_list *ifl;
187 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
188 if (interface_match(&(ifl->iface), iface)) {
189 return &(ifl->iface);
192 return NULL;
196 see if a uuid and if_version match to an interface
198 static bool interface_match_by_uuid(const struct dcesrv_interface *iface,
199 const struct GUID *uuid, uint32_t if_version)
201 return (iface->syntax_id.if_version == if_version &&
202 GUID_equal(&iface->syntax_id.uuid, uuid));
206 find the interface operations on an endpoint by uuid
208 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
209 const struct GUID *uuid, uint32_t if_version)
211 struct dcesrv_if_list *ifl;
212 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
213 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
214 return &(ifl->iface);
217 return NULL;
221 find the earlier parts of a fragmented call awaiting reassembily
223 static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
225 struct dcesrv_call_state *c;
226 for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
227 if (c->pkt.call_id == call_id) {
228 return c;
231 return NULL;
235 register an interface on an endpoint
237 _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
238 const char *ep_name,
239 const struct dcesrv_interface *iface,
240 const struct security_descriptor *sd)
242 struct dcesrv_endpoint *ep;
243 struct dcesrv_if_list *ifl;
244 struct dcerpc_binding *binding;
245 bool add_ep = false;
246 NTSTATUS status;
248 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
250 if (NT_STATUS_IS_ERR(status)) {
251 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
252 return status;
255 /* check if this endpoint exists
257 if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
258 ep = talloc(dce_ctx, struct dcesrv_endpoint);
259 if (!ep) {
260 return NT_STATUS_NO_MEMORY;
262 ZERO_STRUCTP(ep);
263 ep->ep_description = talloc_reference(ep, binding);
264 add_ep = true;
266 /* add mgmt interface */
267 ifl = talloc(dce_ctx, struct dcesrv_if_list);
268 if (!ifl) {
269 return NT_STATUS_NO_MEMORY;
272 memcpy(&(ifl->iface), &dcesrv_mgmt_interface,
273 sizeof(struct dcesrv_interface));
275 DLIST_ADD(ep->interface_list, ifl);
278 /* see if the interface is already registered on te endpoint */
279 if (find_interface(ep, iface)!=NULL) {
280 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
281 iface->name, ep_name));
282 return NT_STATUS_OBJECT_NAME_COLLISION;
285 /* talloc a new interface list element */
286 ifl = talloc(dce_ctx, struct dcesrv_if_list);
287 if (!ifl) {
288 return NT_STATUS_NO_MEMORY;
291 /* copy the given interface struct to the one on the endpoints interface list */
292 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
294 /* if we have a security descriptor given,
295 * we should see if we can set it up on the endpoint
297 if (sd != NULL) {
298 /* if there's currently no security descriptor given on the endpoint
299 * we try to set it
301 if (ep->sd == NULL) {
302 ep->sd = security_descriptor_copy(dce_ctx, sd);
305 /* if now there's no security descriptor given on the endpoint
306 * something goes wrong, either we failed to copy the security descriptor
307 * or there was already one on the endpoint
309 if (ep->sd != NULL) {
310 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
311 " on endpoint '%s'\n",
312 iface->name, ep_name));
313 if (add_ep) free(ep);
314 free(ifl);
315 return NT_STATUS_OBJECT_NAME_COLLISION;
319 /* finally add the interface on the endpoint */
320 DLIST_ADD(ep->interface_list, ifl);
322 /* if it's a new endpoint add it to the dcesrv_context */
323 if (add_ep) {
324 DLIST_ADD(dce_ctx->endpoint_list, ep);
327 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
328 iface->name, ep_name));
330 return NT_STATUS_OK;
333 NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
334 DATA_BLOB *session_key)
336 if (p->auth_state.session_info->session_key.length) {
337 *session_key = p->auth_state.session_info->session_key;
338 return NT_STATUS_OK;
340 return NT_STATUS_NO_USER_SESSION_KEY;
344 fetch the user session key - may be default (above) or the SMB session key
346 The key is always truncated to 16 bytes
348 _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
349 DATA_BLOB *session_key)
351 NTSTATUS status = p->auth_state.session_key(p, session_key);
352 if (!NT_STATUS_IS_OK(status)) {
353 return status;
356 session_key->length = MIN(session_key->length, 16);
358 return NT_STATUS_OK;
362 connect to a dcerpc endpoint
364 _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
365 TALLOC_CTX *mem_ctx,
366 const struct dcesrv_endpoint *ep,
367 struct auth_session_info *session_info,
368 struct tevent_context *event_ctx,
369 struct messaging_context *msg_ctx,
370 struct server_id server_id,
371 uint32_t state_flags,
372 struct dcesrv_connection **_p)
374 struct dcesrv_connection *p;
376 if (!session_info) {
377 return NT_STATUS_ACCESS_DENIED;
380 p = talloc(mem_ctx, struct dcesrv_connection);
381 NT_STATUS_HAVE_NO_MEMORY(p);
383 if (!talloc_reference(p, session_info)) {
384 talloc_free(p);
385 return NT_STATUS_NO_MEMORY;
388 p->dce_ctx = dce_ctx;
389 p->endpoint = ep;
390 p->contexts = NULL;
391 p->call_list = NULL;
392 p->packet_log_dir = lpcfg_lockdir(dce_ctx->lp_ctx);
393 p->incoming_fragmented_call_list = NULL;
394 p->pending_call_list = NULL;
395 p->cli_max_recv_frag = 0;
396 p->partial_input = data_blob(NULL, 0);
397 p->auth_state.auth_info = NULL;
398 p->auth_state.gensec_security = NULL;
399 p->auth_state.session_info = session_info;
400 p->auth_state.session_key = dcesrv_generic_session_key;
401 p->event_ctx = event_ctx;
402 p->msg_ctx = msg_ctx;
403 p->server_id = server_id;
404 p->processing = false;
405 p->state_flags = state_flags;
406 ZERO_STRUCT(p->transport);
408 *_p = p;
409 return NT_STATUS_OK;
413 move a call from an existing linked list to the specified list. This
414 prevents bugs where we forget to remove the call from a previous
415 list when moving it.
417 static void dcesrv_call_set_list(struct dcesrv_call_state *call,
418 enum dcesrv_call_list list)
420 switch (call->list) {
421 case DCESRV_LIST_NONE:
422 break;
423 case DCESRV_LIST_CALL_LIST:
424 DLIST_REMOVE(call->conn->call_list, call);
425 break;
426 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
427 DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
428 break;
429 case DCESRV_LIST_PENDING_CALL_LIST:
430 DLIST_REMOVE(call->conn->pending_call_list, call);
431 break;
433 call->list = list;
434 switch (list) {
435 case DCESRV_LIST_NONE:
436 break;
437 case DCESRV_LIST_CALL_LIST:
438 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
439 break;
440 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
441 DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
442 break;
443 case DCESRV_LIST_PENDING_CALL_LIST:
444 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
445 break;
451 return a dcerpc bind_nak
453 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
455 struct ncacn_packet pkt;
456 struct data_blob_list_item *rep;
457 NTSTATUS status;
459 /* setup a bind_nak */
460 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
461 pkt.auth_length = 0;
462 pkt.call_id = call->pkt.call_id;
463 pkt.ptype = DCERPC_PKT_BIND_NAK;
464 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
465 pkt.u.bind_nak.reject_reason = reason;
466 if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
467 pkt.u.bind_nak.versions.v.num_versions = 0;
470 rep = talloc(call, struct data_blob_list_item);
471 if (!rep) {
472 return NT_STATUS_NO_MEMORY;
475 status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
476 if (!NT_STATUS_IS_OK(status)) {
477 return status;
480 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
482 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
483 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
485 if (call->conn->call_list && call->conn->call_list->replies) {
486 if (call->conn->transport.report_output_data) {
487 call->conn->transport.report_output_data(call->conn);
491 return NT_STATUS_OK;
494 static int dcesrv_connection_context_destructor(struct dcesrv_connection_context *c)
496 DLIST_REMOVE(c->conn->contexts, c);
498 if (c->iface && c->iface->unbind) {
499 c->iface->unbind(c, c->iface);
502 return 0;
506 handle a bind request
508 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
510 uint32_t if_version, transfer_syntax_version;
511 struct GUID uuid, *transfer_syntax_uuid;
512 struct ncacn_packet pkt;
513 struct data_blob_list_item *rep;
514 NTSTATUS status;
515 uint32_t result=0, reason=0;
516 uint32_t context_id;
517 const struct dcesrv_interface *iface;
518 uint32_t extra_flags = 0;
521 if provided, check the assoc_group is valid
523 if (call->pkt.u.bind.assoc_group_id != 0 &&
524 lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
525 dcesrv_assoc_group_find(call->conn->dce_ctx, call->pkt.u.bind.assoc_group_id) == NULL) {
526 return dcesrv_bind_nak(call, 0);
529 if (call->pkt.u.bind.num_contexts < 1 ||
530 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
531 return dcesrv_bind_nak(call, 0);
534 context_id = call->pkt.u.bind.ctx_list[0].context_id;
536 /* you can't bind twice on one context */
537 if (dcesrv_find_context(call->conn, context_id) != NULL) {
538 return dcesrv_bind_nak(call, 0);
541 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
542 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
544 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
545 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
546 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
547 ndr_transfer_syntax.if_version != transfer_syntax_version) {
548 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
549 /* we only do NDR encoded dcerpc */
550 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
551 talloc_free(uuid_str);
552 return dcesrv_bind_nak(call, 0);
555 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
556 if (iface == NULL) {
557 char *uuid_str = GUID_string(call, &uuid);
558 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
559 talloc_free(uuid_str);
561 /* we don't know about that interface */
562 result = DCERPC_BIND_PROVIDER_REJECT;
563 reason = DCERPC_BIND_REASON_ASYNTAX;
566 if (iface) {
567 /* add this context to the list of available context_ids */
568 struct dcesrv_connection_context *context = talloc(call->conn,
569 struct dcesrv_connection_context);
570 if (context == NULL) {
571 return dcesrv_bind_nak(call, 0);
573 context->conn = call->conn;
574 context->iface = iface;
575 context->context_id = context_id;
576 if (call->pkt.u.bind.assoc_group_id != 0) {
577 context->assoc_group = dcesrv_assoc_group_reference(context,
578 call->conn->dce_ctx,
579 call->pkt.u.bind.assoc_group_id);
580 } else {
581 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
583 if (context->assoc_group == NULL) {
584 talloc_free(context);
585 return dcesrv_bind_nak(call, 0);
587 context->private_data = NULL;
588 DLIST_ADD(call->conn->contexts, context);
589 call->context = context;
590 talloc_set_destructor(context, dcesrv_connection_context_destructor);
592 status = iface->bind(call, iface, if_version);
593 if (!NT_STATUS_IS_OK(status)) {
594 char *uuid_str = GUID_string(call, &uuid);
595 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
596 uuid_str, if_version, nt_errstr(status)));
597 talloc_free(uuid_str);
598 /* we don't want to trigger the iface->unbind() hook */
599 context->iface = NULL;
600 talloc_free(call->context);
601 call->context = NULL;
602 return dcesrv_bind_nak(call, 0);
606 if (call->conn->cli_max_recv_frag == 0) {
607 call->conn->cli_max_recv_frag = MIN(0x2000, call->pkt.u.bind.max_recv_frag);
610 if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) &&
611 lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","header signing", false)) {
612 call->conn->state_flags |= DCESRV_CALL_STATE_FLAG_HEADER_SIGNING;
613 extra_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
616 /* handle any authentication that is being requested */
617 if (!dcesrv_auth_bind(call)) {
618 talloc_free(call->context);
619 call->context = NULL;
620 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
623 /* setup a bind_ack */
624 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
625 pkt.auth_length = 0;
626 pkt.call_id = call->pkt.call_id;
627 pkt.ptype = DCERPC_PKT_BIND_ACK;
628 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
629 pkt.u.bind_ack.max_xmit_frag = call->conn->cli_max_recv_frag;
630 pkt.u.bind_ack.max_recv_frag = 0x2000;
633 make it possible for iface->bind() to specify the assoc_group_id
634 This helps the openchange mapiproxy plugin to work correctly.
636 metze
638 if (call->context) {
639 pkt.u.bind_ack.assoc_group_id = call->context->assoc_group->id;
640 } else {
641 pkt.u.bind_ack.assoc_group_id = DUMMY_ASSOC_GROUP;
644 if (iface) {
645 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
646 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
647 } else {
648 pkt.u.bind_ack.secondary_address = "";
650 pkt.u.bind_ack.num_results = 1;
651 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
652 if (!pkt.u.bind_ack.ctx_list) {
653 talloc_free(call->context);
654 call->context = NULL;
655 return NT_STATUS_NO_MEMORY;
657 pkt.u.bind_ack.ctx_list[0].result = result;
658 pkt.u.bind_ack.ctx_list[0].reason = reason;
659 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
660 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
662 status = dcesrv_auth_bind_ack(call, &pkt);
663 if (!NT_STATUS_IS_OK(status)) {
664 talloc_free(call->context);
665 call->context = NULL;
666 return dcesrv_bind_nak(call, 0);
669 rep = talloc(call, struct data_blob_list_item);
670 if (!rep) {
671 talloc_free(call->context);
672 call->context = NULL;
673 return NT_STATUS_NO_MEMORY;
676 status = ncacn_push_auth(&rep->blob, call, &pkt,
677 call->conn->auth_state.auth_info);
678 if (!NT_STATUS_IS_OK(status)) {
679 talloc_free(call->context);
680 call->context = NULL;
681 return status;
684 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
686 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
687 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
689 if (call->conn->call_list && call->conn->call_list->replies) {
690 if (call->conn->transport.report_output_data) {
691 call->conn->transport.report_output_data(call->conn);
695 return NT_STATUS_OK;
700 handle a auth3 request
702 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
704 /* handle the auth3 in the auth code */
705 if (!dcesrv_auth_auth3(call)) {
706 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
709 talloc_free(call);
711 /* we don't send a reply to a auth3 request, except by a
712 fault */
713 return NT_STATUS_OK;
718 handle a bind request
720 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
722 uint32_t if_version, transfer_syntax_version;
723 struct dcesrv_connection_context *context;
724 const struct dcesrv_interface *iface;
725 struct GUID uuid, *transfer_syntax_uuid;
726 NTSTATUS status;
728 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
729 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
731 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
732 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
733 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
734 ndr_transfer_syntax.if_version != transfer_syntax_version) {
735 /* we only do NDR encoded dcerpc */
736 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
739 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
740 if (iface == NULL) {
741 char *uuid_str = GUID_string(call, &uuid);
742 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
743 talloc_free(uuid_str);
744 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
747 /* add this context to the list of available context_ids */
748 context = talloc(call->conn, struct dcesrv_connection_context);
749 if (context == NULL) {
750 return NT_STATUS_NO_MEMORY;
752 context->conn = call->conn;
753 context->iface = iface;
754 context->context_id = context_id;
755 if (call->pkt.u.alter.assoc_group_id != 0) {
756 context->assoc_group = dcesrv_assoc_group_reference(context,
757 call->conn->dce_ctx,
758 call->pkt.u.alter.assoc_group_id);
759 } else {
760 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
762 if (context->assoc_group == NULL) {
763 talloc_free(context);
764 call->context = NULL;
765 return NT_STATUS_NO_MEMORY;
767 context->private_data = NULL;
768 DLIST_ADD(call->conn->contexts, context);
769 call->context = context;
770 talloc_set_destructor(context, dcesrv_connection_context_destructor);
772 status = iface->bind(call, iface, if_version);
773 if (!NT_STATUS_IS_OK(status)) {
774 /* we don't want to trigger the iface->unbind() hook */
775 context->iface = NULL;
776 talloc_free(context);
777 call->context = NULL;
778 return status;
781 return NT_STATUS_OK;
786 handle a alter context request
788 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
790 struct ncacn_packet pkt;
791 struct data_blob_list_item *rep;
792 NTSTATUS status;
793 uint32_t result=0, reason=0;
794 uint32_t context_id;
796 /* handle any authentication that is being requested */
797 if (!dcesrv_auth_alter(call)) {
798 /* TODO: work out the right reject code */
799 result = DCERPC_BIND_PROVIDER_REJECT;
800 reason = DCERPC_BIND_REASON_ASYNTAX;
803 context_id = call->pkt.u.alter.ctx_list[0].context_id;
805 /* see if they are asking for a new interface */
806 if (result == 0) {
807 call->context = dcesrv_find_context(call->conn, context_id);
808 if (!call->context) {
809 status = dcesrv_alter_new_context(call, context_id);
810 if (!NT_STATUS_IS_OK(status)) {
811 result = DCERPC_BIND_PROVIDER_REJECT;
812 reason = DCERPC_BIND_REASON_ASYNTAX;
817 if (result == 0 &&
818 call->pkt.u.alter.assoc_group_id != 0 &&
819 lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
820 call->pkt.u.alter.assoc_group_id != call->context->assoc_group->id) {
821 DEBUG(0,(__location__ ": Failed attempt to use new assoc_group in alter context (0x%08x 0x%08x)\n",
822 call->context->assoc_group->id, call->pkt.u.alter.assoc_group_id));
823 /* TODO: can they ask for a new association group? */
824 result = DCERPC_BIND_PROVIDER_REJECT;
825 reason = DCERPC_BIND_REASON_ASYNTAX;
828 /* setup a alter_resp */
829 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
830 pkt.auth_length = 0;
831 pkt.call_id = call->pkt.call_id;
832 pkt.ptype = DCERPC_PKT_ALTER_RESP;
833 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
834 pkt.u.alter_resp.max_xmit_frag = 0x2000;
835 pkt.u.alter_resp.max_recv_frag = 0x2000;
836 if (result == 0) {
837 pkt.u.alter_resp.assoc_group_id = call->context->assoc_group->id;
838 } else {
839 pkt.u.alter_resp.assoc_group_id = 0;
841 pkt.u.alter_resp.num_results = 1;
842 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
843 if (!pkt.u.alter_resp.ctx_list) {
844 return NT_STATUS_NO_MEMORY;
846 pkt.u.alter_resp.ctx_list[0].result = result;
847 pkt.u.alter_resp.ctx_list[0].reason = reason;
848 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
849 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
850 pkt.u.alter_resp.secondary_address = "";
852 status = dcesrv_auth_alter_ack(call, &pkt);
853 if (!NT_STATUS_IS_OK(status)) {
854 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
855 || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
856 || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
857 || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
858 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
860 return dcesrv_fault(call, 0);
863 rep = talloc(call, struct data_blob_list_item);
864 if (!rep) {
865 return NT_STATUS_NO_MEMORY;
868 status = ncacn_push_auth(&rep->blob, call, &pkt, call->conn->auth_state.auth_info);
869 if (!NT_STATUS_IS_OK(status)) {
870 return status;
873 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
875 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
876 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
878 if (call->conn->call_list && call->conn->call_list->replies) {
879 if (call->conn->transport.report_output_data) {
880 call->conn->transport.report_output_data(call->conn);
884 return NT_STATUS_OK;
888 possibly save the call for inspection with ndrdump
890 static void dcesrv_save_call(struct dcesrv_call_state *call, const char *why)
892 #ifdef DEVELOPER
893 char *fname;
894 const char *dump_dir;
895 dump_dir = lpcfg_parm_string(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv", "stubs directory");
896 if (!dump_dir) {
897 return;
899 fname = talloc_asprintf(call, "%s/RPC-%s-%u-%s.dat",
900 dump_dir,
901 call->context->iface->name,
902 call->pkt.u.request.opnum,
903 why);
904 if (file_save(fname, call->pkt.u.request.stub_and_verifier.data, call->pkt.u.request.stub_and_verifier.length)) {
905 DEBUG(0,("RPC SAVED %s\n", fname));
907 talloc_free(fname);
908 #endif
912 handle a dcerpc request packet
914 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
916 struct ndr_pull *pull;
917 NTSTATUS status;
918 struct dcesrv_connection_context *context;
920 /* if authenticated, and the mech we use can't do async replies, don't use them... */
921 if (call->conn->auth_state.gensec_security &&
922 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
923 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
926 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
927 if (context == NULL) {
928 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
931 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
932 NT_STATUS_HAVE_NO_MEMORY(pull);
934 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
936 call->context = context;
937 call->ndr_pull = pull;
939 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
940 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
943 /* unravel the NDR for the packet */
944 status = context->iface->ndr_pull(call, call, pull, &call->r);
945 if (!NT_STATUS_IS_OK(status)) {
946 if (call->fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
947 /* we got an unknown call */
948 DEBUG(3,(__location__ ": Unknown RPC call %u on %s\n",
949 call->pkt.u.request.opnum, context->iface->name));
950 dcesrv_save_call(call, "unknown");
951 } else {
952 dcesrv_save_call(call, "pullfail");
954 return dcesrv_fault(call, call->fault_code);
957 if (pull->offset != pull->data_size) {
958 dcesrv_save_call(call, "extrabytes");
959 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
960 pull->data_size - pull->offset));
963 /* call the dispatch function */
964 status = context->iface->dispatch(call, call, call->r);
965 if (!NT_STATUS_IS_OK(status)) {
966 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
967 context->iface->name,
968 call->pkt.u.request.opnum,
969 dcerpc_errstr(pull, call->fault_code)));
970 return dcesrv_fault(call, call->fault_code);
973 /* add the call to the pending list */
974 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
976 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
977 return NT_STATUS_OK;
980 return dcesrv_reply(call);
985 remove the call from the right list when freed
987 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
989 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
990 return 0;
993 _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_local_address(struct dcesrv_connection *conn)
995 return conn->local_address;
998 _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_remote_address(struct dcesrv_connection *conn)
1000 return conn->remote_address;
1004 process some input to a dcerpc endpoint server.
1006 NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
1007 struct ncacn_packet *pkt,
1008 DATA_BLOB blob)
1010 NTSTATUS status;
1011 struct dcesrv_call_state *call;
1013 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1014 if (!call) {
1015 data_blob_free(&blob);
1016 talloc_free(pkt);
1017 return NT_STATUS_NO_MEMORY;
1019 call->conn = dce_conn;
1020 call->event_ctx = dce_conn->event_ctx;
1021 call->msg_ctx = dce_conn->msg_ctx;
1022 call->state_flags = call->conn->state_flags;
1023 call->time = timeval_current();
1024 call->list = DCESRV_LIST_NONE;
1026 talloc_steal(call, pkt);
1027 talloc_steal(call, blob.data);
1028 call->pkt = *pkt;
1030 talloc_set_destructor(call, dcesrv_call_dequeue);
1032 /* we have to check the signing here, before combining the
1033 pdus */
1034 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1035 !dcesrv_auth_request(call, &blob)) {
1036 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1039 /* see if this is a continued packet */
1040 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1041 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1042 struct dcesrv_call_state *call2 = call;
1043 uint32_t alloc_size;
1045 /* we only allow fragmented requests, no other packet types */
1046 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1047 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1050 /* this is a continuation of an existing call - find the call
1051 then tack it on the end */
1052 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1053 if (!call) {
1054 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1057 if (call->pkt.ptype != call2->pkt.ptype) {
1058 /* trying to play silly buggers are we? */
1059 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1062 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1063 call2->pkt.u.request.stub_and_verifier.length;
1064 if (call->pkt.u.request.alloc_hint > alloc_size) {
1065 alloc_size = call->pkt.u.request.alloc_hint;
1068 call->pkt.u.request.stub_and_verifier.data =
1069 talloc_realloc(call,
1070 call->pkt.u.request.stub_and_verifier.data,
1071 uint8_t, alloc_size);
1072 if (!call->pkt.u.request.stub_and_verifier.data) {
1073 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1075 memcpy(call->pkt.u.request.stub_and_verifier.data +
1076 call->pkt.u.request.stub_and_verifier.length,
1077 call2->pkt.u.request.stub_and_verifier.data,
1078 call2->pkt.u.request.stub_and_verifier.length);
1079 call->pkt.u.request.stub_and_verifier.length +=
1080 call2->pkt.u.request.stub_and_verifier.length;
1082 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1084 talloc_free(call2);
1087 /* this may not be the last pdu in the chain - if its isn't then
1088 just put it on the incoming_fragmented_call_list and wait for the rest */
1089 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1090 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1091 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1092 return NT_STATUS_OK;
1095 /* This removes any fragments we may have had stashed away */
1096 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1098 switch (call->pkt.ptype) {
1099 case DCERPC_PKT_BIND:
1100 status = dcesrv_bind(call);
1101 break;
1102 case DCERPC_PKT_AUTH3:
1103 status = dcesrv_auth3(call);
1104 break;
1105 case DCERPC_PKT_ALTER:
1106 status = dcesrv_alter(call);
1107 break;
1108 case DCERPC_PKT_REQUEST:
1109 status = dcesrv_request(call);
1110 break;
1111 default:
1112 status = NT_STATUS_INVALID_PARAMETER;
1113 break;
1116 /* if we are going to be sending a reply then add
1117 it to the list of pending calls. We add it to the end to keep the call
1118 list in the order we will answer */
1119 if (!NT_STATUS_IS_OK(status)) {
1120 talloc_free(call);
1123 return status;
1126 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1127 struct loadparm_context *lp_ctx,
1128 const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1130 NTSTATUS status;
1131 struct dcesrv_context *dce_ctx;
1132 int i;
1134 if (!endpoint_servers) {
1135 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1136 return NT_STATUS_INTERNAL_ERROR;
1139 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1140 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1141 dce_ctx->endpoint_list = NULL;
1142 dce_ctx->lp_ctx = lp_ctx;
1143 dce_ctx->assoc_groups_idr = idr_init(dce_ctx);
1144 NT_STATUS_HAVE_NO_MEMORY(dce_ctx->assoc_groups_idr);
1146 for (i=0;endpoint_servers[i];i++) {
1147 const struct dcesrv_endpoint_server *ep_server;
1149 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1150 if (!ep_server) {
1151 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1152 return NT_STATUS_INTERNAL_ERROR;
1155 status = ep_server->init_server(dce_ctx, ep_server);
1156 if (!NT_STATUS_IS_OK(status)) {
1157 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1158 nt_errstr(status)));
1159 return status;
1163 *_dce_ctx = dce_ctx;
1164 return NT_STATUS_OK;
1167 /* the list of currently registered DCERPC endpoint servers.
1169 static struct ep_server {
1170 struct dcesrv_endpoint_server *ep_server;
1171 } *ep_servers = NULL;
1172 static int num_ep_servers;
1175 register a DCERPC endpoint server.
1177 The 'name' can be later used by other backends to find the operations
1178 structure for this backend.
1180 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1182 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1184 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1186 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1187 /* its already registered! */
1188 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1189 ep_server->name));
1190 return NT_STATUS_OBJECT_NAME_COLLISION;
1193 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1194 if (!ep_servers) {
1195 smb_panic("out of memory in dcerpc_register");
1198 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1199 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1201 num_ep_servers++;
1203 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1204 ep_server->name));
1206 return NT_STATUS_OK;
1210 return the operations structure for a named backend of the specified type
1212 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1214 int i;
1216 for (i=0;i<num_ep_servers;i++) {
1217 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1218 return ep_servers[i].ep_server;
1222 return NULL;
1225 void dcerpc_server_init(struct loadparm_context *lp_ctx)
1227 static bool initialized;
1228 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
1229 STATIC_dcerpc_server_MODULES_PROTO;
1230 init_module_fn static_init[] = { STATIC_dcerpc_server_MODULES };
1231 init_module_fn *shared_init;
1233 if (initialized) {
1234 return;
1236 initialized = true;
1238 shared_init = load_samba_modules(NULL, lp_ctx, "dcerpc_server");
1240 run_init_functions(static_init);
1241 run_init_functions(shared_init);
1243 talloc_free(shared_init);
1247 return the DCERPC module version, and the size of some critical types
1248 This can be used by endpoint server modules to either detect compilation errors, or provide
1249 multiple implementations for different smbd compilation options in one module
1251 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1253 static const struct dcesrv_critical_sizes critical_sizes = {
1254 DCERPC_MODULE_VERSION,
1255 sizeof(struct dcesrv_context),
1256 sizeof(struct dcesrv_endpoint),
1257 sizeof(struct dcesrv_endpoint_server),
1258 sizeof(struct dcesrv_interface),
1259 sizeof(struct dcesrv_if_list),
1260 sizeof(struct dcesrv_connection),
1261 sizeof(struct dcesrv_call_state),
1262 sizeof(struct dcesrv_auth),
1263 sizeof(struct dcesrv_handle)
1266 return &critical_sizes;
1269 static void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, const char *reason)
1271 struct stream_connection *srv_conn;
1272 srv_conn = talloc_get_type(dce_conn->transport.private_data,
1273 struct stream_connection);
1275 stream_terminate_connection(srv_conn, reason);
1277 /* We need this include to be able to compile on some plateforms
1278 * (ie. freebsd 7.2) as it seems that <sys/uio.h> is not included
1279 * correctly.
1280 * It has to be that deep because otherwise we have a conflict on
1281 * const struct dcesrv_interface declaration.
1282 * This is mostly due to socket_wrapper defining #define bind swrap_bind
1283 * which conflict with the bind used before.
1285 #include "system/network.h"
1287 struct dcesrv_sock_reply_state {
1288 struct dcesrv_connection *dce_conn;
1289 struct dcesrv_call_state *call;
1290 struct iovec iov;
1293 static void dcesrv_sock_reply_done(struct tevent_req *subreq);
1295 static void dcesrv_sock_report_output_data(struct dcesrv_connection *dce_conn)
1297 struct dcesrv_call_state *call;
1299 call = dce_conn->call_list;
1300 if (!call || !call->replies) {
1301 return;
1304 while (call->replies) {
1305 struct data_blob_list_item *rep = call->replies;
1306 struct dcesrv_sock_reply_state *substate;
1307 struct tevent_req *subreq;
1309 substate = talloc(call, struct dcesrv_sock_reply_state);
1310 if (!substate) {
1311 dcesrv_terminate_connection(dce_conn, "no memory");
1312 return;
1315 substate->dce_conn = dce_conn;
1316 substate->call = NULL;
1318 DLIST_REMOVE(call->replies, rep);
1320 if (call->replies == NULL) {
1321 substate->call = call;
1324 substate->iov.iov_base = (void *) rep->blob.data;
1325 substate->iov.iov_len = rep->blob.length;
1327 subreq = tstream_writev_queue_send(substate,
1328 dce_conn->event_ctx,
1329 dce_conn->stream,
1330 dce_conn->send_queue,
1331 &substate->iov, 1);
1332 if (!subreq) {
1333 dcesrv_terminate_connection(dce_conn, "no memory");
1334 return;
1336 tevent_req_set_callback(subreq, dcesrv_sock_reply_done,
1337 substate);
1340 DLIST_REMOVE(call->conn->call_list, call);
1341 call->list = DCESRV_LIST_NONE;
1344 static void dcesrv_sock_reply_done(struct tevent_req *subreq)
1346 struct dcesrv_sock_reply_state *substate = tevent_req_callback_data(subreq,
1347 struct dcesrv_sock_reply_state);
1348 int ret;
1349 int sys_errno;
1350 NTSTATUS status;
1351 struct dcesrv_call_state *call = substate->call;
1353 ret = tstream_writev_queue_recv(subreq, &sys_errno);
1354 TALLOC_FREE(subreq);
1355 if (ret == -1) {
1356 status = map_nt_error_from_unix(sys_errno);
1357 dcesrv_terminate_connection(substate->dce_conn, nt_errstr(status));
1358 return;
1361 talloc_free(substate);
1362 if (call) {
1363 talloc_free(call);
1370 struct dcesrv_socket_context {
1371 const struct dcesrv_endpoint *endpoint;
1372 struct dcesrv_context *dcesrv_ctx;
1376 static void dcesrv_read_fragment_done(struct tevent_req *subreq);
1378 static void dcesrv_sock_accept(struct stream_connection *srv_conn)
1380 NTSTATUS status;
1381 struct dcesrv_socket_context *dcesrv_sock =
1382 talloc_get_type(srv_conn->private_data, struct dcesrv_socket_context);
1383 struct dcesrv_connection *dcesrv_conn = NULL;
1384 int ret;
1385 struct tevent_req *subreq;
1386 struct loadparm_context *lp_ctx = dcesrv_sock->dcesrv_ctx->lp_ctx;
1388 if (!srv_conn->session_info) {
1389 status = auth_anonymous_session_info(srv_conn,
1390 lp_ctx,
1391 &srv_conn->session_info);
1392 if (!NT_STATUS_IS_OK(status)) {
1393 DEBUG(0,("dcesrv_sock_accept: auth_anonymous_session_info failed: %s\n",
1394 nt_errstr(status)));
1395 stream_terminate_connection(srv_conn, nt_errstr(status));
1396 return;
1400 status = dcesrv_endpoint_connect(dcesrv_sock->dcesrv_ctx,
1401 srv_conn,
1402 dcesrv_sock->endpoint,
1403 srv_conn->session_info,
1404 srv_conn->event.ctx,
1405 srv_conn->msg_ctx,
1406 srv_conn->server_id,
1407 DCESRV_CALL_STATE_FLAG_MAY_ASYNC,
1408 &dcesrv_conn);
1409 if (!NT_STATUS_IS_OK(status)) {
1410 DEBUG(0,("dcesrv_sock_accept: dcesrv_endpoint_connect failed: %s\n",
1411 nt_errstr(status)));
1412 stream_terminate_connection(srv_conn, nt_errstr(status));
1413 return;
1416 dcesrv_conn->transport.private_data = srv_conn;
1417 dcesrv_conn->transport.report_output_data = dcesrv_sock_report_output_data;
1419 TALLOC_FREE(srv_conn->event.fde);
1421 dcesrv_conn->send_queue = tevent_queue_create(dcesrv_conn, "dcesrv send queue");
1422 if (!dcesrv_conn->send_queue) {
1423 status = NT_STATUS_NO_MEMORY;
1424 DEBUG(0,("dcesrv_sock_accept: tevent_queue_create(%s)\n",
1425 nt_errstr(status)));
1426 stream_terminate_connection(srv_conn, nt_errstr(status));
1427 return;
1430 if (dcesrv_sock->endpoint->ep_description->transport == NCACN_NP) {
1431 dcesrv_conn->auth_state.session_key = dcesrv_inherited_session_key;
1432 dcesrv_conn->stream = talloc_move(dcesrv_conn,
1433 &srv_conn->tstream);
1434 } else {
1435 ret = tstream_bsd_existing_socket(dcesrv_conn,
1436 socket_get_fd(srv_conn->socket),
1437 &dcesrv_conn->stream);
1438 if (ret == -1) {
1439 status = map_nt_error_from_unix(errno);
1440 DEBUG(0, ("dcesrv_sock_accept: "
1441 "failed to setup tstream: %s\n",
1442 nt_errstr(status)));
1443 stream_terminate_connection(srv_conn, nt_errstr(status));
1444 return;
1446 socket_set_flags(srv_conn->socket, SOCKET_FLAG_NOCLOSE);
1449 dcesrv_conn->local_address = srv_conn->local_address;
1450 dcesrv_conn->remote_address = srv_conn->remote_address;
1452 srv_conn->private_data = dcesrv_conn;
1454 irpc_add_name(srv_conn->msg_ctx, "rpc_server");
1456 subreq = dcerpc_read_ncacn_packet_send(dcesrv_conn,
1457 dcesrv_conn->event_ctx,
1458 dcesrv_conn->stream);
1459 if (!subreq) {
1460 status = NT_STATUS_NO_MEMORY;
1461 DEBUG(0,("dcesrv_sock_accept: dcerpc_read_fragment_buffer_send(%s)\n",
1462 nt_errstr(status)));
1463 stream_terminate_connection(srv_conn, nt_errstr(status));
1464 return;
1466 tevent_req_set_callback(subreq, dcesrv_read_fragment_done, dcesrv_conn);
1468 return;
1471 static void dcesrv_read_fragment_done(struct tevent_req *subreq)
1473 struct dcesrv_connection *dce_conn = tevent_req_callback_data(subreq,
1474 struct dcesrv_connection);
1475 struct ncacn_packet *pkt;
1476 DATA_BLOB buffer;
1477 NTSTATUS status;
1479 status = dcerpc_read_ncacn_packet_recv(subreq, dce_conn,
1480 &pkt, &buffer);
1481 TALLOC_FREE(subreq);
1482 if (!NT_STATUS_IS_OK(status)) {
1483 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1484 return;
1487 status = dcesrv_process_ncacn_packet(dce_conn, pkt, buffer);
1488 if (!NT_STATUS_IS_OK(status)) {
1489 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1490 return;
1493 subreq = dcerpc_read_ncacn_packet_send(dce_conn,
1494 dce_conn->event_ctx,
1495 dce_conn->stream);
1496 if (!subreq) {
1497 status = NT_STATUS_NO_MEMORY;
1498 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1499 return;
1501 tevent_req_set_callback(subreq, dcesrv_read_fragment_done, dce_conn);
1504 static void dcesrv_sock_recv(struct stream_connection *conn, uint16_t flags)
1506 struct dcesrv_connection *dce_conn = talloc_get_type(conn->private_data,
1507 struct dcesrv_connection);
1508 dcesrv_terminate_connection(dce_conn, "dcesrv_sock_recv triggered");
1511 static void dcesrv_sock_send(struct stream_connection *conn, uint16_t flags)
1513 struct dcesrv_connection *dce_conn = talloc_get_type(conn->private_data,
1514 struct dcesrv_connection);
1515 dcesrv_terminate_connection(dce_conn, "dcesrv_sock_send triggered");
1519 static const struct stream_server_ops dcesrv_stream_ops = {
1520 .name = "rpc",
1521 .accept_connection = dcesrv_sock_accept,
1522 .recv_handler = dcesrv_sock_recv,
1523 .send_handler = dcesrv_sock_send,
1526 static NTSTATUS dcesrv_add_ep_unix(struct dcesrv_context *dce_ctx,
1527 struct loadparm_context *lp_ctx,
1528 struct dcesrv_endpoint *e,
1529 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1531 struct dcesrv_socket_context *dcesrv_sock;
1532 uint16_t port = 1;
1533 NTSTATUS status;
1535 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1536 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1538 /* remember the endpoint of this socket */
1539 dcesrv_sock->endpoint = e;
1540 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1542 status = stream_setup_socket(dcesrv_sock, event_ctx, lp_ctx,
1543 model_ops, &dcesrv_stream_ops,
1544 "unix", e->ep_description->endpoint, &port,
1545 lpcfg_socket_options(lp_ctx),
1546 dcesrv_sock);
1547 if (!NT_STATUS_IS_OK(status)) {
1548 DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n",
1549 e->ep_description->endpoint, nt_errstr(status)));
1552 return status;
1555 static NTSTATUS dcesrv_add_ep_ncalrpc(struct dcesrv_context *dce_ctx,
1556 struct loadparm_context *lp_ctx,
1557 struct dcesrv_endpoint *e,
1558 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1560 struct dcesrv_socket_context *dcesrv_sock;
1561 uint16_t port = 1;
1562 char *full_path;
1563 NTSTATUS status;
1565 if (!e->ep_description->endpoint) {
1566 /* No identifier specified: use DEFAULT.
1567 * DO NOT hardcode this value anywhere else. Rather, specify
1568 * no endpoint and let the epmapper worry about it. */
1569 e->ep_description->endpoint = talloc_strdup(dce_ctx, "DEFAULT");
1572 full_path = talloc_asprintf(dce_ctx, "%s/%s", lpcfg_ncalrpc_dir(lp_ctx),
1573 e->ep_description->endpoint);
1575 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1576 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1578 /* remember the endpoint of this socket */
1579 dcesrv_sock->endpoint = e;
1580 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1582 status = stream_setup_socket(dcesrv_sock, event_ctx, lp_ctx,
1583 model_ops, &dcesrv_stream_ops,
1584 "unix", full_path, &port,
1585 lpcfg_socket_options(lp_ctx),
1586 dcesrv_sock);
1587 if (!NT_STATUS_IS_OK(status)) {
1588 DEBUG(0,("service_setup_stream_socket(identifier=%s,path=%s) failed - %s\n",
1589 e->ep_description->endpoint, full_path, nt_errstr(status)));
1591 return status;
1594 static NTSTATUS dcesrv_add_ep_np(struct dcesrv_context *dce_ctx,
1595 struct loadparm_context *lp_ctx,
1596 struct dcesrv_endpoint *e,
1597 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1599 struct dcesrv_socket_context *dcesrv_sock;
1600 NTSTATUS status;
1602 if (e->ep_description->endpoint == NULL) {
1603 DEBUG(0, ("Endpoint mandatory for named pipes\n"));
1604 return NT_STATUS_INVALID_PARAMETER;
1607 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1608 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1610 /* remember the endpoint of this socket */
1611 dcesrv_sock->endpoint = e;
1612 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1614 status = tstream_setup_named_pipe(dce_ctx, event_ctx, lp_ctx,
1615 model_ops, &dcesrv_stream_ops,
1616 e->ep_description->endpoint,
1617 dcesrv_sock);
1618 if (!NT_STATUS_IS_OK(status)) {
1619 DEBUG(0,("stream_setup_named_pipe(pipe=%s) failed - %s\n",
1620 e->ep_description->endpoint, nt_errstr(status)));
1621 return status;
1624 return NT_STATUS_OK;
1628 add a socket address to the list of events, one event per dcerpc endpoint
1630 static NTSTATUS add_socket_rpc_tcp_iface(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e,
1631 struct tevent_context *event_ctx, const struct model_ops *model_ops,
1632 const char *address)
1634 struct dcesrv_socket_context *dcesrv_sock;
1635 uint16_t port = 0;
1636 NTSTATUS status;
1638 if (e->ep_description->endpoint) {
1639 port = atoi(e->ep_description->endpoint);
1642 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1643 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1645 /* remember the endpoint of this socket */
1646 dcesrv_sock->endpoint = e;
1647 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1649 status = stream_setup_socket(dcesrv_sock, event_ctx, dce_ctx->lp_ctx,
1650 model_ops, &dcesrv_stream_ops,
1651 "ipv4", address, &port,
1652 lpcfg_socket_options(dce_ctx->lp_ctx),
1653 dcesrv_sock);
1654 if (!NT_STATUS_IS_OK(status)) {
1655 DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) failed - %s\n",
1656 address, port, nt_errstr(status)));
1659 if (e->ep_description->endpoint == NULL) {
1660 e->ep_description->endpoint = talloc_asprintf(dce_ctx, "%d", port);
1663 return status;
1666 #include "lib/socket/netif.h" /* Included here to work around the fact that socket_wrapper redefines bind() */
1668 static NTSTATUS dcesrv_add_ep_tcp(struct dcesrv_context *dce_ctx,
1669 struct loadparm_context *lp_ctx,
1670 struct dcesrv_endpoint *e,
1671 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1673 NTSTATUS status;
1675 /* Add TCP/IP sockets */
1676 if (lpcfg_interfaces(lp_ctx) && lpcfg_bind_interfaces_only(lp_ctx)) {
1677 int num_interfaces;
1678 int i;
1679 struct interface *ifaces;
1681 load_interfaces(dce_ctx, lpcfg_interfaces(lp_ctx), &ifaces);
1683 num_interfaces = iface_count(ifaces);
1684 for(i = 0; i < num_interfaces; i++) {
1685 const char *address = iface_n_ip(ifaces, i);
1686 status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, address);
1687 NT_STATUS_NOT_OK_RETURN(status);
1689 } else {
1690 status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops,
1691 lpcfg_socket_address(lp_ctx));
1692 NT_STATUS_NOT_OK_RETURN(status);
1695 return NT_STATUS_OK;
1698 NTSTATUS dcesrv_add_ep(struct dcesrv_context *dce_ctx,
1699 struct loadparm_context *lp_ctx,
1700 struct dcesrv_endpoint *e,
1701 struct tevent_context *event_ctx,
1702 const struct model_ops *model_ops)
1704 switch (e->ep_description->transport) {
1705 case NCACN_UNIX_STREAM:
1706 return dcesrv_add_ep_unix(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1708 case NCALRPC:
1709 return dcesrv_add_ep_ncalrpc(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1711 case NCACN_IP_TCP:
1712 return dcesrv_add_ep_tcp(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1714 case NCACN_NP:
1715 return dcesrv_add_ep_np(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1717 default:
1718 return NT_STATUS_NOT_SUPPORTED;
1724 * retrieve credentials from a dce_call
1726 _PUBLIC_ struct cli_credentials *dcesrv_call_credentials(struct dcesrv_call_state *dce_call)
1728 return dce_call->conn->auth_state.session_info->credentials;
1732 * returns true if this is an authenticated call
1734 _PUBLIC_ bool dcesrv_call_authenticated(struct dcesrv_call_state *dce_call)
1736 enum security_user_level level;
1737 level = security_session_user_level(dce_call->conn->auth_state.session_info, NULL);
1738 return level >= SECURITY_USER;
1742 * retrieve account_name for a dce_call
1744 _PUBLIC_ const char *dcesrv_call_account_name(struct dcesrv_call_state *dce_call)
1746 return dce_call->context->conn->auth_state.session_info->info->account_name;