smbprinting: fix wrong == in shell tests
[Samba/gebeck_regimport.git] / source4 / rpc_server / dcerpc_server.c
blob1371ad9b360821c152d538304fa458a0f046012c
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"
42 /* this is only used when the client asks for an unknown interface */
43 #define DUMMY_ASSOC_GROUP 0x0FFFFFFF
45 extern const struct dcesrv_interface dcesrv_mgmt_interface;
49 find an association group given a assoc_group_id
51 static struct dcesrv_assoc_group *dcesrv_assoc_group_find(struct dcesrv_context *dce_ctx,
52 uint32_t id)
54 void *id_ptr;
56 id_ptr = idr_find(dce_ctx->assoc_groups_idr, id);
57 if (id_ptr == NULL) {
58 return NULL;
60 return talloc_get_type_abort(id_ptr, struct dcesrv_assoc_group);
64 take a reference to an existing association group
66 static struct dcesrv_assoc_group *dcesrv_assoc_group_reference(TALLOC_CTX *mem_ctx,
67 struct dcesrv_context *dce_ctx,
68 uint32_t id)
70 struct dcesrv_assoc_group *assoc_group;
72 assoc_group = dcesrv_assoc_group_find(dce_ctx, id);
73 if (assoc_group == NULL) {
74 DEBUG(0,(__location__ ": Failed to find assoc_group 0x%08x\n", id));
75 return NULL;
77 return talloc_reference(mem_ctx, assoc_group);
80 static int dcesrv_assoc_group_destructor(struct dcesrv_assoc_group *assoc_group)
82 int ret;
83 ret = idr_remove(assoc_group->dce_ctx->assoc_groups_idr, assoc_group->id);
84 if (ret != 0) {
85 DEBUG(0,(__location__ ": Failed to remove assoc_group 0x%08x\n",
86 assoc_group->id));
88 return 0;
92 allocate a new association group
94 static struct dcesrv_assoc_group *dcesrv_assoc_group_new(TALLOC_CTX *mem_ctx,
95 struct dcesrv_context *dce_ctx)
97 struct dcesrv_assoc_group *assoc_group;
98 int id;
100 assoc_group = talloc_zero(mem_ctx, struct dcesrv_assoc_group);
101 if (assoc_group == NULL) {
102 return NULL;
105 id = idr_get_new_random(dce_ctx->assoc_groups_idr, assoc_group, UINT16_MAX);
106 if (id == -1) {
107 talloc_free(assoc_group);
108 DEBUG(0,(__location__ ": Out of association groups!\n"));
109 return NULL;
112 assoc_group->id = id;
113 assoc_group->dce_ctx = dce_ctx;
115 talloc_set_destructor(assoc_group, dcesrv_assoc_group_destructor);
117 return assoc_group;
122 see if two endpoints match
124 static bool endpoints_match(const struct dcerpc_binding *ep1,
125 const struct dcerpc_binding *ep2)
127 if (ep1->transport != ep2->transport) {
128 return false;
131 if (!ep1->endpoint || !ep2->endpoint) {
132 return ep1->endpoint == ep2->endpoint;
135 if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
136 return false;
138 return true;
142 find an endpoint in the dcesrv_context
144 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
145 const struct dcerpc_binding *ep_description)
147 struct dcesrv_endpoint *ep;
148 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
149 if (endpoints_match(ep->ep_description, ep_description)) {
150 return ep;
153 return NULL;
157 find a registered context_id from a bind or alter_context
159 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn,
160 uint32_t context_id)
162 struct dcesrv_connection_context *c;
163 for (c=conn->contexts;c;c=c->next) {
164 if (c->context_id == context_id) return c;
166 return NULL;
170 see if a uuid and if_version match to an interface
172 static bool interface_match(const struct dcesrv_interface *if1,
173 const struct dcesrv_interface *if2)
175 return (if1->syntax_id.if_version == if2->syntax_id.if_version &&
176 GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
180 find the interface operations on an endpoint
182 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
183 const struct dcesrv_interface *iface)
185 struct dcesrv_if_list *ifl;
186 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
187 if (interface_match(&(ifl->iface), iface)) {
188 return &(ifl->iface);
191 return NULL;
195 see if a uuid and if_version match to an interface
197 static bool interface_match_by_uuid(const struct dcesrv_interface *iface,
198 const struct GUID *uuid, uint32_t if_version)
200 return (iface->syntax_id.if_version == if_version &&
201 GUID_equal(&iface->syntax_id.uuid, uuid));
205 find the interface operations on an endpoint by uuid
207 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
208 const struct GUID *uuid, uint32_t if_version)
210 struct dcesrv_if_list *ifl;
211 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
212 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
213 return &(ifl->iface);
216 return NULL;
220 find the earlier parts of a fragmented call awaiting reassembily
222 static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
224 struct dcesrv_call_state *c;
225 for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
226 if (c->pkt.call_id == call_id) {
227 return c;
230 return NULL;
234 register an interface on an endpoint
236 _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
237 const char *ep_name,
238 const struct dcesrv_interface *iface,
239 const struct security_descriptor *sd)
241 struct dcesrv_endpoint *ep;
242 struct dcesrv_if_list *ifl;
243 struct dcerpc_binding *binding;
244 bool add_ep = false;
245 NTSTATUS status;
247 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
249 if (NT_STATUS_IS_ERR(status)) {
250 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
251 return status;
254 /* check if this endpoint exists
256 if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
257 ep = talloc(dce_ctx, struct dcesrv_endpoint);
258 if (!ep) {
259 return NT_STATUS_NO_MEMORY;
261 ZERO_STRUCTP(ep);
262 ep->ep_description = talloc_reference(ep, binding);
263 add_ep = true;
265 /* add mgmt interface */
266 ifl = talloc(dce_ctx, struct dcesrv_if_list);
267 if (!ifl) {
268 return NT_STATUS_NO_MEMORY;
271 memcpy(&(ifl->iface), &dcesrv_mgmt_interface,
272 sizeof(struct dcesrv_interface));
274 DLIST_ADD(ep->interface_list, ifl);
277 /* see if the interface is already registered on te endpoint */
278 if (find_interface(ep, iface)!=NULL) {
279 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
280 iface->name, ep_name));
281 return NT_STATUS_OBJECT_NAME_COLLISION;
284 /* talloc a new interface list element */
285 ifl = talloc(dce_ctx, struct dcesrv_if_list);
286 if (!ifl) {
287 return NT_STATUS_NO_MEMORY;
290 /* copy the given interface struct to the one on the endpoints interface list */
291 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
293 /* if we have a security descriptor given,
294 * we should see if we can set it up on the endpoint
296 if (sd != NULL) {
297 /* if there's currently no security descriptor given on the endpoint
298 * we try to set it
300 if (ep->sd == NULL) {
301 ep->sd = security_descriptor_copy(dce_ctx, sd);
304 /* if now there's no security descriptor given on the endpoint
305 * something goes wrong, either we failed to copy the security descriptor
306 * or there was already one on the endpoint
308 if (ep->sd != NULL) {
309 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
310 " on endpoint '%s'\n",
311 iface->name, ep_name));
312 if (add_ep) free(ep);
313 free(ifl);
314 return NT_STATUS_OBJECT_NAME_COLLISION;
318 /* finally add the interface on the endpoint */
319 DLIST_ADD(ep->interface_list, ifl);
321 /* if it's a new endpoint add it to the dcesrv_context */
322 if (add_ep) {
323 DLIST_ADD(dce_ctx->endpoint_list, ep);
326 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
327 iface->name, ep_name));
329 return NT_STATUS_OK;
332 NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
333 DATA_BLOB *session_key)
335 if (p->auth_state.session_info->session_key.length) {
336 *session_key = p->auth_state.session_info->session_key;
337 return NT_STATUS_OK;
339 return NT_STATUS_NO_USER_SESSION_KEY;
343 fetch the user session key - may be default (above) or the SMB session key
345 The key is always truncated to 16 bytes
347 _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
348 DATA_BLOB *session_key)
350 NTSTATUS status = p->auth_state.session_key(p, session_key);
351 if (!NT_STATUS_IS_OK(status)) {
352 return status;
355 session_key->length = MIN(session_key->length, 16);
357 return NT_STATUS_OK;
361 connect to a dcerpc endpoint
363 _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
364 TALLOC_CTX *mem_ctx,
365 const struct dcesrv_endpoint *ep,
366 struct auth_session_info *session_info,
367 struct tevent_context *event_ctx,
368 struct messaging_context *msg_ctx,
369 struct server_id server_id,
370 uint32_t state_flags,
371 struct dcesrv_connection **_p)
373 struct dcesrv_connection *p;
375 if (!session_info) {
376 return NT_STATUS_ACCESS_DENIED;
379 p = talloc(mem_ctx, struct dcesrv_connection);
380 NT_STATUS_HAVE_NO_MEMORY(p);
382 if (!talloc_reference(p, session_info)) {
383 talloc_free(p);
384 return NT_STATUS_NO_MEMORY;
387 p->dce_ctx = dce_ctx;
388 p->endpoint = ep;
389 p->contexts = NULL;
390 p->call_list = NULL;
391 p->packet_log_dir = lpcfg_lockdir(dce_ctx->lp_ctx);
392 p->incoming_fragmented_call_list = NULL;
393 p->pending_call_list = NULL;
394 p->cli_max_recv_frag = 0;
395 p->partial_input = data_blob(NULL, 0);
396 p->auth_state.auth_info = NULL;
397 p->auth_state.gensec_security = NULL;
398 p->auth_state.session_info = session_info;
399 p->auth_state.session_key = dcesrv_generic_session_key;
400 p->event_ctx = event_ctx;
401 p->msg_ctx = msg_ctx;
402 p->server_id = server_id;
403 p->processing = false;
404 p->state_flags = state_flags;
405 ZERO_STRUCT(p->transport);
407 *_p = p;
408 return NT_STATUS_OK;
412 move a call from an existing linked list to the specified list. This
413 prevents bugs where we forget to remove the call from a previous
414 list when moving it.
416 static void dcesrv_call_set_list(struct dcesrv_call_state *call,
417 enum dcesrv_call_list list)
419 switch (call->list) {
420 case DCESRV_LIST_NONE:
421 break;
422 case DCESRV_LIST_CALL_LIST:
423 DLIST_REMOVE(call->conn->call_list, call);
424 break;
425 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
426 DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
427 break;
428 case DCESRV_LIST_PENDING_CALL_LIST:
429 DLIST_REMOVE(call->conn->pending_call_list, call);
430 break;
432 call->list = list;
433 switch (list) {
434 case DCESRV_LIST_NONE:
435 break;
436 case DCESRV_LIST_CALL_LIST:
437 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
438 break;
439 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
440 DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
441 break;
442 case DCESRV_LIST_PENDING_CALL_LIST:
443 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
444 break;
450 return a dcerpc bind_nak
452 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
454 struct ncacn_packet pkt;
455 struct data_blob_list_item *rep;
456 NTSTATUS status;
458 /* setup a bind_nak */
459 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
460 pkt.auth_length = 0;
461 pkt.call_id = call->pkt.call_id;
462 pkt.ptype = DCERPC_PKT_BIND_NAK;
463 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
464 pkt.u.bind_nak.reject_reason = reason;
465 if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
466 pkt.u.bind_nak.versions.v.num_versions = 0;
469 rep = talloc(call, struct data_blob_list_item);
470 if (!rep) {
471 return NT_STATUS_NO_MEMORY;
474 status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
475 if (!NT_STATUS_IS_OK(status)) {
476 return status;
479 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
481 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
482 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
484 if (call->conn->call_list && call->conn->call_list->replies) {
485 if (call->conn->transport.report_output_data) {
486 call->conn->transport.report_output_data(call->conn);
490 return NT_STATUS_OK;
493 static int dcesrv_connection_context_destructor(struct dcesrv_connection_context *c)
495 DLIST_REMOVE(c->conn->contexts, c);
497 if (c->iface && c->iface->unbind) {
498 c->iface->unbind(c, c->iface);
501 return 0;
505 handle a bind request
507 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
509 uint32_t if_version, transfer_syntax_version;
510 struct GUID uuid, *transfer_syntax_uuid;
511 struct ncacn_packet pkt;
512 struct data_blob_list_item *rep;
513 NTSTATUS status;
514 uint32_t result=0, reason=0;
515 uint32_t context_id;
516 const struct dcesrv_interface *iface;
517 uint32_t extra_flags = 0;
520 if provided, check the assoc_group is valid
522 if (call->pkt.u.bind.assoc_group_id != 0 &&
523 lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
524 dcesrv_assoc_group_find(call->conn->dce_ctx, call->pkt.u.bind.assoc_group_id) == NULL) {
525 return dcesrv_bind_nak(call, 0);
528 if (call->pkt.u.bind.num_contexts < 1 ||
529 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
530 return dcesrv_bind_nak(call, 0);
533 context_id = call->pkt.u.bind.ctx_list[0].context_id;
535 /* you can't bind twice on one context */
536 if (dcesrv_find_context(call->conn, context_id) != NULL) {
537 return dcesrv_bind_nak(call, 0);
540 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
541 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
543 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
544 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
545 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
546 ndr_transfer_syntax.if_version != transfer_syntax_version) {
547 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
548 /* we only do NDR encoded dcerpc */
549 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
550 talloc_free(uuid_str);
551 return dcesrv_bind_nak(call, 0);
554 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
555 if (iface == NULL) {
556 char *uuid_str = GUID_string(call, &uuid);
557 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
558 talloc_free(uuid_str);
560 /* we don't know about that interface */
561 result = DCERPC_BIND_PROVIDER_REJECT;
562 reason = DCERPC_BIND_REASON_ASYNTAX;
565 if (iface) {
566 /* add this context to the list of available context_ids */
567 struct dcesrv_connection_context *context = talloc(call->conn,
568 struct dcesrv_connection_context);
569 if (context == NULL) {
570 return dcesrv_bind_nak(call, 0);
572 context->conn = call->conn;
573 context->iface = iface;
574 context->context_id = context_id;
575 if (call->pkt.u.bind.assoc_group_id != 0) {
576 context->assoc_group = dcesrv_assoc_group_reference(context,
577 call->conn->dce_ctx,
578 call->pkt.u.bind.assoc_group_id);
579 } else {
580 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
582 if (context->assoc_group == NULL) {
583 talloc_free(context);
584 return dcesrv_bind_nak(call, 0);
586 context->private_data = NULL;
587 DLIST_ADD(call->conn->contexts, context);
588 call->context = context;
589 talloc_set_destructor(context, dcesrv_connection_context_destructor);
591 status = iface->bind(call, iface, if_version);
592 if (!NT_STATUS_IS_OK(status)) {
593 char *uuid_str = GUID_string(call, &uuid);
594 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
595 uuid_str, if_version, nt_errstr(status)));
596 talloc_free(uuid_str);
597 /* we don't want to trigger the iface->unbind() hook */
598 context->iface = NULL;
599 talloc_free(call->context);
600 call->context = NULL;
601 return dcesrv_bind_nak(call, 0);
605 if (call->conn->cli_max_recv_frag == 0) {
606 call->conn->cli_max_recv_frag = MIN(0x2000, call->pkt.u.bind.max_recv_frag);
609 if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) &&
610 lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","header signing", false)) {
611 call->conn->state_flags |= DCESRV_CALL_STATE_FLAG_HEADER_SIGNING;
612 extra_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
615 /* handle any authentication that is being requested */
616 if (!dcesrv_auth_bind(call)) {
617 talloc_free(call->context);
618 call->context = NULL;
619 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
622 /* setup a bind_ack */
623 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
624 pkt.auth_length = 0;
625 pkt.call_id = call->pkt.call_id;
626 pkt.ptype = DCERPC_PKT_BIND_ACK;
627 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
628 pkt.u.bind_ack.max_xmit_frag = call->conn->cli_max_recv_frag;
629 pkt.u.bind_ack.max_recv_frag = 0x2000;
632 make it possible for iface->bind() to specify the assoc_group_id
633 This helps the openchange mapiproxy plugin to work correctly.
635 metze
637 if (call->context) {
638 pkt.u.bind_ack.assoc_group_id = call->context->assoc_group->id;
639 } else {
640 pkt.u.bind_ack.assoc_group_id = DUMMY_ASSOC_GROUP;
643 if (iface) {
644 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
645 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
646 } else {
647 pkt.u.bind_ack.secondary_address = "";
649 pkt.u.bind_ack.num_results = 1;
650 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
651 if (!pkt.u.bind_ack.ctx_list) {
652 talloc_free(call->context);
653 call->context = NULL;
654 return NT_STATUS_NO_MEMORY;
656 pkt.u.bind_ack.ctx_list[0].result = result;
657 pkt.u.bind_ack.ctx_list[0].reason = reason;
658 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
659 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
661 status = dcesrv_auth_bind_ack(call, &pkt);
662 if (!NT_STATUS_IS_OK(status)) {
663 talloc_free(call->context);
664 call->context = NULL;
665 return dcesrv_bind_nak(call, 0);
668 rep = talloc(call, struct data_blob_list_item);
669 if (!rep) {
670 talloc_free(call->context);
671 call->context = NULL;
672 return NT_STATUS_NO_MEMORY;
675 status = ncacn_push_auth(&rep->blob, call, &pkt,
676 call->conn->auth_state.auth_info);
677 if (!NT_STATUS_IS_OK(status)) {
678 talloc_free(call->context);
679 call->context = NULL;
680 return status;
683 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
685 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
686 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
688 if (call->conn->call_list && call->conn->call_list->replies) {
689 if (call->conn->transport.report_output_data) {
690 call->conn->transport.report_output_data(call->conn);
694 return NT_STATUS_OK;
699 handle a auth3 request
701 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
703 /* handle the auth3 in the auth code */
704 if (!dcesrv_auth_auth3(call)) {
705 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
708 talloc_free(call);
710 /* we don't send a reply to a auth3 request, except by a
711 fault */
712 return NT_STATUS_OK;
717 handle a bind request
719 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
721 uint32_t if_version, transfer_syntax_version;
722 struct dcesrv_connection_context *context;
723 const struct dcesrv_interface *iface;
724 struct GUID uuid, *transfer_syntax_uuid;
725 NTSTATUS status;
727 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
728 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
730 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
731 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
732 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
733 ndr_transfer_syntax.if_version != transfer_syntax_version) {
734 /* we only do NDR encoded dcerpc */
735 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
738 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
739 if (iface == NULL) {
740 char *uuid_str = GUID_string(call, &uuid);
741 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
742 talloc_free(uuid_str);
743 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
746 /* add this context to the list of available context_ids */
747 context = talloc(call->conn, struct dcesrv_connection_context);
748 if (context == NULL) {
749 return NT_STATUS_NO_MEMORY;
751 context->conn = call->conn;
752 context->iface = iface;
753 context->context_id = context_id;
754 if (call->pkt.u.alter.assoc_group_id != 0) {
755 context->assoc_group = dcesrv_assoc_group_reference(context,
756 call->conn->dce_ctx,
757 call->pkt.u.alter.assoc_group_id);
758 } else {
759 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
761 if (context->assoc_group == NULL) {
762 talloc_free(context);
763 call->context = NULL;
764 return NT_STATUS_NO_MEMORY;
766 context->private_data = NULL;
767 DLIST_ADD(call->conn->contexts, context);
768 call->context = context;
769 talloc_set_destructor(context, dcesrv_connection_context_destructor);
771 status = iface->bind(call, iface, if_version);
772 if (!NT_STATUS_IS_OK(status)) {
773 /* we don't want to trigger the iface->unbind() hook */
774 context->iface = NULL;
775 talloc_free(context);
776 call->context = NULL;
777 return status;
780 return NT_STATUS_OK;
785 handle a alter context request
787 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
789 struct ncacn_packet pkt;
790 struct data_blob_list_item *rep;
791 NTSTATUS status;
792 uint32_t result=0, reason=0;
793 uint32_t context_id;
795 /* handle any authentication that is being requested */
796 if (!dcesrv_auth_alter(call)) {
797 /* TODO: work out the right reject code */
798 result = DCERPC_BIND_PROVIDER_REJECT;
799 reason = DCERPC_BIND_REASON_ASYNTAX;
802 context_id = call->pkt.u.alter.ctx_list[0].context_id;
804 /* see if they are asking for a new interface */
805 if (result == 0) {
806 call->context = dcesrv_find_context(call->conn, context_id);
807 if (!call->context) {
808 status = dcesrv_alter_new_context(call, context_id);
809 if (!NT_STATUS_IS_OK(status)) {
810 result = DCERPC_BIND_PROVIDER_REJECT;
811 reason = DCERPC_BIND_REASON_ASYNTAX;
816 if (result == 0 &&
817 call->pkt.u.alter.assoc_group_id != 0 &&
818 lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
819 call->pkt.u.alter.assoc_group_id != call->context->assoc_group->id) {
820 DEBUG(0,(__location__ ": Failed attempt to use new assoc_group in alter context (0x%08x 0x%08x)\n",
821 call->context->assoc_group->id, call->pkt.u.alter.assoc_group_id));
822 /* TODO: can they ask for a new association group? */
823 result = DCERPC_BIND_PROVIDER_REJECT;
824 reason = DCERPC_BIND_REASON_ASYNTAX;
827 /* setup a alter_resp */
828 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
829 pkt.auth_length = 0;
830 pkt.call_id = call->pkt.call_id;
831 pkt.ptype = DCERPC_PKT_ALTER_RESP;
832 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
833 pkt.u.alter_resp.max_xmit_frag = 0x2000;
834 pkt.u.alter_resp.max_recv_frag = 0x2000;
835 if (result == 0) {
836 pkt.u.alter_resp.assoc_group_id = call->context->assoc_group->id;
837 } else {
838 pkt.u.alter_resp.assoc_group_id = 0;
840 pkt.u.alter_resp.num_results = 1;
841 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
842 if (!pkt.u.alter_resp.ctx_list) {
843 return NT_STATUS_NO_MEMORY;
845 pkt.u.alter_resp.ctx_list[0].result = result;
846 pkt.u.alter_resp.ctx_list[0].reason = reason;
847 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
848 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
849 pkt.u.alter_resp.secondary_address = "";
851 status = dcesrv_auth_alter_ack(call, &pkt);
852 if (!NT_STATUS_IS_OK(status)) {
853 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
854 || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
855 || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
856 || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
857 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
859 return dcesrv_fault(call, 0);
862 rep = talloc(call, struct data_blob_list_item);
863 if (!rep) {
864 return NT_STATUS_NO_MEMORY;
867 status = ncacn_push_auth(&rep->blob, call, &pkt, call->conn->auth_state.auth_info);
868 if (!NT_STATUS_IS_OK(status)) {
869 return status;
872 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
874 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
875 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
877 if (call->conn->call_list && call->conn->call_list->replies) {
878 if (call->conn->transport.report_output_data) {
879 call->conn->transport.report_output_data(call->conn);
883 return NT_STATUS_OK;
887 possibly save the call for inspection with ndrdump
889 static void dcesrv_save_call(struct dcesrv_call_state *call, const char *why)
891 #ifdef DEVELOPER
892 char *fname;
893 const char *dump_dir;
894 dump_dir = lpcfg_parm_string(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv", "stubs directory");
895 if (!dump_dir) {
896 return;
898 fname = talloc_asprintf(call, "%s/RPC-%s-%u-%s.dat",
899 dump_dir,
900 call->context->iface->name,
901 call->pkt.u.request.opnum,
902 why);
903 if (file_save(fname, call->pkt.u.request.stub_and_verifier.data, call->pkt.u.request.stub_and_verifier.length)) {
904 DEBUG(0,("RPC SAVED %s\n", fname));
906 talloc_free(fname);
907 #endif
911 handle a dcerpc request packet
913 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
915 struct ndr_pull *pull;
916 NTSTATUS status;
917 struct dcesrv_connection_context *context;
919 /* if authenticated, and the mech we use can't do async replies, don't use them... */
920 if (call->conn->auth_state.gensec_security &&
921 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
922 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
925 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
926 if (context == NULL) {
927 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
930 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
931 NT_STATUS_HAVE_NO_MEMORY(pull);
933 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
935 call->context = context;
936 call->ndr_pull = pull;
938 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
939 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
942 /* unravel the NDR for the packet */
943 status = context->iface->ndr_pull(call, call, pull, &call->r);
944 if (!NT_STATUS_IS_OK(status)) {
945 if (call->fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
946 /* we got an unknown call */
947 DEBUG(3,(__location__ ": Unknown RPC call %u on %s\n",
948 call->pkt.u.request.opnum, context->iface->name));
949 dcesrv_save_call(call, "unknown");
950 } else {
951 dcesrv_save_call(call, "pullfail");
953 return dcesrv_fault(call, call->fault_code);
956 if (pull->offset != pull->data_size) {
957 dcesrv_save_call(call, "extrabytes");
958 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
959 pull->data_size - pull->offset));
962 /* call the dispatch function */
963 status = context->iface->dispatch(call, call, call->r);
964 if (!NT_STATUS_IS_OK(status)) {
965 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
966 context->iface->name,
967 call->pkt.u.request.opnum,
968 dcerpc_errstr(pull, call->fault_code)));
969 return dcesrv_fault(call, call->fault_code);
972 /* add the call to the pending list */
973 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
975 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
976 return NT_STATUS_OK;
979 return dcesrv_reply(call);
984 remove the call from the right list when freed
986 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
988 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
989 return 0;
992 _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_local_address(struct dcesrv_connection *conn)
994 return conn->local_address;
997 _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_remote_address(struct dcesrv_connection *conn)
999 return conn->remote_address;
1003 process some input to a dcerpc endpoint server.
1005 NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
1006 struct ncacn_packet *pkt,
1007 DATA_BLOB blob)
1009 NTSTATUS status;
1010 struct dcesrv_call_state *call;
1012 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1013 if (!call) {
1014 data_blob_free(&blob);
1015 talloc_free(pkt);
1016 return NT_STATUS_NO_MEMORY;
1018 call->conn = dce_conn;
1019 call->event_ctx = dce_conn->event_ctx;
1020 call->msg_ctx = dce_conn->msg_ctx;
1021 call->state_flags = call->conn->state_flags;
1022 call->time = timeval_current();
1023 call->list = DCESRV_LIST_NONE;
1025 talloc_steal(call, pkt);
1026 talloc_steal(call, blob.data);
1027 call->pkt = *pkt;
1029 talloc_set_destructor(call, dcesrv_call_dequeue);
1031 /* we have to check the signing here, before combining the
1032 pdus */
1033 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1034 !dcesrv_auth_request(call, &blob)) {
1035 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1038 /* see if this is a continued packet */
1039 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1040 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1041 struct dcesrv_call_state *call2 = call;
1042 uint32_t alloc_size;
1044 /* we only allow fragmented requests, no other packet types */
1045 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1046 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1049 /* this is a continuation of an existing call - find the call
1050 then tack it on the end */
1051 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1052 if (!call) {
1053 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1056 if (call->pkt.ptype != call2->pkt.ptype) {
1057 /* trying to play silly buggers are we? */
1058 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1061 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1062 call2->pkt.u.request.stub_and_verifier.length;
1063 if (call->pkt.u.request.alloc_hint > alloc_size) {
1064 alloc_size = call->pkt.u.request.alloc_hint;
1067 call->pkt.u.request.stub_and_verifier.data =
1068 talloc_realloc(call,
1069 call->pkt.u.request.stub_and_verifier.data,
1070 uint8_t, alloc_size);
1071 if (!call->pkt.u.request.stub_and_verifier.data) {
1072 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1074 memcpy(call->pkt.u.request.stub_and_verifier.data +
1075 call->pkt.u.request.stub_and_verifier.length,
1076 call2->pkt.u.request.stub_and_verifier.data,
1077 call2->pkt.u.request.stub_and_verifier.length);
1078 call->pkt.u.request.stub_and_verifier.length +=
1079 call2->pkt.u.request.stub_and_verifier.length;
1081 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1083 talloc_free(call2);
1086 /* this may not be the last pdu in the chain - if its isn't then
1087 just put it on the incoming_fragmented_call_list and wait for the rest */
1088 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1089 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1090 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1091 return NT_STATUS_OK;
1094 /* This removes any fragments we may have had stashed away */
1095 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1097 switch (call->pkt.ptype) {
1098 case DCERPC_PKT_BIND:
1099 status = dcesrv_bind(call);
1100 break;
1101 case DCERPC_PKT_AUTH3:
1102 status = dcesrv_auth3(call);
1103 break;
1104 case DCERPC_PKT_ALTER:
1105 status = dcesrv_alter(call);
1106 break;
1107 case DCERPC_PKT_REQUEST:
1108 status = dcesrv_request(call);
1109 break;
1110 default:
1111 status = NT_STATUS_INVALID_PARAMETER;
1112 break;
1115 /* if we are going to be sending a reply then add
1116 it to the list of pending calls. We add it to the end to keep the call
1117 list in the order we will answer */
1118 if (!NT_STATUS_IS_OK(status)) {
1119 talloc_free(call);
1122 return status;
1125 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1126 struct loadparm_context *lp_ctx,
1127 const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1129 NTSTATUS status;
1130 struct dcesrv_context *dce_ctx;
1131 int i;
1133 if (!endpoint_servers) {
1134 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1135 return NT_STATUS_INTERNAL_ERROR;
1138 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1139 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1140 dce_ctx->endpoint_list = NULL;
1141 dce_ctx->lp_ctx = lp_ctx;
1142 dce_ctx->assoc_groups_idr = idr_init(dce_ctx);
1143 NT_STATUS_HAVE_NO_MEMORY(dce_ctx->assoc_groups_idr);
1145 for (i=0;endpoint_servers[i];i++) {
1146 const struct dcesrv_endpoint_server *ep_server;
1148 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1149 if (!ep_server) {
1150 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1151 return NT_STATUS_INTERNAL_ERROR;
1154 status = ep_server->init_server(dce_ctx, ep_server);
1155 if (!NT_STATUS_IS_OK(status)) {
1156 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1157 nt_errstr(status)));
1158 return status;
1162 *_dce_ctx = dce_ctx;
1163 return NT_STATUS_OK;
1166 /* the list of currently registered DCERPC endpoint servers.
1168 static struct ep_server {
1169 struct dcesrv_endpoint_server *ep_server;
1170 } *ep_servers = NULL;
1171 static int num_ep_servers;
1174 register a DCERPC endpoint server.
1176 The 'name' can be later used by other backends to find the operations
1177 structure for this backend.
1179 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1181 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1183 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1185 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1186 /* its already registered! */
1187 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1188 ep_server->name));
1189 return NT_STATUS_OBJECT_NAME_COLLISION;
1192 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1193 if (!ep_servers) {
1194 smb_panic("out of memory in dcerpc_register");
1197 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1198 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1200 num_ep_servers++;
1202 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1203 ep_server->name));
1205 return NT_STATUS_OK;
1209 return the operations structure for a named backend of the specified type
1211 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1213 int i;
1215 for (i=0;i<num_ep_servers;i++) {
1216 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1217 return ep_servers[i].ep_server;
1221 return NULL;
1224 void dcerpc_server_init(struct loadparm_context *lp_ctx)
1226 static bool initialized;
1227 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
1228 STATIC_dcerpc_server_MODULES_PROTO;
1229 init_module_fn static_init[] = { STATIC_dcerpc_server_MODULES };
1230 init_module_fn *shared_init;
1232 if (initialized) {
1233 return;
1235 initialized = true;
1237 shared_init = load_samba_modules(NULL, lp_ctx, "dcerpc_server");
1239 run_init_functions(static_init);
1240 run_init_functions(shared_init);
1242 talloc_free(shared_init);
1246 return the DCERPC module version, and the size of some critical types
1247 This can be used by endpoint server modules to either detect compilation errors, or provide
1248 multiple implementations for different smbd compilation options in one module
1250 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1252 static const struct dcesrv_critical_sizes critical_sizes = {
1253 DCERPC_MODULE_VERSION,
1254 sizeof(struct dcesrv_context),
1255 sizeof(struct dcesrv_endpoint),
1256 sizeof(struct dcesrv_endpoint_server),
1257 sizeof(struct dcesrv_interface),
1258 sizeof(struct dcesrv_if_list),
1259 sizeof(struct dcesrv_connection),
1260 sizeof(struct dcesrv_call_state),
1261 sizeof(struct dcesrv_auth),
1262 sizeof(struct dcesrv_handle)
1265 return &critical_sizes;
1268 static void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, const char *reason)
1270 struct stream_connection *srv_conn;
1271 srv_conn = talloc_get_type(dce_conn->transport.private_data,
1272 struct stream_connection);
1274 stream_terminate_connection(srv_conn, reason);
1276 /* We need this include to be able to compile on some plateforms
1277 * (ie. freebsd 7.2) as it seems that <sys/uio.h> is not included
1278 * correctly.
1279 * It has to be that deep because otherwise we have a conflict on
1280 * const struct dcesrv_interface declaration.
1281 * This is mostly due to socket_wrapper defining #define bind swrap_bind
1282 * which conflict with the bind used before.
1284 #include "system/network.h"
1286 struct dcesrv_sock_reply_state {
1287 struct dcesrv_connection *dce_conn;
1288 struct dcesrv_call_state *call;
1289 struct iovec iov;
1292 static void dcesrv_sock_reply_done(struct tevent_req *subreq);
1294 static void dcesrv_sock_report_output_data(struct dcesrv_connection *dce_conn)
1296 struct dcesrv_call_state *call;
1298 call = dce_conn->call_list;
1299 if (!call || !call->replies) {
1300 return;
1303 while (call->replies) {
1304 struct data_blob_list_item *rep = call->replies;
1305 struct dcesrv_sock_reply_state *substate;
1306 struct tevent_req *subreq;
1308 substate = talloc(call, struct dcesrv_sock_reply_state);
1309 if (!substate) {
1310 dcesrv_terminate_connection(dce_conn, "no memory");
1311 return;
1314 substate->dce_conn = dce_conn;
1315 substate->call = NULL;
1317 DLIST_REMOVE(call->replies, rep);
1319 if (call->replies == NULL) {
1320 substate->call = call;
1323 substate->iov.iov_base = (void *) rep->blob.data;
1324 substate->iov.iov_len = rep->blob.length;
1326 subreq = tstream_writev_queue_send(substate,
1327 dce_conn->event_ctx,
1328 dce_conn->stream,
1329 dce_conn->send_queue,
1330 &substate->iov, 1);
1331 if (!subreq) {
1332 dcesrv_terminate_connection(dce_conn, "no memory");
1333 return;
1335 tevent_req_set_callback(subreq, dcesrv_sock_reply_done,
1336 substate);
1339 DLIST_REMOVE(call->conn->call_list, call);
1340 call->list = DCESRV_LIST_NONE;
1343 static void dcesrv_sock_reply_done(struct tevent_req *subreq)
1345 struct dcesrv_sock_reply_state *substate = tevent_req_callback_data(subreq,
1346 struct dcesrv_sock_reply_state);
1347 int ret;
1348 int sys_errno;
1349 NTSTATUS status;
1350 struct dcesrv_call_state *call = substate->call;
1352 ret = tstream_writev_queue_recv(subreq, &sys_errno);
1353 TALLOC_FREE(subreq);
1354 if (ret == -1) {
1355 status = map_nt_error_from_unix(sys_errno);
1356 dcesrv_terminate_connection(substate->dce_conn, nt_errstr(status));
1357 return;
1360 talloc_free(substate);
1361 if (call) {
1362 talloc_free(call);
1369 struct dcesrv_socket_context {
1370 const struct dcesrv_endpoint *endpoint;
1371 struct dcesrv_context *dcesrv_ctx;
1375 static void dcesrv_read_fragment_done(struct tevent_req *subreq);
1377 static void dcesrv_sock_accept(struct stream_connection *srv_conn)
1379 NTSTATUS status;
1380 struct dcesrv_socket_context *dcesrv_sock =
1381 talloc_get_type(srv_conn->private_data, struct dcesrv_socket_context);
1382 struct dcesrv_connection *dcesrv_conn = NULL;
1383 int ret;
1384 struct tevent_req *subreq;
1385 struct loadparm_context *lp_ctx = dcesrv_sock->dcesrv_ctx->lp_ctx;
1387 if (!srv_conn->session_info) {
1388 status = auth_anonymous_session_info(srv_conn,
1389 lp_ctx,
1390 &srv_conn->session_info);
1391 if (!NT_STATUS_IS_OK(status)) {
1392 DEBUG(0,("dcesrv_sock_accept: auth_anonymous_session_info failed: %s\n",
1393 nt_errstr(status)));
1394 stream_terminate_connection(srv_conn, nt_errstr(status));
1395 return;
1399 status = dcesrv_endpoint_connect(dcesrv_sock->dcesrv_ctx,
1400 srv_conn,
1401 dcesrv_sock->endpoint,
1402 srv_conn->session_info,
1403 srv_conn->event.ctx,
1404 srv_conn->msg_ctx,
1405 srv_conn->server_id,
1406 DCESRV_CALL_STATE_FLAG_MAY_ASYNC,
1407 &dcesrv_conn);
1408 if (!NT_STATUS_IS_OK(status)) {
1409 DEBUG(0,("dcesrv_sock_accept: dcesrv_endpoint_connect failed: %s\n",
1410 nt_errstr(status)));
1411 stream_terminate_connection(srv_conn, nt_errstr(status));
1412 return;
1415 dcesrv_conn->transport.private_data = srv_conn;
1416 dcesrv_conn->transport.report_output_data = dcesrv_sock_report_output_data;
1418 TALLOC_FREE(srv_conn->event.fde);
1420 dcesrv_conn->send_queue = tevent_queue_create(dcesrv_conn, "dcesrv send queue");
1421 if (!dcesrv_conn->send_queue) {
1422 status = NT_STATUS_NO_MEMORY;
1423 DEBUG(0,("dcesrv_sock_accept: tevent_queue_create(%s)\n",
1424 nt_errstr(status)));
1425 stream_terminate_connection(srv_conn, nt_errstr(status));
1426 return;
1429 if (dcesrv_sock->endpoint->ep_description->transport == NCACN_NP) {
1430 dcesrv_conn->auth_state.session_key = dcesrv_inherited_session_key;
1431 dcesrv_conn->stream = talloc_move(dcesrv_conn,
1432 &srv_conn->tstream);
1433 } else {
1434 ret = tstream_bsd_existing_socket(dcesrv_conn,
1435 socket_get_fd(srv_conn->socket),
1436 &dcesrv_conn->stream);
1437 if (ret == -1) {
1438 status = map_nt_error_from_unix(errno);
1439 DEBUG(0, ("dcesrv_sock_accept: "
1440 "failed to setup tstream: %s\n",
1441 nt_errstr(status)));
1442 stream_terminate_connection(srv_conn, nt_errstr(status));
1443 return;
1445 socket_set_flags(srv_conn->socket, SOCKET_FLAG_NOCLOSE);
1448 dcesrv_conn->local_address = srv_conn->local_address;
1449 dcesrv_conn->remote_address = srv_conn->remote_address;
1451 srv_conn->private_data = dcesrv_conn;
1453 irpc_add_name(srv_conn->msg_ctx, "rpc_server");
1455 subreq = dcerpc_read_ncacn_packet_send(dcesrv_conn,
1456 dcesrv_conn->event_ctx,
1457 dcesrv_conn->stream);
1458 if (!subreq) {
1459 status = NT_STATUS_NO_MEMORY;
1460 DEBUG(0,("dcesrv_sock_accept: dcerpc_read_fragment_buffer_send(%s)\n",
1461 nt_errstr(status)));
1462 stream_terminate_connection(srv_conn, nt_errstr(status));
1463 return;
1465 tevent_req_set_callback(subreq, dcesrv_read_fragment_done, dcesrv_conn);
1467 return;
1470 static void dcesrv_read_fragment_done(struct tevent_req *subreq)
1472 struct dcesrv_connection *dce_conn = tevent_req_callback_data(subreq,
1473 struct dcesrv_connection);
1474 struct ncacn_packet *pkt;
1475 DATA_BLOB buffer;
1476 NTSTATUS status;
1478 status = dcerpc_read_ncacn_packet_recv(subreq, dce_conn,
1479 &pkt, &buffer);
1480 TALLOC_FREE(subreq);
1481 if (!NT_STATUS_IS_OK(status)) {
1482 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1483 return;
1486 status = dcesrv_process_ncacn_packet(dce_conn, pkt, buffer);
1487 if (!NT_STATUS_IS_OK(status)) {
1488 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1489 return;
1492 subreq = dcerpc_read_ncacn_packet_send(dce_conn,
1493 dce_conn->event_ctx,
1494 dce_conn->stream);
1495 if (!subreq) {
1496 status = NT_STATUS_NO_MEMORY;
1497 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1498 return;
1500 tevent_req_set_callback(subreq, dcesrv_read_fragment_done, dce_conn);
1503 static void dcesrv_sock_recv(struct stream_connection *conn, uint16_t flags)
1505 struct dcesrv_connection *dce_conn = talloc_get_type(conn->private_data,
1506 struct dcesrv_connection);
1507 dcesrv_terminate_connection(dce_conn, "dcesrv_sock_recv triggered");
1510 static void dcesrv_sock_send(struct stream_connection *conn, uint16_t flags)
1512 struct dcesrv_connection *dce_conn = talloc_get_type(conn->private_data,
1513 struct dcesrv_connection);
1514 dcesrv_terminate_connection(dce_conn, "dcesrv_sock_send triggered");
1518 static const struct stream_server_ops dcesrv_stream_ops = {
1519 .name = "rpc",
1520 .accept_connection = dcesrv_sock_accept,
1521 .recv_handler = dcesrv_sock_recv,
1522 .send_handler = dcesrv_sock_send,
1525 static NTSTATUS dcesrv_add_ep_unix(struct dcesrv_context *dce_ctx,
1526 struct loadparm_context *lp_ctx,
1527 struct dcesrv_endpoint *e,
1528 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1530 struct dcesrv_socket_context *dcesrv_sock;
1531 uint16_t port = 1;
1532 NTSTATUS status;
1534 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1535 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1537 /* remember the endpoint of this socket */
1538 dcesrv_sock->endpoint = e;
1539 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1541 status = stream_setup_socket(dcesrv_sock, event_ctx, lp_ctx,
1542 model_ops, &dcesrv_stream_ops,
1543 "unix", e->ep_description->endpoint, &port,
1544 lpcfg_socket_options(lp_ctx),
1545 dcesrv_sock);
1546 if (!NT_STATUS_IS_OK(status)) {
1547 DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n",
1548 e->ep_description->endpoint, nt_errstr(status)));
1551 return status;
1554 static NTSTATUS dcesrv_add_ep_ncalrpc(struct dcesrv_context *dce_ctx,
1555 struct loadparm_context *lp_ctx,
1556 struct dcesrv_endpoint *e,
1557 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1559 struct dcesrv_socket_context *dcesrv_sock;
1560 uint16_t port = 1;
1561 char *full_path;
1562 NTSTATUS status;
1564 if (!e->ep_description->endpoint) {
1565 /* No identifier specified: use DEFAULT.
1566 * DO NOT hardcode this value anywhere else. Rather, specify
1567 * no endpoint and let the epmapper worry about it. */
1568 e->ep_description->endpoint = talloc_strdup(dce_ctx, "DEFAULT");
1571 full_path = talloc_asprintf(dce_ctx, "%s/%s", lpcfg_ncalrpc_dir(lp_ctx),
1572 e->ep_description->endpoint);
1574 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1575 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1577 /* remember the endpoint of this socket */
1578 dcesrv_sock->endpoint = e;
1579 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1581 status = stream_setup_socket(dcesrv_sock, event_ctx, lp_ctx,
1582 model_ops, &dcesrv_stream_ops,
1583 "unix", full_path, &port,
1584 lpcfg_socket_options(lp_ctx),
1585 dcesrv_sock);
1586 if (!NT_STATUS_IS_OK(status)) {
1587 DEBUG(0,("service_setup_stream_socket(identifier=%s,path=%s) failed - %s\n",
1588 e->ep_description->endpoint, full_path, nt_errstr(status)));
1590 return status;
1593 static NTSTATUS dcesrv_add_ep_np(struct dcesrv_context *dce_ctx,
1594 struct loadparm_context *lp_ctx,
1595 struct dcesrv_endpoint *e,
1596 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1598 struct dcesrv_socket_context *dcesrv_sock;
1599 NTSTATUS status;
1601 if (e->ep_description->endpoint == NULL) {
1602 DEBUG(0, ("Endpoint mandatory for named pipes\n"));
1603 return NT_STATUS_INVALID_PARAMETER;
1606 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1607 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1609 /* remember the endpoint of this socket */
1610 dcesrv_sock->endpoint = e;
1611 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1613 status = tstream_setup_named_pipe(dce_ctx, event_ctx, lp_ctx,
1614 model_ops, &dcesrv_stream_ops,
1615 e->ep_description->endpoint,
1616 dcesrv_sock);
1617 if (!NT_STATUS_IS_OK(status)) {
1618 DEBUG(0,("stream_setup_named_pipe(pipe=%s) failed - %s\n",
1619 e->ep_description->endpoint, nt_errstr(status)));
1620 return status;
1623 return NT_STATUS_OK;
1627 add a socket address to the list of events, one event per dcerpc endpoint
1629 static NTSTATUS add_socket_rpc_tcp_iface(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e,
1630 struct tevent_context *event_ctx, const struct model_ops *model_ops,
1631 const char *address)
1633 struct dcesrv_socket_context *dcesrv_sock;
1634 uint16_t port = 0;
1635 NTSTATUS status;
1637 if (e->ep_description->endpoint) {
1638 port = atoi(e->ep_description->endpoint);
1641 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1642 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1644 /* remember the endpoint of this socket */
1645 dcesrv_sock->endpoint = e;
1646 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1648 status = stream_setup_socket(dcesrv_sock, event_ctx, dce_ctx->lp_ctx,
1649 model_ops, &dcesrv_stream_ops,
1650 "ipv4", address, &port,
1651 lpcfg_socket_options(dce_ctx->lp_ctx),
1652 dcesrv_sock);
1653 if (!NT_STATUS_IS_OK(status)) {
1654 DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) failed - %s\n",
1655 address, port, nt_errstr(status)));
1658 if (e->ep_description->endpoint == NULL) {
1659 e->ep_description->endpoint = talloc_asprintf(dce_ctx, "%d", port);
1662 return status;
1665 #include "lib/socket/netif.h" /* Included here to work around the fact that socket_wrapper redefines bind() */
1667 static NTSTATUS dcesrv_add_ep_tcp(struct dcesrv_context *dce_ctx,
1668 struct loadparm_context *lp_ctx,
1669 struct dcesrv_endpoint *e,
1670 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1672 NTSTATUS status;
1674 /* Add TCP/IP sockets */
1675 if (lpcfg_interfaces(lp_ctx) && lpcfg_bind_interfaces_only(lp_ctx)) {
1676 int num_interfaces;
1677 int i;
1678 struct interface *ifaces;
1680 load_interfaces(dce_ctx, lpcfg_interfaces(lp_ctx), &ifaces);
1682 num_interfaces = iface_count(ifaces);
1683 for(i = 0; i < num_interfaces; i++) {
1684 const char *address = iface_n_ip(ifaces, i);
1685 status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, address);
1686 NT_STATUS_NOT_OK_RETURN(status);
1688 } else {
1689 status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops,
1690 lpcfg_socket_address(lp_ctx));
1691 NT_STATUS_NOT_OK_RETURN(status);
1694 return NT_STATUS_OK;
1697 NTSTATUS dcesrv_add_ep(struct dcesrv_context *dce_ctx,
1698 struct loadparm_context *lp_ctx,
1699 struct dcesrv_endpoint *e,
1700 struct tevent_context *event_ctx,
1701 const struct model_ops *model_ops)
1703 switch (e->ep_description->transport) {
1704 case NCACN_UNIX_STREAM:
1705 return dcesrv_add_ep_unix(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1707 case NCALRPC:
1708 return dcesrv_add_ep_ncalrpc(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1710 case NCACN_IP_TCP:
1711 return dcesrv_add_ep_tcp(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1713 case NCACN_NP:
1714 return dcesrv_add_ep_np(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1716 default:
1717 return NT_STATUS_NOT_SUPPORTED;