vfs: add snapshot create/delete hooks
[Samba.git] / source4 / rpc_server / dcerpc_server.c
bloba8785b02e1346f6292976dc56a2116b42e09f67e
1 /*
2 Unix SMB/CIFS implementation.
4 server side dcerpc core code
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) Stefan (metze) Metzmacher 2004-2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "auth/auth.h"
25 #include "auth/gensec/gensec.h"
26 #include "../lib/util/dlinklist.h"
27 #include "rpc_server/dcerpc_server.h"
28 #include "rpc_server/dcerpc_server_proto.h"
29 #include "rpc_server/common/proto.h"
30 #include "librpc/rpc/dcerpc_proto.h"
31 #include "system/filesys.h"
32 #include "libcli/security/security.h"
33 #include "param/param.h"
34 #include "../lib/tsocket/tsocket.h"
35 #include "../libcli/named_pipe_auth/npa_tstream.h"
36 #include "smbd/service_stream.h"
37 #include "../lib/tsocket/tsocket.h"
38 #include "lib/socket/socket.h"
39 #include "smbd/process_model.h"
40 #include "lib/messaging/irpc.h"
41 #include "librpc/rpc/rpc_common.h"
42 #include "lib/util/samba_modules.h"
43 #include "librpc/gen_ndr/ndr_dcerpc.h"
45 /* this is only used when the client asks for an unknown interface */
46 #define DUMMY_ASSOC_GROUP 0x0FFFFFFF
48 extern const struct dcesrv_interface dcesrv_mgmt_interface;
52 find an association group given a assoc_group_id
54 static struct dcesrv_assoc_group *dcesrv_assoc_group_find(struct dcesrv_context *dce_ctx,
55 uint32_t id)
57 void *id_ptr;
59 id_ptr = idr_find(dce_ctx->assoc_groups_idr, id);
60 if (id_ptr == NULL) {
61 return NULL;
63 return talloc_get_type_abort(id_ptr, struct dcesrv_assoc_group);
67 take a reference to an existing association group
69 static struct dcesrv_assoc_group *dcesrv_assoc_group_reference(TALLOC_CTX *mem_ctx,
70 struct dcesrv_context *dce_ctx,
71 uint32_t id)
73 struct dcesrv_assoc_group *assoc_group;
75 assoc_group = dcesrv_assoc_group_find(dce_ctx, id);
76 if (assoc_group == NULL) {
77 DEBUG(0,(__location__ ": Failed to find assoc_group 0x%08x\n", id));
78 return NULL;
80 return talloc_reference(mem_ctx, assoc_group);
83 static int dcesrv_assoc_group_destructor(struct dcesrv_assoc_group *assoc_group)
85 int ret;
86 ret = idr_remove(assoc_group->dce_ctx->assoc_groups_idr, assoc_group->id);
87 if (ret != 0) {
88 DEBUG(0,(__location__ ": Failed to remove assoc_group 0x%08x\n",
89 assoc_group->id));
91 return 0;
95 allocate a new association group
97 static struct dcesrv_assoc_group *dcesrv_assoc_group_new(TALLOC_CTX *mem_ctx,
98 struct dcesrv_context *dce_ctx)
100 struct dcesrv_assoc_group *assoc_group;
101 int id;
103 assoc_group = talloc_zero(mem_ctx, struct dcesrv_assoc_group);
104 if (assoc_group == NULL) {
105 return NULL;
108 id = idr_get_new_random(dce_ctx->assoc_groups_idr, assoc_group, UINT16_MAX);
109 if (id == -1) {
110 talloc_free(assoc_group);
111 DEBUG(0,(__location__ ": Out of association groups!\n"));
112 return NULL;
115 assoc_group->id = id;
116 assoc_group->dce_ctx = dce_ctx;
118 talloc_set_destructor(assoc_group, dcesrv_assoc_group_destructor);
120 return assoc_group;
125 see if two endpoints match
127 static bool endpoints_match(const struct dcerpc_binding *ep1,
128 const struct dcerpc_binding *ep2)
130 enum dcerpc_transport_t t1;
131 enum dcerpc_transport_t t2;
132 const char *e1;
133 const char *e2;
135 t1 = dcerpc_binding_get_transport(ep1);
136 t2 = dcerpc_binding_get_transport(ep2);
138 e1 = dcerpc_binding_get_string_option(ep1, "endpoint");
139 e2 = dcerpc_binding_get_string_option(ep2, "endpoint");
141 if (t1 != t2) {
142 return false;
145 if (!e1 || !e2) {
146 return e1 == e2;
149 if (strcasecmp(e1, e2) != 0) {
150 return false;
153 return true;
157 find an endpoint in the dcesrv_context
159 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
160 const struct dcerpc_binding *ep_description)
162 struct dcesrv_endpoint *ep;
163 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
164 if (endpoints_match(ep->ep_description, ep_description)) {
165 return ep;
168 return NULL;
172 find a registered context_id from a bind or alter_context
174 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn,
175 uint32_t context_id)
177 struct dcesrv_connection_context *c;
178 for (c=conn->contexts;c;c=c->next) {
179 if (c->context_id == context_id) return c;
181 return NULL;
185 see if a uuid and if_version match to an interface
187 static bool interface_match(const struct dcesrv_interface *if1,
188 const struct dcesrv_interface *if2)
190 return (if1->syntax_id.if_version == if2->syntax_id.if_version &&
191 GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
195 find the interface operations on an endpoint
197 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
198 const struct dcesrv_interface *iface)
200 struct dcesrv_if_list *ifl;
201 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
202 if (interface_match(&(ifl->iface), iface)) {
203 return &(ifl->iface);
206 return NULL;
210 see if a uuid and if_version match to an interface
212 static bool interface_match_by_uuid(const struct dcesrv_interface *iface,
213 const struct GUID *uuid, uint32_t if_version)
215 return (iface->syntax_id.if_version == if_version &&
216 GUID_equal(&iface->syntax_id.uuid, uuid));
220 find the interface operations on an endpoint by uuid
222 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
223 const struct GUID *uuid, uint32_t if_version)
225 struct dcesrv_if_list *ifl;
226 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
227 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
228 return &(ifl->iface);
231 return NULL;
235 find the earlier parts of a fragmented call awaiting reassembily
237 static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
239 struct dcesrv_call_state *c;
240 for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
241 if (c->pkt.call_id == call_id) {
242 return c;
245 return NULL;
249 register an interface on an endpoint
251 _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
252 const char *ep_name,
253 const struct dcesrv_interface *iface,
254 const struct security_descriptor *sd)
256 struct dcesrv_endpoint *ep;
257 struct dcesrv_if_list *ifl;
258 struct dcerpc_binding *binding;
259 bool add_ep = false;
260 NTSTATUS status;
262 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
264 if (NT_STATUS_IS_ERR(status)) {
265 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
266 return status;
269 /* check if this endpoint exists
271 if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
272 ep = talloc(dce_ctx, struct dcesrv_endpoint);
273 if (!ep) {
274 return NT_STATUS_NO_MEMORY;
276 ZERO_STRUCTP(ep);
277 ep->ep_description = talloc_move(ep, &binding);
278 add_ep = true;
280 /* add mgmt interface */
281 ifl = talloc(ep, struct dcesrv_if_list);
282 if (!ifl) {
283 return NT_STATUS_NO_MEMORY;
286 memcpy(&(ifl->iface), &dcesrv_mgmt_interface,
287 sizeof(struct dcesrv_interface));
289 DLIST_ADD(ep->interface_list, ifl);
292 /* see if the interface is already registered on te endpoint */
293 if (find_interface(ep, iface)!=NULL) {
294 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
295 iface->name, ep_name));
296 return NT_STATUS_OBJECT_NAME_COLLISION;
299 /* talloc a new interface list element */
300 ifl = talloc(ep, struct dcesrv_if_list);
301 if (!ifl) {
302 return NT_STATUS_NO_MEMORY;
305 /* copy the given interface struct to the one on the endpoints interface list */
306 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
308 /* if we have a security descriptor given,
309 * we should see if we can set it up on the endpoint
311 if (sd != NULL) {
312 /* if there's currently no security descriptor given on the endpoint
313 * we try to set it
315 if (ep->sd == NULL) {
316 ep->sd = security_descriptor_copy(ep, sd);
319 /* if now there's no security descriptor given on the endpoint
320 * something goes wrong, either we failed to copy the security descriptor
321 * or there was already one on the endpoint
323 if (ep->sd != NULL) {
324 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
325 " on endpoint '%s'\n",
326 iface->name, ep_name));
327 if (add_ep) free(ep);
328 free(ifl);
329 return NT_STATUS_OBJECT_NAME_COLLISION;
333 /* finally add the interface on the endpoint */
334 DLIST_ADD(ep->interface_list, ifl);
336 /* if it's a new endpoint add it to the dcesrv_context */
337 if (add_ep) {
338 DLIST_ADD(dce_ctx->endpoint_list, ep);
341 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
342 iface->name, ep_name));
344 return NT_STATUS_OK;
347 NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
348 DATA_BLOB *session_key)
350 if (p->auth_state.session_info->session_key.length) {
351 *session_key = p->auth_state.session_info->session_key;
352 return NT_STATUS_OK;
354 return NT_STATUS_NO_USER_SESSION_KEY;
358 fetch the user session key - may be default (above) or the SMB session key
360 The key is always truncated to 16 bytes
362 _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
363 DATA_BLOB *session_key)
365 NTSTATUS status = p->auth_state.session_key(p, session_key);
366 if (!NT_STATUS_IS_OK(status)) {
367 return status;
370 session_key->length = MIN(session_key->length, 16);
372 return NT_STATUS_OK;
376 connect to a dcerpc endpoint
378 _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
379 TALLOC_CTX *mem_ctx,
380 const struct dcesrv_endpoint *ep,
381 struct auth_session_info *session_info,
382 struct tevent_context *event_ctx,
383 struct imessaging_context *msg_ctx,
384 struct server_id server_id,
385 uint32_t state_flags,
386 struct dcesrv_connection **_p)
388 struct dcesrv_connection *p;
390 if (!session_info) {
391 return NT_STATUS_ACCESS_DENIED;
394 p = talloc_zero(mem_ctx, struct dcesrv_connection);
395 NT_STATUS_HAVE_NO_MEMORY(p);
397 if (!talloc_reference(p, session_info)) {
398 talloc_free(p);
399 return NT_STATUS_NO_MEMORY;
402 p->dce_ctx = dce_ctx;
403 p->endpoint = ep;
404 p->packet_log_dir = lpcfg_lock_directory(dce_ctx->lp_ctx);
405 p->auth_state.session_info = session_info;
406 p->auth_state.session_key = dcesrv_generic_session_key;
407 p->event_ctx = event_ctx;
408 p->msg_ctx = msg_ctx;
409 p->server_id = server_id;
410 p->state_flags = state_flags;
412 *_p = p;
413 return NT_STATUS_OK;
417 move a call from an existing linked list to the specified list. This
418 prevents bugs where we forget to remove the call from a previous
419 list when moving it.
421 static void dcesrv_call_set_list(struct dcesrv_call_state *call,
422 enum dcesrv_call_list list)
424 switch (call->list) {
425 case DCESRV_LIST_NONE:
426 break;
427 case DCESRV_LIST_CALL_LIST:
428 DLIST_REMOVE(call->conn->call_list, call);
429 break;
430 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
431 DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
432 break;
433 case DCESRV_LIST_PENDING_CALL_LIST:
434 DLIST_REMOVE(call->conn->pending_call_list, call);
435 break;
437 call->list = list;
438 switch (list) {
439 case DCESRV_LIST_NONE:
440 break;
441 case DCESRV_LIST_CALL_LIST:
442 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
443 break;
444 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
445 DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
446 break;
447 case DCESRV_LIST_PENDING_CALL_LIST:
448 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
449 break;
455 return a dcerpc bind_nak
457 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
459 struct ncacn_packet pkt;
460 struct dcerpc_bind_nak_version version;
461 struct data_blob_list_item *rep;
462 NTSTATUS status;
464 /* setup a bind_nak */
465 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
466 pkt.auth_length = 0;
467 pkt.call_id = call->pkt.call_id;
468 pkt.ptype = DCERPC_PKT_BIND_NAK;
469 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
470 pkt.u.bind_nak.reject_reason = reason;
471 version.rpc_vers = 5;
472 version.rpc_vers_minor = 0;
473 pkt.u.bind_nak.num_versions = 1;
474 pkt.u.bind_nak.versions = &version;
475 pkt.u.bind_nak._pad = data_blob_null;
477 rep = talloc(call, struct data_blob_list_item);
478 if (!rep) {
479 return NT_STATUS_NO_MEMORY;
482 status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
483 if (!NT_STATUS_IS_OK(status)) {
484 return status;
487 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
489 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
490 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
492 if (call->conn->call_list && call->conn->call_list->replies) {
493 if (call->conn->transport.report_output_data) {
494 call->conn->transport.report_output_data(call->conn);
498 return NT_STATUS_OK;
501 static int dcesrv_connection_context_destructor(struct dcesrv_connection_context *c)
503 DLIST_REMOVE(c->conn->contexts, c);
505 if (c->iface && c->iface->unbind) {
506 c->iface->unbind(c, c->iface);
509 return 0;
513 handle a bind request
515 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
517 uint32_t if_version, transfer_syntax_version;
518 struct GUID uuid, *transfer_syntax_uuid;
519 struct ncacn_packet pkt;
520 struct data_blob_list_item *rep;
521 NTSTATUS status;
522 uint32_t result=0, reason=0;
523 uint32_t context_id;
524 const struct dcesrv_interface *iface;
525 uint32_t extra_flags = 0;
528 if provided, check the assoc_group is valid
530 if (call->pkt.u.bind.assoc_group_id != 0 &&
531 lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
532 dcesrv_assoc_group_find(call->conn->dce_ctx, call->pkt.u.bind.assoc_group_id) == NULL) {
533 return dcesrv_bind_nak(call, 0);
536 if (call->pkt.u.bind.num_contexts < 1 ||
537 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
538 return dcesrv_bind_nak(call, 0);
541 context_id = call->pkt.u.bind.ctx_list[0].context_id;
543 /* you can't bind twice on one context */
544 if (dcesrv_find_context(call->conn, context_id) != NULL) {
545 return dcesrv_bind_nak(call, 0);
548 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
549 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
551 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
552 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
553 if (!GUID_equal(&ndr_transfer_syntax_ndr.uuid, transfer_syntax_uuid) != 0 ||
554 ndr_transfer_syntax_ndr.if_version != transfer_syntax_version) {
555 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
556 /* we only do NDR encoded dcerpc */
557 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
558 talloc_free(uuid_str);
559 return dcesrv_bind_nak(call, 0);
562 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
563 if (iface == NULL) {
564 char *uuid_str = GUID_string(call, &uuid);
565 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
566 talloc_free(uuid_str);
568 /* we don't know about that interface */
569 result = DCERPC_BIND_PROVIDER_REJECT;
570 reason = DCERPC_BIND_REASON_ASYNTAX;
573 if (iface) {
574 /* add this context to the list of available context_ids */
575 struct dcesrv_connection_context *context = talloc(call->conn,
576 struct dcesrv_connection_context);
577 if (context == NULL) {
578 return dcesrv_bind_nak(call, 0);
580 context->conn = call->conn;
581 context->iface = iface;
582 context->context_id = context_id;
583 if (call->pkt.u.bind.assoc_group_id != 0) {
584 context->assoc_group = dcesrv_assoc_group_reference(context,
585 call->conn->dce_ctx,
586 call->pkt.u.bind.assoc_group_id);
587 } else {
588 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
590 if (context->assoc_group == NULL) {
591 talloc_free(context);
592 return dcesrv_bind_nak(call, 0);
594 context->private_data = NULL;
595 DLIST_ADD(call->conn->contexts, context);
596 call->context = context;
597 talloc_set_destructor(context, dcesrv_connection_context_destructor);
599 status = iface->bind(call, iface, if_version);
600 if (!NT_STATUS_IS_OK(status)) {
601 char *uuid_str = GUID_string(call, &uuid);
602 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
603 uuid_str, if_version, nt_errstr(status)));
604 talloc_free(uuid_str);
605 /* we don't want to trigger the iface->unbind() hook */
606 context->iface = NULL;
607 talloc_free(call->context);
608 call->context = NULL;
609 return dcesrv_bind_nak(call, 0);
613 if (call->conn->cli_max_recv_frag == 0) {
614 call->conn->cli_max_recv_frag = MIN(0x2000, call->pkt.u.bind.max_recv_frag);
617 if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_CONC_MPX) &&
618 (call->state_flags & DCESRV_CALL_STATE_FLAG_MULTIPLEXED)) {
619 call->context->conn->state_flags |= DCESRV_CALL_STATE_FLAG_MULTIPLEXED;
620 extra_flags |= DCERPC_PFC_FLAG_CONC_MPX;
623 /* handle any authentication that is being requested */
624 if (!dcesrv_auth_bind(call)) {
625 talloc_free(call->context);
626 call->context = NULL;
627 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
630 /* setup a bind_ack */
631 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
632 pkt.auth_length = 0;
633 pkt.call_id = call->pkt.call_id;
634 pkt.ptype = DCERPC_PKT_BIND_ACK;
635 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
636 pkt.u.bind_ack.max_xmit_frag = call->conn->cli_max_recv_frag;
637 pkt.u.bind_ack.max_recv_frag = 0x2000;
640 make it possible for iface->bind() to specify the assoc_group_id
641 This helps the openchange mapiproxy plugin to work correctly.
643 metze
645 if (call->context) {
646 pkt.u.bind_ack.assoc_group_id = call->context->assoc_group->id;
647 } else {
648 pkt.u.bind_ack.assoc_group_id = DUMMY_ASSOC_GROUP;
651 if (iface) {
652 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
653 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
654 } else {
655 pkt.u.bind_ack.secondary_address = "";
657 pkt.u.bind_ack.num_results = 1;
658 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
659 if (!pkt.u.bind_ack.ctx_list) {
660 talloc_free(call->context);
661 call->context = NULL;
662 return NT_STATUS_NO_MEMORY;
664 pkt.u.bind_ack.ctx_list[0].result = result;
665 pkt.u.bind_ack.ctx_list[0].reason.value = reason;
666 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax_ndr;
667 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
669 status = dcesrv_auth_bind_ack(call, &pkt);
670 if (!NT_STATUS_IS_OK(status)) {
671 talloc_free(call->context);
672 call->context = NULL;
673 return dcesrv_bind_nak(call, 0);
676 rep = talloc(call, struct data_blob_list_item);
677 if (!rep) {
678 talloc_free(call->context);
679 call->context = NULL;
680 return NT_STATUS_NO_MEMORY;
683 status = ncacn_push_auth(&rep->blob, call, &pkt,
684 call->conn->auth_state.auth_info);
685 if (!NT_STATUS_IS_OK(status)) {
686 talloc_free(call->context);
687 call->context = NULL;
688 return status;
691 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
693 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
694 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
696 if (call->conn->call_list && call->conn->call_list->replies) {
697 if (call->conn->transport.report_output_data) {
698 call->conn->transport.report_output_data(call->conn);
702 return NT_STATUS_OK;
707 handle a auth3 request
709 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
711 /* handle the auth3 in the auth code */
712 if (!dcesrv_auth_auth3(call)) {
713 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
716 talloc_free(call);
718 /* we don't send a reply to a auth3 request, except by a
719 fault */
720 return NT_STATUS_OK;
725 handle a bind request
727 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
729 uint32_t if_version, transfer_syntax_version;
730 struct dcesrv_connection_context *context;
731 const struct dcesrv_interface *iface;
732 struct GUID uuid, *transfer_syntax_uuid;
733 NTSTATUS status;
735 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
736 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
738 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
739 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
740 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax_ndr.uuid) ||
741 ndr_transfer_syntax_ndr.if_version != transfer_syntax_version) {
742 /* we only do NDR encoded dcerpc */
743 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
746 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
747 if (iface == NULL) {
748 char *uuid_str = GUID_string(call, &uuid);
749 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
750 talloc_free(uuid_str);
751 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
754 /* add this context to the list of available context_ids */
755 context = talloc(call->conn, struct dcesrv_connection_context);
756 if (context == NULL) {
757 return NT_STATUS_NO_MEMORY;
759 context->conn = call->conn;
760 context->iface = iface;
761 context->context_id = context_id;
762 if (call->pkt.u.alter.assoc_group_id != 0) {
763 context->assoc_group = dcesrv_assoc_group_reference(context,
764 call->conn->dce_ctx,
765 call->pkt.u.alter.assoc_group_id);
766 } else {
767 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
769 if (context->assoc_group == NULL) {
770 talloc_free(context);
771 call->context = NULL;
772 return NT_STATUS_NO_MEMORY;
774 context->private_data = NULL;
775 DLIST_ADD(call->conn->contexts, context);
776 call->context = context;
777 talloc_set_destructor(context, dcesrv_connection_context_destructor);
779 status = iface->bind(call, iface, if_version);
780 if (!NT_STATUS_IS_OK(status)) {
781 /* we don't want to trigger the iface->unbind() hook */
782 context->iface = NULL;
783 talloc_free(context);
784 call->context = NULL;
785 return status;
788 return NT_STATUS_OK;
793 handle a alter context request
795 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
797 struct ncacn_packet pkt;
798 struct data_blob_list_item *rep;
799 NTSTATUS status;
800 uint32_t result=0, reason=0;
801 uint32_t context_id;
802 uint32_t extra_flags = 0;
804 /* handle any authentication that is being requested */
805 if (!dcesrv_auth_alter(call)) {
806 /* TODO: work out the right reject code */
807 result = DCERPC_BIND_PROVIDER_REJECT;
808 reason = DCERPC_BIND_REASON_ASYNTAX;
811 context_id = call->pkt.u.alter.ctx_list[0].context_id;
813 /* see if they are asking for a new interface */
814 if (result == 0) {
815 call->context = dcesrv_find_context(call->conn, context_id);
816 if (!call->context) {
817 status = dcesrv_alter_new_context(call, context_id);
818 if (!NT_STATUS_IS_OK(status)) {
819 result = DCERPC_BIND_PROVIDER_REJECT;
820 reason = DCERPC_BIND_REASON_ASYNTAX;
825 if (result == 0 &&
826 call->pkt.u.alter.assoc_group_id != 0 &&
827 lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
828 call->pkt.u.alter.assoc_group_id != call->context->assoc_group->id) {
829 DEBUG(0,(__location__ ": Failed attempt to use new assoc_group in alter context (0x%08x 0x%08x)\n",
830 call->context->assoc_group->id, call->pkt.u.alter.assoc_group_id));
831 /* TODO: can they ask for a new association group? */
832 result = DCERPC_BIND_PROVIDER_REJECT;
833 reason = DCERPC_BIND_REASON_ASYNTAX;
836 if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
837 if (call->context->conn->state_flags & DCESRV_CALL_STATE_FLAG_MULTIPLEXED) {
838 extra_flags |= DCERPC_PFC_FLAG_CONC_MPX;
842 /* setup a alter_resp */
843 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
844 pkt.auth_length = 0;
845 pkt.call_id = call->pkt.call_id;
846 pkt.ptype = DCERPC_PKT_ALTER_RESP;
847 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
848 pkt.u.alter_resp.max_xmit_frag = 0x2000;
849 pkt.u.alter_resp.max_recv_frag = 0x2000;
850 if (result == 0) {
851 pkt.u.alter_resp.assoc_group_id = call->context->assoc_group->id;
852 } else {
853 pkt.u.alter_resp.assoc_group_id = 0;
855 pkt.u.alter_resp.num_results = 1;
856 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
857 if (!pkt.u.alter_resp.ctx_list) {
858 return NT_STATUS_NO_MEMORY;
860 pkt.u.alter_resp.ctx_list[0].result = result;
861 pkt.u.alter_resp.ctx_list[0].reason.value = reason;
862 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax_ndr;
863 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
864 pkt.u.alter_resp.secondary_address = "";
866 status = dcesrv_auth_alter_ack(call, &pkt);
867 if (!NT_STATUS_IS_OK(status)) {
868 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
869 || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
870 || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
871 || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
872 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
874 return dcesrv_fault(call, 0);
877 rep = talloc(call, struct data_blob_list_item);
878 if (!rep) {
879 return NT_STATUS_NO_MEMORY;
882 status = ncacn_push_auth(&rep->blob, call, &pkt, call->conn->auth_state.auth_info);
883 if (!NT_STATUS_IS_OK(status)) {
884 return status;
887 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
889 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
890 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
892 if (call->conn->call_list && call->conn->call_list->replies) {
893 if (call->conn->transport.report_output_data) {
894 call->conn->transport.report_output_data(call->conn);
898 return NT_STATUS_OK;
902 possibly save the call for inspection with ndrdump
904 static void dcesrv_save_call(struct dcesrv_call_state *call, const char *why)
906 #ifdef DEVELOPER
907 char *fname;
908 const char *dump_dir;
909 dump_dir = lpcfg_parm_string(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv", "stubs directory");
910 if (!dump_dir) {
911 return;
913 fname = talloc_asprintf(call, "%s/RPC-%s-%u-%s.dat",
914 dump_dir,
915 call->context->iface->name,
916 call->pkt.u.request.opnum,
917 why);
918 if (file_save(fname, call->pkt.u.request.stub_and_verifier.data, call->pkt.u.request.stub_and_verifier.length)) {
919 DEBUG(0,("RPC SAVED %s\n", fname));
921 talloc_free(fname);
922 #endif
925 static NTSTATUS dcesrv_check_verification_trailer(struct dcesrv_call_state *call)
927 TALLOC_CTX *frame = talloc_stackframe();
928 const uint32_t bitmask1 = call->conn->auth_state.client_hdr_signing ?
929 DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING : 0;
930 const struct dcerpc_sec_vt_pcontext pcontext = {
931 .abstract_syntax = call->context->iface->syntax_id,
932 .transfer_syntax = ndr_transfer_syntax_ndr,
934 const struct dcerpc_sec_vt_header2 header2 =
935 dcerpc_sec_vt_header2_from_ncacn_packet(&call->pkt);
936 enum ndr_err_code ndr_err;
937 struct dcerpc_sec_verification_trailer *vt = NULL;
938 NTSTATUS status = NT_STATUS_OK;
939 bool ok;
941 SMB_ASSERT(call->pkt.ptype == DCERPC_PKT_REQUEST);
943 ndr_err = ndr_pop_dcerpc_sec_verification_trailer(call->ndr_pull,
944 frame, &vt);
945 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
946 status = ndr_map_error2ntstatus(ndr_err);
947 goto done;
950 ok = dcerpc_sec_verification_trailer_check(vt, &bitmask1,
951 &pcontext, &header2);
952 if (!ok) {
953 status = NT_STATUS_ACCESS_DENIED;
954 goto done;
956 done:
957 TALLOC_FREE(frame);
958 return status;
962 handle a dcerpc request packet
964 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
966 struct ndr_pull *pull;
967 NTSTATUS status;
968 struct dcesrv_connection_context *context;
970 /* if authenticated, and the mech we use can't do async replies, don't use them... */
971 if (call->conn->auth_state.gensec_security &&
972 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
973 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
976 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
977 if (context == NULL) {
978 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
981 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
982 NT_STATUS_HAVE_NO_MEMORY(pull);
984 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
986 call->context = context;
987 call->ndr_pull = pull;
989 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
990 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
993 status = dcesrv_check_verification_trailer(call);
994 if (!NT_STATUS_IS_OK(status)) {
995 uint32_t faultcode = DCERPC_FAULT_OTHER;
996 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
997 faultcode = DCERPC_FAULT_ACCESS_DENIED;
999 DEBUG(10, ("dcesrv_check_verification_trailer failed: %s\n",
1000 nt_errstr(status)));
1001 return dcesrv_fault(call, faultcode);
1004 /* unravel the NDR for the packet */
1005 status = context->iface->ndr_pull(call, call, pull, &call->r);
1006 if (!NT_STATUS_IS_OK(status)) {
1007 if (call->fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
1008 /* we got an unknown call */
1009 DEBUG(3,(__location__ ": Unknown RPC call %u on %s\n",
1010 call->pkt.u.request.opnum, context->iface->name));
1011 dcesrv_save_call(call, "unknown");
1012 } else {
1013 dcesrv_save_call(call, "pullfail");
1015 return dcesrv_fault(call, call->fault_code);
1018 if (pull->offset != pull->data_size) {
1019 dcesrv_save_call(call, "extrabytes");
1020 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
1021 pull->data_size - pull->offset));
1024 /* call the dispatch function */
1025 status = context->iface->dispatch(call, call, call->r);
1026 if (!NT_STATUS_IS_OK(status)) {
1027 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
1028 context->iface->name,
1029 call->pkt.u.request.opnum,
1030 dcerpc_errstr(pull, call->fault_code)));
1031 return dcesrv_fault(call, call->fault_code);
1034 /* add the call to the pending list */
1035 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
1037 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
1038 return NT_STATUS_OK;
1041 return dcesrv_reply(call);
1046 remove the call from the right list when freed
1048 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1050 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1051 return 0;
1054 _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_local_address(struct dcesrv_connection *conn)
1056 return conn->local_address;
1059 _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_remote_address(struct dcesrv_connection *conn)
1061 return conn->remote_address;
1065 process some input to a dcerpc endpoint server.
1067 NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
1068 struct ncacn_packet *pkt,
1069 DATA_BLOB blob)
1071 NTSTATUS status;
1072 struct dcesrv_call_state *call;
1074 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1075 if (!call) {
1076 data_blob_free(&blob);
1077 talloc_free(pkt);
1078 return NT_STATUS_NO_MEMORY;
1080 call->conn = dce_conn;
1081 call->event_ctx = dce_conn->event_ctx;
1082 call->msg_ctx = dce_conn->msg_ctx;
1083 call->state_flags = call->conn->state_flags;
1084 call->time = timeval_current();
1085 call->list = DCESRV_LIST_NONE;
1087 talloc_steal(call, pkt);
1088 talloc_steal(call, blob.data);
1089 call->pkt = *pkt;
1091 talloc_set_destructor(call, dcesrv_call_dequeue);
1093 /* we have to check the signing here, before combining the
1094 pdus */
1095 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1096 !dcesrv_auth_request(call, &blob)) {
1097 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1100 /* see if this is a continued packet */
1101 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1102 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1103 struct dcesrv_call_state *call2 = call;
1104 uint32_t alloc_size;
1106 /* we only allow fragmented requests, no other packet types */
1107 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1108 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1111 /* this is a continuation of an existing call - find the call
1112 then tack it on the end */
1113 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1114 if (!call) {
1115 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1118 if (call->pkt.ptype != call2->pkt.ptype) {
1119 /* trying to play silly buggers are we? */
1120 return dcesrv_fault(call2, DCERPC_NCA_S_PROTO_ERROR);
1122 if (memcmp(call->pkt.drep, call2->pkt.drep, sizeof(pkt->drep)) != 0) {
1123 return dcesrv_fault(call2, DCERPC_NCA_S_PROTO_ERROR);
1125 if (call->pkt.call_id != call2->pkt.call_id) {
1126 return dcesrv_fault(call2, DCERPC_NCA_S_PROTO_ERROR);
1128 if (call->pkt.u.request.context_id != call2->pkt.u.request.context_id) {
1129 return dcesrv_fault(call2, DCERPC_NCA_S_PROTO_ERROR);
1131 if (call->pkt.u.request.opnum != call2->pkt.u.request.opnum) {
1132 return dcesrv_fault(call2, DCERPC_NCA_S_PROTO_ERROR);
1135 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1136 call2->pkt.u.request.stub_and_verifier.length;
1137 if (call->pkt.u.request.alloc_hint > alloc_size) {
1138 alloc_size = call->pkt.u.request.alloc_hint;
1141 call->pkt.u.request.stub_and_verifier.data =
1142 talloc_realloc(call,
1143 call->pkt.u.request.stub_and_verifier.data,
1144 uint8_t, alloc_size);
1145 if (!call->pkt.u.request.stub_and_verifier.data) {
1146 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1148 memcpy(call->pkt.u.request.stub_and_verifier.data +
1149 call->pkt.u.request.stub_and_verifier.length,
1150 call2->pkt.u.request.stub_and_verifier.data,
1151 call2->pkt.u.request.stub_and_verifier.length);
1152 call->pkt.u.request.stub_and_verifier.length +=
1153 call2->pkt.u.request.stub_and_verifier.length;
1155 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1157 talloc_free(call2);
1160 /* this may not be the last pdu in the chain - if its isn't then
1161 just put it on the incoming_fragmented_call_list and wait for the rest */
1162 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1163 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1164 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1165 return NT_STATUS_OK;
1168 /* This removes any fragments we may have had stashed away */
1169 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1171 switch (call->pkt.ptype) {
1172 case DCERPC_PKT_BIND:
1173 status = dcesrv_bind(call);
1174 break;
1175 case DCERPC_PKT_AUTH3:
1176 status = dcesrv_auth3(call);
1177 break;
1178 case DCERPC_PKT_ALTER:
1179 status = dcesrv_alter(call);
1180 break;
1181 case DCERPC_PKT_REQUEST:
1182 status = dcesrv_request(call);
1183 break;
1184 default:
1185 status = NT_STATUS_INVALID_PARAMETER;
1186 break;
1189 /* if we are going to be sending a reply then add
1190 it to the list of pending calls. We add it to the end to keep the call
1191 list in the order we will answer */
1192 if (!NT_STATUS_IS_OK(status)) {
1193 talloc_free(call);
1196 return status;
1199 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1200 struct loadparm_context *lp_ctx,
1201 const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1203 NTSTATUS status;
1204 struct dcesrv_context *dce_ctx;
1205 int i;
1207 if (!endpoint_servers) {
1208 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1209 return NT_STATUS_INTERNAL_ERROR;
1212 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1213 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1214 dce_ctx->initial_euid = geteuid();
1215 dce_ctx->endpoint_list = NULL;
1216 dce_ctx->lp_ctx = lp_ctx;
1217 dce_ctx->assoc_groups_idr = idr_init(dce_ctx);
1218 NT_STATUS_HAVE_NO_MEMORY(dce_ctx->assoc_groups_idr);
1219 dce_ctx->broken_connections = NULL;
1221 for (i=0;endpoint_servers[i];i++) {
1222 const struct dcesrv_endpoint_server *ep_server;
1224 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1225 if (!ep_server) {
1226 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1227 return NT_STATUS_INTERNAL_ERROR;
1230 status = ep_server->init_server(dce_ctx, ep_server);
1231 if (!NT_STATUS_IS_OK(status)) {
1232 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1233 nt_errstr(status)));
1234 return status;
1238 *_dce_ctx = dce_ctx;
1239 return NT_STATUS_OK;
1242 /* the list of currently registered DCERPC endpoint servers.
1244 static struct ep_server {
1245 struct dcesrv_endpoint_server *ep_server;
1246 } *ep_servers = NULL;
1247 static int num_ep_servers;
1250 register a DCERPC endpoint server.
1252 The 'name' can be later used by other backends to find the operations
1253 structure for this backend.
1255 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1257 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1259 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1261 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1262 /* its already registered! */
1263 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1264 ep_server->name));
1265 return NT_STATUS_OBJECT_NAME_COLLISION;
1268 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1269 if (!ep_servers) {
1270 smb_panic("out of memory in dcerpc_register");
1273 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1274 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1276 num_ep_servers++;
1278 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1279 ep_server->name));
1281 return NT_STATUS_OK;
1285 return the operations structure for a named backend of the specified type
1287 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1289 int i;
1291 for (i=0;i<num_ep_servers;i++) {
1292 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1293 return ep_servers[i].ep_server;
1297 return NULL;
1300 void dcerpc_server_init(struct loadparm_context *lp_ctx)
1302 static bool initialized;
1303 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
1304 STATIC_dcerpc_server_MODULES_PROTO;
1305 init_module_fn static_init[] = { STATIC_dcerpc_server_MODULES };
1306 init_module_fn *shared_init;
1308 if (initialized) {
1309 return;
1311 initialized = true;
1313 shared_init = load_samba_modules(NULL, "dcerpc_server");
1315 run_init_functions(static_init);
1316 run_init_functions(shared_init);
1318 talloc_free(shared_init);
1322 return the DCERPC module version, and the size of some critical types
1323 This can be used by endpoint server modules to either detect compilation errors, or provide
1324 multiple implementations for different smbd compilation options in one module
1326 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1328 static const struct dcesrv_critical_sizes critical_sizes = {
1329 DCERPC_MODULE_VERSION,
1330 sizeof(struct dcesrv_context),
1331 sizeof(struct dcesrv_endpoint),
1332 sizeof(struct dcesrv_endpoint_server),
1333 sizeof(struct dcesrv_interface),
1334 sizeof(struct dcesrv_if_list),
1335 sizeof(struct dcesrv_connection),
1336 sizeof(struct dcesrv_call_state),
1337 sizeof(struct dcesrv_auth),
1338 sizeof(struct dcesrv_handle)
1341 return &critical_sizes;
1344 static void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, const char *reason)
1346 struct dcesrv_context *dce_ctx = dce_conn->dce_ctx;
1347 struct stream_connection *srv_conn;
1348 srv_conn = talloc_get_type(dce_conn->transport.private_data,
1349 struct stream_connection);
1351 if (dce_conn->pending_call_list == NULL) {
1352 char *full_reason = talloc_asprintf(dce_conn, "dcesrv: %s", reason);
1354 DLIST_REMOVE(dce_ctx->broken_connections, dce_conn);
1355 stream_terminate_connection(srv_conn, full_reason ? full_reason : reason);
1356 return;
1359 if (dce_conn->terminate != NULL) {
1360 return;
1363 DEBUG(3,("dcesrv: terminating connection due to '%s' defered due to pending calls\n",
1364 reason));
1365 dce_conn->terminate = talloc_strdup(dce_conn, reason);
1366 if (dce_conn->terminate == NULL) {
1367 dce_conn->terminate = "dcesrv: defered terminating connection - no memory";
1369 DLIST_ADD_END(dce_ctx->broken_connections, dce_conn, NULL);
1372 static void dcesrv_cleanup_broken_connections(struct dcesrv_context *dce_ctx)
1374 struct dcesrv_connection *cur, *next;
1376 next = dce_ctx->broken_connections;
1377 while (next != NULL) {
1378 cur = next;
1379 next = cur->next;
1381 dcesrv_terminate_connection(cur, cur->terminate);
1385 /* We need this include to be able to compile on some plateforms
1386 * (ie. freebsd 7.2) as it seems that <sys/uio.h> is not included
1387 * correctly.
1388 * It has to be that deep because otherwise we have a conflict on
1389 * const struct dcesrv_interface declaration.
1390 * This is mostly due to socket_wrapper defining #define bind swrap_bind
1391 * which conflict with the bind used before.
1393 #include "system/network.h"
1395 struct dcesrv_sock_reply_state {
1396 struct dcesrv_connection *dce_conn;
1397 struct dcesrv_call_state *call;
1398 struct iovec iov;
1401 static void dcesrv_sock_reply_done(struct tevent_req *subreq);
1403 static void dcesrv_sock_report_output_data(struct dcesrv_connection *dce_conn)
1405 struct dcesrv_call_state *call;
1407 call = dce_conn->call_list;
1408 if (!call || !call->replies) {
1409 return;
1412 while (call->replies) {
1413 struct data_blob_list_item *rep = call->replies;
1414 struct dcesrv_sock_reply_state *substate;
1415 struct tevent_req *subreq;
1417 substate = talloc(call, struct dcesrv_sock_reply_state);
1418 if (!substate) {
1419 dcesrv_terminate_connection(dce_conn, "no memory");
1420 return;
1423 substate->dce_conn = dce_conn;
1424 substate->call = NULL;
1426 DLIST_REMOVE(call->replies, rep);
1428 if (call->replies == NULL) {
1429 substate->call = call;
1432 substate->iov.iov_base = (void *) rep->blob.data;
1433 substate->iov.iov_len = rep->blob.length;
1435 subreq = tstream_writev_queue_send(substate,
1436 dce_conn->event_ctx,
1437 dce_conn->stream,
1438 dce_conn->send_queue,
1439 &substate->iov, 1);
1440 if (!subreq) {
1441 dcesrv_terminate_connection(dce_conn, "no memory");
1442 return;
1444 tevent_req_set_callback(subreq, dcesrv_sock_reply_done,
1445 substate);
1448 DLIST_REMOVE(call->conn->call_list, call);
1449 call->list = DCESRV_LIST_NONE;
1452 static void dcesrv_sock_reply_done(struct tevent_req *subreq)
1454 struct dcesrv_sock_reply_state *substate = tevent_req_callback_data(subreq,
1455 struct dcesrv_sock_reply_state);
1456 int ret;
1457 int sys_errno;
1458 NTSTATUS status;
1459 struct dcesrv_call_state *call = substate->call;
1461 ret = tstream_writev_queue_recv(subreq, &sys_errno);
1462 TALLOC_FREE(subreq);
1463 if (ret == -1) {
1464 status = map_nt_error_from_unix_common(sys_errno);
1465 dcesrv_terminate_connection(substate->dce_conn, nt_errstr(status));
1466 return;
1469 talloc_free(substate);
1470 if (call) {
1471 talloc_free(call);
1478 struct dcesrv_socket_context {
1479 const struct dcesrv_endpoint *endpoint;
1480 struct dcesrv_context *dcesrv_ctx;
1484 static void dcesrv_read_fragment_done(struct tevent_req *subreq);
1486 static void dcesrv_sock_accept(struct stream_connection *srv_conn)
1488 NTSTATUS status;
1489 struct dcesrv_socket_context *dcesrv_sock =
1490 talloc_get_type(srv_conn->private_data, struct dcesrv_socket_context);
1491 enum dcerpc_transport_t transport =
1492 dcerpc_binding_get_transport(dcesrv_sock->endpoint->ep_description);
1493 struct dcesrv_connection *dcesrv_conn = NULL;
1494 int ret;
1495 struct tevent_req *subreq;
1496 struct loadparm_context *lp_ctx = dcesrv_sock->dcesrv_ctx->lp_ctx;
1498 dcesrv_cleanup_broken_connections(dcesrv_sock->dcesrv_ctx);
1500 if (!srv_conn->session_info) {
1501 status = auth_anonymous_session_info(srv_conn,
1502 lp_ctx,
1503 &srv_conn->session_info);
1504 if (!NT_STATUS_IS_OK(status)) {
1505 DEBUG(0,("dcesrv_sock_accept: auth_anonymous_session_info failed: %s\n",
1506 nt_errstr(status)));
1507 stream_terminate_connection(srv_conn, nt_errstr(status));
1508 return;
1512 status = dcesrv_endpoint_connect(dcesrv_sock->dcesrv_ctx,
1513 srv_conn,
1514 dcesrv_sock->endpoint,
1515 srv_conn->session_info,
1516 srv_conn->event.ctx,
1517 srv_conn->msg_ctx,
1518 srv_conn->server_id,
1519 DCESRV_CALL_STATE_FLAG_MAY_ASYNC,
1520 &dcesrv_conn);
1521 if (!NT_STATUS_IS_OK(status)) {
1522 DEBUG(0,("dcesrv_sock_accept: dcesrv_endpoint_connect failed: %s\n",
1523 nt_errstr(status)));
1524 stream_terminate_connection(srv_conn, nt_errstr(status));
1525 return;
1528 dcesrv_conn->transport.private_data = srv_conn;
1529 dcesrv_conn->transport.report_output_data = dcesrv_sock_report_output_data;
1531 TALLOC_FREE(srv_conn->event.fde);
1533 dcesrv_conn->send_queue = tevent_queue_create(dcesrv_conn, "dcesrv send queue");
1534 if (!dcesrv_conn->send_queue) {
1535 status = NT_STATUS_NO_MEMORY;
1536 DEBUG(0,("dcesrv_sock_accept: tevent_queue_create(%s)\n",
1537 nt_errstr(status)));
1538 stream_terminate_connection(srv_conn, nt_errstr(status));
1539 return;
1542 if (transport == NCACN_NP) {
1543 dcesrv_conn->auth_state.session_key = dcesrv_inherited_session_key;
1544 dcesrv_conn->stream = talloc_move(dcesrv_conn,
1545 &srv_conn->tstream);
1546 } else {
1547 ret = tstream_bsd_existing_socket(dcesrv_conn,
1548 socket_get_fd(srv_conn->socket),
1549 &dcesrv_conn->stream);
1550 if (ret == -1) {
1551 status = map_nt_error_from_unix_common(errno);
1552 DEBUG(0, ("dcesrv_sock_accept: "
1553 "failed to setup tstream: %s\n",
1554 nt_errstr(status)));
1555 stream_terminate_connection(srv_conn, nt_errstr(status));
1556 return;
1558 socket_set_flags(srv_conn->socket, SOCKET_FLAG_NOCLOSE);
1561 dcesrv_conn->local_address = srv_conn->local_address;
1562 dcesrv_conn->remote_address = srv_conn->remote_address;
1564 if (transport == NCALRPC) {
1565 uid_t uid;
1566 gid_t gid;
1568 ret = getpeereid(socket_get_fd(srv_conn->socket), &uid, &gid);
1569 if (ret == -1) {
1570 status = map_nt_error_from_unix_common(errno);
1571 DEBUG(0, ("dcesrv_sock_accept: "
1572 "getpeereid() failed for NCALRPC: %s\n",
1573 nt_errstr(status)));
1574 stream_terminate_connection(srv_conn, nt_errstr(status));
1575 return;
1577 if (uid == dcesrv_conn->dce_ctx->initial_euid) {
1578 struct tsocket_address *r = NULL;
1580 ret = tsocket_address_unix_from_path(dcesrv_conn,
1581 "/root/ncalrpc_as_system",
1582 &r);
1583 if (ret == -1) {
1584 status = map_nt_error_from_unix_common(errno);
1585 DEBUG(0, ("dcesrv_sock_accept: "
1586 "tsocket_address_unix_from_path() failed for NCALRPC: %s\n",
1587 nt_errstr(status)));
1588 stream_terminate_connection(srv_conn, nt_errstr(status));
1589 return;
1591 dcesrv_conn->remote_address = r;
1595 srv_conn->private_data = dcesrv_conn;
1597 irpc_add_name(srv_conn->msg_ctx, "rpc_server");
1599 subreq = dcerpc_read_ncacn_packet_send(dcesrv_conn,
1600 dcesrv_conn->event_ctx,
1601 dcesrv_conn->stream);
1602 if (!subreq) {
1603 status = NT_STATUS_NO_MEMORY;
1604 DEBUG(0,("dcesrv_sock_accept: dcerpc_read_fragment_buffer_send(%s)\n",
1605 nt_errstr(status)));
1606 stream_terminate_connection(srv_conn, nt_errstr(status));
1607 return;
1609 tevent_req_set_callback(subreq, dcesrv_read_fragment_done, dcesrv_conn);
1611 return;
1614 static void dcesrv_read_fragment_done(struct tevent_req *subreq)
1616 struct dcesrv_connection *dce_conn = tevent_req_callback_data(subreq,
1617 struct dcesrv_connection);
1618 struct dcesrv_context *dce_ctx = dce_conn->dce_ctx;
1619 struct ncacn_packet *pkt;
1620 DATA_BLOB buffer;
1621 NTSTATUS status;
1623 if (dce_conn->terminate) {
1625 * if the current connection is broken
1626 * we need to clean it up before any other connection
1628 dcesrv_terminate_connection(dce_conn, dce_conn->terminate);
1629 dcesrv_cleanup_broken_connections(dce_ctx);
1630 return;
1633 dcesrv_cleanup_broken_connections(dce_ctx);
1635 status = dcerpc_read_ncacn_packet_recv(subreq, dce_conn,
1636 &pkt, &buffer);
1637 TALLOC_FREE(subreq);
1638 if (!NT_STATUS_IS_OK(status)) {
1639 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1640 return;
1643 status = dcesrv_process_ncacn_packet(dce_conn, pkt, buffer);
1644 if (!NT_STATUS_IS_OK(status)) {
1645 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1646 return;
1649 subreq = dcerpc_read_ncacn_packet_send(dce_conn,
1650 dce_conn->event_ctx,
1651 dce_conn->stream);
1652 if (!subreq) {
1653 status = NT_STATUS_NO_MEMORY;
1654 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1655 return;
1657 tevent_req_set_callback(subreq, dcesrv_read_fragment_done, dce_conn);
1660 static void dcesrv_sock_recv(struct stream_connection *conn, uint16_t flags)
1662 struct dcesrv_connection *dce_conn = talloc_get_type(conn->private_data,
1663 struct dcesrv_connection);
1664 dcesrv_terminate_connection(dce_conn, "dcesrv_sock_recv triggered");
1667 static void dcesrv_sock_send(struct stream_connection *conn, uint16_t flags)
1669 struct dcesrv_connection *dce_conn = talloc_get_type(conn->private_data,
1670 struct dcesrv_connection);
1671 dcesrv_terminate_connection(dce_conn, "dcesrv_sock_send triggered");
1675 static const struct stream_server_ops dcesrv_stream_ops = {
1676 .name = "rpc",
1677 .accept_connection = dcesrv_sock_accept,
1678 .recv_handler = dcesrv_sock_recv,
1679 .send_handler = dcesrv_sock_send,
1682 static NTSTATUS dcesrv_add_ep_unix(struct dcesrv_context *dce_ctx,
1683 struct loadparm_context *lp_ctx,
1684 struct dcesrv_endpoint *e,
1685 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1687 struct dcesrv_socket_context *dcesrv_sock;
1688 uint16_t port = 1;
1689 NTSTATUS status;
1690 const char *endpoint;
1692 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1693 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1695 /* remember the endpoint of this socket */
1696 dcesrv_sock->endpoint = e;
1697 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1699 endpoint = dcerpc_binding_get_string_option(e->ep_description, "endpoint");
1701 status = stream_setup_socket(dcesrv_sock, event_ctx, lp_ctx,
1702 model_ops, &dcesrv_stream_ops,
1703 "unix", endpoint, &port,
1704 lpcfg_socket_options(lp_ctx),
1705 dcesrv_sock);
1706 if (!NT_STATUS_IS_OK(status)) {
1707 DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n",
1708 endpoint, nt_errstr(status)));
1711 return status;
1714 static NTSTATUS dcesrv_add_ep_ncalrpc(struct dcesrv_context *dce_ctx,
1715 struct loadparm_context *lp_ctx,
1716 struct dcesrv_endpoint *e,
1717 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1719 struct dcesrv_socket_context *dcesrv_sock;
1720 uint16_t port = 1;
1721 char *full_path;
1722 NTSTATUS status;
1723 const char *endpoint;
1725 endpoint = dcerpc_binding_get_string_option(e->ep_description, "endpoint");
1727 if (endpoint == NULL) {
1729 * No identifier specified: use DEFAULT.
1731 * TODO: DO NOT hardcode this value anywhere else. Rather, specify
1732 * no endpoint and let the epmapper worry about it.
1734 endpoint = "DEFAULT";
1735 status = dcerpc_binding_set_string_option(e->ep_description,
1736 "endpoint",
1737 endpoint);
1738 if (!NT_STATUS_IS_OK(status)) {
1739 DEBUG(0,("dcerpc_binding_set_string_option() failed - %s\n",
1740 nt_errstr(status)));
1741 return status;
1745 full_path = talloc_asprintf(dce_ctx, "%s/%s", lpcfg_ncalrpc_dir(lp_ctx),
1746 endpoint);
1748 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1749 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1751 /* remember the endpoint of this socket */
1752 dcesrv_sock->endpoint = e;
1753 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1755 status = stream_setup_socket(dcesrv_sock, event_ctx, lp_ctx,
1756 model_ops, &dcesrv_stream_ops,
1757 "unix", full_path, &port,
1758 lpcfg_socket_options(lp_ctx),
1759 dcesrv_sock);
1760 if (!NT_STATUS_IS_OK(status)) {
1761 DEBUG(0,("service_setup_stream_socket(identifier=%s,path=%s) failed - %s\n",
1762 endpoint, full_path, nt_errstr(status)));
1764 return status;
1767 static NTSTATUS dcesrv_add_ep_np(struct dcesrv_context *dce_ctx,
1768 struct loadparm_context *lp_ctx,
1769 struct dcesrv_endpoint *e,
1770 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1772 struct dcesrv_socket_context *dcesrv_sock;
1773 NTSTATUS status;
1774 const char *endpoint;
1776 endpoint = dcerpc_binding_get_string_option(e->ep_description, "endpoint");
1777 if (endpoint == NULL) {
1778 DEBUG(0, ("Endpoint mandatory for named pipes\n"));
1779 return NT_STATUS_INVALID_PARAMETER;
1782 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1783 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1785 /* remember the endpoint of this socket */
1786 dcesrv_sock->endpoint = e;
1787 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1789 status = tstream_setup_named_pipe(dce_ctx, event_ctx, lp_ctx,
1790 model_ops, &dcesrv_stream_ops,
1791 endpoint,
1792 dcesrv_sock);
1793 if (!NT_STATUS_IS_OK(status)) {
1794 DEBUG(0,("stream_setup_named_pipe(pipe=%s) failed - %s\n",
1795 endpoint, nt_errstr(status)));
1796 return status;
1799 return NT_STATUS_OK;
1803 add a socket address to the list of events, one event per dcerpc endpoint
1805 static NTSTATUS add_socket_rpc_tcp_iface(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e,
1806 struct tevent_context *event_ctx, const struct model_ops *model_ops,
1807 const char *address)
1809 struct dcesrv_socket_context *dcesrv_sock;
1810 uint16_t port = 0;
1811 NTSTATUS status;
1812 const char *endpoint;
1813 char port_str[6];
1815 endpoint = dcerpc_binding_get_string_option(e->ep_description, "endpoint");
1816 if (endpoint != NULL) {
1817 port = atoi(endpoint);
1820 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1821 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1823 /* remember the endpoint of this socket */
1824 dcesrv_sock->endpoint = e;
1825 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1827 status = stream_setup_socket(dcesrv_sock, event_ctx, dce_ctx->lp_ctx,
1828 model_ops, &dcesrv_stream_ops,
1829 "ip", address, &port,
1830 lpcfg_socket_options(dce_ctx->lp_ctx),
1831 dcesrv_sock);
1832 if (!NT_STATUS_IS_OK(status)) {
1833 DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) failed - %s\n",
1834 address, port, nt_errstr(status)));
1835 return status;
1838 snprintf(port_str, sizeof(port_str), "%u", port);
1840 status = dcerpc_binding_set_string_option(e->ep_description,
1841 "endpoint", port_str);
1842 if (!NT_STATUS_IS_OK(status)) {
1843 DEBUG(0,("dcerpc_binding_set_string_option(endpoint, %s) failed - %s\n",
1844 port_str, nt_errstr(status)));
1845 return status;
1848 return NT_STATUS_OK;
1851 #include "lib/socket/netif.h" /* Included here to work around the fact that socket_wrapper redefines bind() */
1853 static NTSTATUS dcesrv_add_ep_tcp(struct dcesrv_context *dce_ctx,
1854 struct loadparm_context *lp_ctx,
1855 struct dcesrv_endpoint *e,
1856 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1858 NTSTATUS status;
1860 /* Add TCP/IP sockets */
1861 if (lpcfg_interfaces(lp_ctx) && lpcfg_bind_interfaces_only(lp_ctx)) {
1862 int num_interfaces;
1863 int i;
1864 struct interface *ifaces;
1866 load_interface_list(dce_ctx, lp_ctx, &ifaces);
1868 num_interfaces = iface_list_count(ifaces);
1869 for(i = 0; i < num_interfaces; i++) {
1870 const char *address = iface_list_n_ip(ifaces, i);
1871 status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, address);
1872 NT_STATUS_NOT_OK_RETURN(status);
1874 } else {
1875 char **wcard;
1876 int i;
1877 int num_binds = 0;
1878 wcard = iface_list_wildcard(dce_ctx);
1879 NT_STATUS_HAVE_NO_MEMORY(wcard);
1880 for (i=0; wcard[i]; i++) {
1881 status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, wcard[i]);
1882 if (NT_STATUS_IS_OK(status)) {
1883 num_binds++;
1886 talloc_free(wcard);
1887 if (num_binds == 0) {
1888 return NT_STATUS_INVALID_PARAMETER_MIX;
1892 return NT_STATUS_OK;
1895 NTSTATUS dcesrv_add_ep(struct dcesrv_context *dce_ctx,
1896 struct loadparm_context *lp_ctx,
1897 struct dcesrv_endpoint *e,
1898 struct tevent_context *event_ctx,
1899 const struct model_ops *model_ops)
1901 enum dcerpc_transport_t transport =
1902 dcerpc_binding_get_transport(e->ep_description);
1904 switch (transport) {
1905 case NCACN_UNIX_STREAM:
1906 return dcesrv_add_ep_unix(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1908 case NCALRPC:
1909 return dcesrv_add_ep_ncalrpc(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1911 case NCACN_IP_TCP:
1912 return dcesrv_add_ep_tcp(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1914 case NCACN_NP:
1915 return dcesrv_add_ep_np(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1917 default:
1918 return NT_STATUS_NOT_SUPPORTED;
1924 * retrieve credentials from a dce_call
1926 _PUBLIC_ struct cli_credentials *dcesrv_call_credentials(struct dcesrv_call_state *dce_call)
1928 return dce_call->conn->auth_state.session_info->credentials;
1932 * returns true if this is an authenticated call
1934 _PUBLIC_ bool dcesrv_call_authenticated(struct dcesrv_call_state *dce_call)
1936 enum security_user_level level;
1937 level = security_session_user_level(dce_call->conn->auth_state.session_info, NULL);
1938 return level >= SECURITY_USER;
1942 * retrieve account_name for a dce_call
1944 _PUBLIC_ const char *dcesrv_call_account_name(struct dcesrv_call_state *dce_call)
1946 return dce_call->context->conn->auth_state.session_info->info->account_name;