Allow us to cope correctly with NT_STATUS_MORE_PROCESSING_REQUIRED when downgrading...
[Samba/ekacnet.git] / source4 / rpc_server / dcerpc_server.c
blob774309996dd7b2bb1a7465b894127f478cf19ed2
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 "librpc/rpc/dcerpc_proto.h"
30 #include "system/filesys.h"
31 #include "libcli/security/security.h"
32 #include "param/param.h"
34 /* this is only used when the client asks for an unknown interface */
35 #define DUMMY_ASSOC_GROUP 0x0FFFFFFF
37 extern const struct dcesrv_interface dcesrv_mgmt_interface;
41 find an association group given a assoc_group_id
43 static struct dcesrv_assoc_group *dcesrv_assoc_group_find(struct dcesrv_context *dce_ctx,
44 uint32_t id)
46 void *id_ptr;
48 id_ptr = idr_find(dce_ctx->assoc_groups_idr, id);
49 if (id_ptr == NULL) {
50 return NULL;
52 return talloc_get_type_abort(id_ptr, struct dcesrv_assoc_group);
56 take a reference to an existing association group
58 static struct dcesrv_assoc_group *dcesrv_assoc_group_reference(TALLOC_CTX *mem_ctx,
59 struct dcesrv_context *dce_ctx,
60 uint32_t id)
62 struct dcesrv_assoc_group *assoc_group;
64 assoc_group = dcesrv_assoc_group_find(dce_ctx, id);
65 if (assoc_group == NULL) {
66 DEBUG(0,(__location__ ": Failed to find assoc_group 0x%08x\n", id));
67 return NULL;
69 return talloc_reference(mem_ctx, assoc_group);
72 static int dcesrv_assoc_group_destructor(struct dcesrv_assoc_group *assoc_group)
74 int ret;
75 ret = idr_remove(assoc_group->dce_ctx->assoc_groups_idr, assoc_group->id);
76 if (ret != 0) {
77 DEBUG(0,(__location__ ": Failed to remove assoc_group 0x%08x\n",
78 assoc_group->id));
80 return 0;
84 allocate a new association group
86 static struct dcesrv_assoc_group *dcesrv_assoc_group_new(TALLOC_CTX *mem_ctx,
87 struct dcesrv_context *dce_ctx)
89 struct dcesrv_assoc_group *assoc_group;
90 int id;
92 assoc_group = talloc_zero(mem_ctx, struct dcesrv_assoc_group);
93 if (assoc_group == NULL) {
94 return NULL;
97 id = idr_get_new_random(dce_ctx->assoc_groups_idr, assoc_group, UINT16_MAX);
98 if (id == -1) {
99 talloc_free(assoc_group);
100 DEBUG(0,(__location__ ": Out of association groups!\n"));
101 return NULL;
104 assoc_group->id = id;
105 assoc_group->dce_ctx = dce_ctx;
107 talloc_set_destructor(assoc_group, dcesrv_assoc_group_destructor);
109 return assoc_group;
114 see if two endpoints match
116 static bool endpoints_match(const struct dcerpc_binding *ep1,
117 const struct dcerpc_binding *ep2)
119 if (ep1->transport != ep2->transport) {
120 return false;
123 if (!ep1->endpoint || !ep2->endpoint) {
124 return ep1->endpoint == ep2->endpoint;
127 if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
128 return false;
130 return true;
134 find an endpoint in the dcesrv_context
136 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
137 const struct dcerpc_binding *ep_description)
139 struct dcesrv_endpoint *ep;
140 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
141 if (endpoints_match(ep->ep_description, ep_description)) {
142 return ep;
145 return NULL;
149 find a registered context_id from a bind or alter_context
151 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn,
152 uint32_t context_id)
154 struct dcesrv_connection_context *c;
155 for (c=conn->contexts;c;c=c->next) {
156 if (c->context_id == context_id) return c;
158 return NULL;
162 see if a uuid and if_version match to an interface
164 static bool interface_match(const struct dcesrv_interface *if1,
165 const struct dcesrv_interface *if2)
167 return (if1->syntax_id.if_version == if2->syntax_id.if_version &&
168 GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
172 find the interface operations on an endpoint
174 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
175 const struct dcesrv_interface *iface)
177 struct dcesrv_if_list *ifl;
178 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
179 if (interface_match(&(ifl->iface), iface)) {
180 return &(ifl->iface);
183 return NULL;
187 see if a uuid and if_version match to an interface
189 static bool interface_match_by_uuid(const struct dcesrv_interface *iface,
190 const struct GUID *uuid, uint32_t if_version)
192 return (iface->syntax_id.if_version == if_version &&
193 GUID_equal(&iface->syntax_id.uuid, uuid));
197 find the interface operations on an endpoint by uuid
199 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
200 const struct GUID *uuid, uint32_t if_version)
202 struct dcesrv_if_list *ifl;
203 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
204 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
205 return &(ifl->iface);
208 return NULL;
212 find the earlier parts of a fragmented call awaiting reassembily
214 static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
216 struct dcesrv_call_state *c;
217 for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
218 if (c->pkt.call_id == call_id) {
219 return c;
222 return NULL;
226 register an interface on an endpoint
228 _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
229 const char *ep_name,
230 const struct dcesrv_interface *iface,
231 const struct security_descriptor *sd)
233 struct dcesrv_endpoint *ep;
234 struct dcesrv_if_list *ifl;
235 struct dcerpc_binding *binding;
236 bool add_ep = false;
237 NTSTATUS status;
239 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
241 if (NT_STATUS_IS_ERR(status)) {
242 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
243 return status;
246 /* check if this endpoint exists
248 if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
249 ep = talloc(dce_ctx, struct dcesrv_endpoint);
250 if (!ep) {
251 return NT_STATUS_NO_MEMORY;
253 ZERO_STRUCTP(ep);
254 ep->ep_description = talloc_reference(ep, binding);
255 add_ep = true;
257 /* add mgmt interface */
258 ifl = talloc(dce_ctx, struct dcesrv_if_list);
259 if (!ifl) {
260 return NT_STATUS_NO_MEMORY;
263 memcpy(&(ifl->iface), &dcesrv_mgmt_interface,
264 sizeof(struct dcesrv_interface));
266 DLIST_ADD(ep->interface_list, ifl);
269 /* see if the interface is already registered on te endpoint */
270 if (find_interface(ep, iface)!=NULL) {
271 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
272 iface->name, ep_name));
273 return NT_STATUS_OBJECT_NAME_COLLISION;
276 /* talloc a new interface list element */
277 ifl = talloc(dce_ctx, struct dcesrv_if_list);
278 if (!ifl) {
279 return NT_STATUS_NO_MEMORY;
282 /* copy the given interface struct to the one on the endpoints interface list */
283 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
285 /* if we have a security descriptor given,
286 * we should see if we can set it up on the endpoint
288 if (sd != NULL) {
289 /* if there's currently no security descriptor given on the endpoint
290 * we try to set it
292 if (ep->sd == NULL) {
293 ep->sd = security_descriptor_copy(dce_ctx, sd);
296 /* if now there's no security descriptor given on the endpoint
297 * something goes wrong, either we failed to copy the security descriptor
298 * or there was already one on the endpoint
300 if (ep->sd != NULL) {
301 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
302 " on endpoint '%s'\n",
303 iface->name, ep_name));
304 if (add_ep) free(ep);
305 free(ifl);
306 return NT_STATUS_OBJECT_NAME_COLLISION;
310 /* finally add the interface on the endpoint */
311 DLIST_ADD(ep->interface_list, ifl);
313 /* if it's a new endpoint add it to the dcesrv_context */
314 if (add_ep) {
315 DLIST_ADD(dce_ctx->endpoint_list, ep);
318 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
319 iface->name, ep_name));
321 return NT_STATUS_OK;
324 NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
325 DATA_BLOB *session_key)
327 if (p->auth_state.session_info->session_key.length) {
328 *session_key = p->auth_state.session_info->session_key;
329 return NT_STATUS_OK;
331 return NT_STATUS_NO_USER_SESSION_KEY;
334 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *c,
335 DATA_BLOB *session_key)
337 return dcerpc_generic_session_key(NULL, session_key);
341 fetch the user session key - may be default (above) or the SMB session key
343 The key is always truncated to 16 bytes
345 _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
346 DATA_BLOB *session_key)
348 NTSTATUS status = p->auth_state.session_key(p, session_key);
349 if (!NT_STATUS_IS_OK(status)) {
350 return status;
353 session_key->length = MIN(session_key->length, 16);
355 return NT_STATUS_OK;
359 connect to a dcerpc endpoint
361 _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
362 TALLOC_CTX *mem_ctx,
363 const struct dcesrv_endpoint *ep,
364 struct auth_session_info *session_info,
365 struct tevent_context *event_ctx,
366 struct messaging_context *msg_ctx,
367 struct server_id server_id,
368 uint32_t state_flags,
369 struct dcesrv_connection **_p)
371 struct dcesrv_connection *p;
373 if (!session_info) {
374 return NT_STATUS_ACCESS_DENIED;
377 p = talloc(mem_ctx, struct dcesrv_connection);
378 NT_STATUS_HAVE_NO_MEMORY(p);
380 if (!talloc_reference(p, session_info)) {
381 talloc_free(p);
382 return NT_STATUS_NO_MEMORY;
385 p->dce_ctx = dce_ctx;
386 p->endpoint = ep;
387 p->contexts = NULL;
388 p->call_list = NULL;
389 p->packet_log_dir = lp_lockdir(dce_ctx->lp_ctx);
390 p->incoming_fragmented_call_list = NULL;
391 p->pending_call_list = NULL;
392 p->cli_max_recv_frag = 0;
393 p->partial_input = data_blob(NULL, 0);
394 p->auth_state.auth_info = NULL;
395 p->auth_state.gensec_security = NULL;
396 p->auth_state.session_info = session_info;
397 p->auth_state.session_key = dcesrv_generic_session_key;
398 p->event_ctx = event_ctx;
399 p->msg_ctx = msg_ctx;
400 p->server_id = server_id;
401 p->processing = false;
402 p->state_flags = state_flags;
403 ZERO_STRUCT(p->transport);
405 *_p = p;
406 return NT_STATUS_OK;
409 static void dcesrv_init_hdr(struct ncacn_packet *pkt, bool bigendian)
411 pkt->rpc_vers = 5;
412 pkt->rpc_vers_minor = 0;
413 if (bigendian) {
414 pkt->drep[0] = 0;
415 } else {
416 pkt->drep[0] = DCERPC_DREP_LE;
418 pkt->drep[1] = 0;
419 pkt->drep[2] = 0;
420 pkt->drep[3] = 0;
424 move a call from an existing linked list to the specified list. This
425 prevents bugs where we forget to remove the call from a previous
426 list when moving it.
428 static void dcesrv_call_set_list(struct dcesrv_call_state *call,
429 enum dcesrv_call_list list)
431 switch (call->list) {
432 case DCESRV_LIST_NONE:
433 break;
434 case DCESRV_LIST_CALL_LIST:
435 DLIST_REMOVE(call->conn->call_list, call);
436 break;
437 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
438 DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
439 break;
440 case DCESRV_LIST_PENDING_CALL_LIST:
441 DLIST_REMOVE(call->conn->pending_call_list, call);
442 break;
444 call->list = list;
445 switch (list) {
446 case DCESRV_LIST_NONE:
447 break;
448 case DCESRV_LIST_CALL_LIST:
449 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
450 break;
451 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
452 DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
453 break;
454 case DCESRV_LIST_PENDING_CALL_LIST:
455 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
456 break;
461 return a dcerpc fault
463 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
465 struct ncacn_packet pkt;
466 struct data_blob_list_item *rep;
467 uint8_t zeros[4];
468 NTSTATUS status;
470 /* setup a bind_ack */
471 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
472 pkt.auth_length = 0;
473 pkt.call_id = call->pkt.call_id;
474 pkt.ptype = DCERPC_PKT_FAULT;
475 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
476 pkt.u.fault.alloc_hint = 0;
477 pkt.u.fault.context_id = 0;
478 pkt.u.fault.cancel_count = 0;
479 pkt.u.fault.status = fault_code;
481 ZERO_STRUCT(zeros);
482 pkt.u.fault._pad = data_blob_const(zeros, sizeof(zeros));
484 rep = talloc(call, struct data_blob_list_item);
485 if (!rep) {
486 return NT_STATUS_NO_MEMORY;
489 status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
490 if (!NT_STATUS_IS_OK(status)) {
491 return status;
494 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
496 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
497 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
499 if (call->conn->call_list && call->conn->call_list->replies) {
500 if (call->conn->transport.report_output_data) {
501 call->conn->transport.report_output_data(call->conn);
505 return NT_STATUS_OK;
510 return a dcerpc bind_nak
512 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
514 struct ncacn_packet pkt;
515 struct data_blob_list_item *rep;
516 NTSTATUS status;
518 /* setup a bind_nak */
519 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
520 pkt.auth_length = 0;
521 pkt.call_id = call->pkt.call_id;
522 pkt.ptype = DCERPC_PKT_BIND_NAK;
523 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
524 pkt.u.bind_nak.reject_reason = reason;
525 if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
526 pkt.u.bind_nak.versions.v.num_versions = 0;
529 rep = talloc(call, struct data_blob_list_item);
530 if (!rep) {
531 return NT_STATUS_NO_MEMORY;
534 status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
535 if (!NT_STATUS_IS_OK(status)) {
536 return status;
539 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
541 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
542 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
544 if (call->conn->call_list && call->conn->call_list->replies) {
545 if (call->conn->transport.report_output_data) {
546 call->conn->transport.report_output_data(call->conn);
550 return NT_STATUS_OK;
553 static int dcesrv_connection_context_destructor(struct dcesrv_connection_context *c)
555 DLIST_REMOVE(c->conn->contexts, c);
557 if (c->iface) {
558 c->iface->unbind(c, c->iface);
561 return 0;
565 handle a bind request
567 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
569 uint32_t if_version, transfer_syntax_version;
570 struct GUID uuid, *transfer_syntax_uuid;
571 struct ncacn_packet pkt;
572 struct data_blob_list_item *rep;
573 NTSTATUS status;
574 uint32_t result=0, reason=0;
575 uint32_t context_id;
576 const struct dcesrv_interface *iface;
577 uint32_t extra_flags = 0;
580 if provided, check the assoc_group is valid
582 if (call->pkt.u.bind.assoc_group_id != 0 &&
583 lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
584 dcesrv_assoc_group_find(call->conn->dce_ctx, call->pkt.u.bind.assoc_group_id) == NULL) {
585 return dcesrv_bind_nak(call, 0);
588 if (call->pkt.u.bind.num_contexts < 1 ||
589 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
590 return dcesrv_bind_nak(call, 0);
593 context_id = call->pkt.u.bind.ctx_list[0].context_id;
595 /* you can't bind twice on one context */
596 if (dcesrv_find_context(call->conn, context_id) != NULL) {
597 return dcesrv_bind_nak(call, 0);
600 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
601 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
603 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
604 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
605 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
606 ndr_transfer_syntax.if_version != transfer_syntax_version) {
607 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
608 /* we only do NDR encoded dcerpc */
609 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
610 talloc_free(uuid_str);
611 return dcesrv_bind_nak(call, 0);
614 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
615 if (iface == NULL) {
616 char *uuid_str = GUID_string(call, &uuid);
617 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
618 talloc_free(uuid_str);
620 /* we don't know about that interface */
621 result = DCERPC_BIND_PROVIDER_REJECT;
622 reason = DCERPC_BIND_REASON_ASYNTAX;
625 if (iface) {
626 /* add this context to the list of available context_ids */
627 struct dcesrv_connection_context *context = talloc(call->conn,
628 struct dcesrv_connection_context);
629 if (context == NULL) {
630 return dcesrv_bind_nak(call, 0);
632 context->conn = call->conn;
633 context->iface = iface;
634 context->context_id = context_id;
635 if (call->pkt.u.bind.assoc_group_id != 0) {
636 context->assoc_group = dcesrv_assoc_group_reference(context,
637 call->conn->dce_ctx,
638 call->pkt.u.bind.assoc_group_id);
639 } else {
640 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
642 if (context->assoc_group == NULL) {
643 talloc_free(context);
644 return dcesrv_bind_nak(call, 0);
646 context->private_data = NULL;
647 DLIST_ADD(call->conn->contexts, context);
648 call->context = context;
649 talloc_set_destructor(context, dcesrv_connection_context_destructor);
651 status = iface->bind(call, iface, if_version);
652 if (!NT_STATUS_IS_OK(status)) {
653 char *uuid_str = GUID_string(call, &uuid);
654 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
655 uuid_str, if_version, nt_errstr(status)));
656 talloc_free(uuid_str);
657 /* we don't want to trigger the iface->unbind() hook */
658 context->iface = NULL;
659 talloc_free(call->context);
660 call->context = NULL;
661 return dcesrv_bind_nak(call, 0);
665 if (call->conn->cli_max_recv_frag == 0) {
666 call->conn->cli_max_recv_frag = MIN(0x2000, call->pkt.u.bind.max_recv_frag);
669 if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) &&
670 lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","header signing", false)) {
671 call->conn->state_flags |= DCESRV_CALL_STATE_FLAG_HEADER_SIGNING;
672 extra_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
675 /* handle any authentication that is being requested */
676 if (!dcesrv_auth_bind(call)) {
677 talloc_free(call->context);
678 call->context = NULL;
679 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
682 /* setup a bind_ack */
683 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
684 pkt.auth_length = 0;
685 pkt.call_id = call->pkt.call_id;
686 pkt.ptype = DCERPC_PKT_BIND_ACK;
687 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
688 pkt.u.bind_ack.max_xmit_frag = call->conn->cli_max_recv_frag;
689 pkt.u.bind_ack.max_recv_frag = 0x2000;
692 make it possible for iface->bind() to specify the assoc_group_id
693 This helps the openchange mapiproxy plugin to work correctly.
695 metze
697 if (call->context) {
698 pkt.u.bind_ack.assoc_group_id = call->context->assoc_group->id;
699 } else {
700 pkt.u.bind_ack.assoc_group_id = DUMMY_ASSOC_GROUP;
703 if (iface) {
704 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
705 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
706 } else {
707 pkt.u.bind_ack.secondary_address = "";
709 pkt.u.bind_ack.num_results = 1;
710 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
711 if (!pkt.u.bind_ack.ctx_list) {
712 talloc_free(call->context);
713 call->context = NULL;
714 return NT_STATUS_NO_MEMORY;
716 pkt.u.bind_ack.ctx_list[0].result = result;
717 pkt.u.bind_ack.ctx_list[0].reason = reason;
718 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
719 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
721 status = dcesrv_auth_bind_ack(call, &pkt);
722 if (!NT_STATUS_IS_OK(status)) {
723 talloc_free(call->context);
724 call->context = NULL;
725 return dcesrv_bind_nak(call, 0);
728 rep = talloc(call, struct data_blob_list_item);
729 if (!rep) {
730 talloc_free(call->context);
731 call->context = NULL;
732 return NT_STATUS_NO_MEMORY;
735 status = ncacn_push_auth(&rep->blob, call, &pkt,
736 call->conn->auth_state.auth_info);
737 if (!NT_STATUS_IS_OK(status)) {
738 talloc_free(call->context);
739 call->context = NULL;
740 return status;
743 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
745 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
746 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
748 if (call->conn->call_list && call->conn->call_list->replies) {
749 if (call->conn->transport.report_output_data) {
750 call->conn->transport.report_output_data(call->conn);
754 return NT_STATUS_OK;
759 handle a auth3 request
761 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
763 /* handle the auth3 in the auth code */
764 if (!dcesrv_auth_auth3(call)) {
765 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
768 talloc_free(call);
770 /* we don't send a reply to a auth3 request, except by a
771 fault */
772 return NT_STATUS_OK;
777 handle a bind request
779 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
781 uint32_t if_version, transfer_syntax_version;
782 struct dcesrv_connection_context *context;
783 const struct dcesrv_interface *iface;
784 struct GUID uuid, *transfer_syntax_uuid;
785 NTSTATUS status;
787 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
788 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
790 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
791 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
792 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
793 ndr_transfer_syntax.if_version != transfer_syntax_version) {
794 /* we only do NDR encoded dcerpc */
795 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
798 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
799 if (iface == NULL) {
800 char *uuid_str = GUID_string(call, &uuid);
801 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
802 talloc_free(uuid_str);
803 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
806 /* add this context to the list of available context_ids */
807 context = talloc(call->conn, struct dcesrv_connection_context);
808 if (context == NULL) {
809 return NT_STATUS_NO_MEMORY;
811 context->conn = call->conn;
812 context->iface = iface;
813 context->context_id = context_id;
814 if (call->pkt.u.alter.assoc_group_id != 0) {
815 context->assoc_group = dcesrv_assoc_group_reference(context,
816 call->conn->dce_ctx,
817 call->pkt.u.alter.assoc_group_id);
818 } else {
819 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
821 if (context->assoc_group == NULL) {
822 talloc_free(context);
823 call->context = NULL;
824 return NT_STATUS_NO_MEMORY;
826 context->private_data = NULL;
827 DLIST_ADD(call->conn->contexts, context);
828 call->context = context;
829 talloc_set_destructor(context, dcesrv_connection_context_destructor);
831 status = iface->bind(call, iface, if_version);
832 if (!NT_STATUS_IS_OK(status)) {
833 /* we don't want to trigger the iface->unbind() hook */
834 context->iface = NULL;
835 talloc_free(context);
836 call->context = NULL;
837 return status;
840 return NT_STATUS_OK;
845 handle a alter context request
847 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
849 struct ncacn_packet pkt;
850 struct data_blob_list_item *rep;
851 NTSTATUS status;
852 uint32_t result=0, reason=0;
853 uint32_t context_id;
855 /* handle any authentication that is being requested */
856 if (!dcesrv_auth_alter(call)) {
857 /* TODO: work out the right reject code */
858 result = DCERPC_BIND_PROVIDER_REJECT;
859 reason = DCERPC_BIND_REASON_ASYNTAX;
862 context_id = call->pkt.u.alter.ctx_list[0].context_id;
864 /* see if they are asking for a new interface */
865 if (result == 0) {
866 call->context = dcesrv_find_context(call->conn, context_id);
867 if (!call->context) {
868 status = dcesrv_alter_new_context(call, context_id);
869 if (!NT_STATUS_IS_OK(status)) {
870 result = DCERPC_BIND_PROVIDER_REJECT;
871 reason = DCERPC_BIND_REASON_ASYNTAX;
876 if (result == 0 &&
877 call->pkt.u.alter.assoc_group_id != 0 &&
878 lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
879 call->pkt.u.alter.assoc_group_id != call->context->assoc_group->id) {
880 DEBUG(0,(__location__ ": Failed attempt to use new assoc_group in alter context (0x%08x 0x%08x)\n",
881 call->context->assoc_group->id, call->pkt.u.alter.assoc_group_id));
882 /* TODO: can they ask for a new association group? */
883 result = DCERPC_BIND_PROVIDER_REJECT;
884 reason = DCERPC_BIND_REASON_ASYNTAX;
887 /* setup a alter_resp */
888 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
889 pkt.auth_length = 0;
890 pkt.call_id = call->pkt.call_id;
891 pkt.ptype = DCERPC_PKT_ALTER_RESP;
892 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
893 pkt.u.alter_resp.max_xmit_frag = 0x2000;
894 pkt.u.alter_resp.max_recv_frag = 0x2000;
895 if (result == 0) {
896 pkt.u.alter_resp.assoc_group_id = call->context->assoc_group->id;
897 } else {
898 pkt.u.alter_resp.assoc_group_id = 0;
900 pkt.u.alter_resp.num_results = 1;
901 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
902 if (!pkt.u.alter_resp.ctx_list) {
903 return NT_STATUS_NO_MEMORY;
905 pkt.u.alter_resp.ctx_list[0].result = result;
906 pkt.u.alter_resp.ctx_list[0].reason = reason;
907 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
908 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
909 pkt.u.alter_resp.secondary_address = "";
911 status = dcesrv_auth_alter_ack(call, &pkt);
912 if (!NT_STATUS_IS_OK(status)) {
913 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
914 || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
915 || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
916 || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
917 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
919 return dcesrv_fault(call, 0);
922 rep = talloc(call, struct data_blob_list_item);
923 if (!rep) {
924 return NT_STATUS_NO_MEMORY;
927 status = ncacn_push_auth(&rep->blob, call, &pkt, call->conn->auth_state.auth_info);
928 if (!NT_STATUS_IS_OK(status)) {
929 return status;
932 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
934 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
935 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
937 if (call->conn->call_list && call->conn->call_list->replies) {
938 if (call->conn->transport.report_output_data) {
939 call->conn->transport.report_output_data(call->conn);
943 return NT_STATUS_OK;
947 handle a dcerpc request packet
949 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
951 struct ndr_pull *pull;
952 NTSTATUS status;
953 struct dcesrv_connection_context *context;
955 /* if authenticated, and the mech we use can't do async replies, don't use them... */
956 if (call->conn->auth_state.gensec_security &&
957 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
958 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
961 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
962 if (context == NULL) {
963 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
966 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
967 NT_STATUS_HAVE_NO_MEMORY(pull);
969 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
971 call->context = context;
972 call->ndr_pull = pull;
974 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
975 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
978 /* unravel the NDR for the packet */
979 status = context->iface->ndr_pull(call, call, pull, &call->r);
980 if (!NT_STATUS_IS_OK(status)) {
981 return dcesrv_fault(call, call->fault_code);
984 if (pull->offset != pull->data_size) {
985 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
986 pull->data_size - pull->offset));
987 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
990 /* call the dispatch function */
991 status = context->iface->dispatch(call, call, call->r);
992 if (!NT_STATUS_IS_OK(status)) {
993 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
994 context->iface->name,
995 call->pkt.u.request.opnum,
996 dcerpc_errstr(pull, call->fault_code)));
997 return dcesrv_fault(call, call->fault_code);
1000 /* add the call to the pending list */
1001 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
1003 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
1004 return NT_STATUS_OK;
1007 return dcesrv_reply(call);
1010 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
1012 struct ndr_push *push;
1013 NTSTATUS status;
1014 DATA_BLOB stub;
1015 uint32_t total_length, chunk_size;
1016 struct dcesrv_connection_context *context = call->context;
1017 size_t sig_size = 0;
1019 /* call the reply function */
1020 status = context->iface->reply(call, call, call->r);
1021 if (!NT_STATUS_IS_OK(status)) {
1022 return dcesrv_fault(call, call->fault_code);
1025 /* form the reply NDR */
1026 push = ndr_push_init_ctx(call);
1027 NT_STATUS_HAVE_NO_MEMORY(push);
1029 /* carry over the pointer count to the reply in case we are
1030 using full pointer. See NDR specification for full
1031 pointers */
1032 push->ptr_count = call->ndr_pull->ptr_count;
1034 if (lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
1035 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1038 status = context->iface->ndr_push(call, call, push, call->r);
1039 if (!NT_STATUS_IS_OK(status)) {
1040 return dcesrv_fault(call, call->fault_code);
1043 stub = ndr_push_blob(push);
1045 total_length = stub.length;
1047 /* we can write a full max_recv_frag size, minus the dcerpc
1048 request header size */
1049 chunk_size = call->conn->cli_max_recv_frag;
1050 chunk_size -= DCERPC_REQUEST_LENGTH;
1051 if (call->conn->auth_state.auth_info &&
1052 call->conn->auth_state.gensec_security) {
1053 sig_size = gensec_sig_size(call->conn->auth_state.gensec_security,
1054 call->conn->cli_max_recv_frag);
1055 if (sig_size) {
1056 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1057 chunk_size -= sig_size;
1060 chunk_size -= (chunk_size % 16);
1062 do {
1063 uint32_t length;
1064 struct data_blob_list_item *rep;
1065 struct ncacn_packet pkt;
1067 rep = talloc(call, struct data_blob_list_item);
1068 NT_STATUS_HAVE_NO_MEMORY(rep);
1070 length = MIN(chunk_size, stub.length);
1072 /* form the dcerpc response packet */
1073 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
1074 pkt.auth_length = 0;
1075 pkt.call_id = call->pkt.call_id;
1076 pkt.ptype = DCERPC_PKT_RESPONSE;
1077 pkt.pfc_flags = 0;
1078 if (stub.length == total_length) {
1079 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1081 if (length == stub.length) {
1082 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1084 pkt.u.response.alloc_hint = stub.length;
1085 pkt.u.response.context_id = call->pkt.u.request.context_id;
1086 pkt.u.response.cancel_count = 0;
1087 pkt.u.response.stub_and_verifier.data = stub.data;
1088 pkt.u.response.stub_and_verifier.length = length;
1090 if (!dcesrv_auth_response(call, &rep->blob, sig_size, &pkt)) {
1091 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
1094 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
1096 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
1098 stub.data += length;
1099 stub.length -= length;
1100 } while (stub.length != 0);
1102 /* move the call from the pending to the finished calls list */
1103 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
1105 if (call->conn->call_list && call->conn->call_list->replies) {
1106 if (call->conn->transport.report_output_data) {
1107 call->conn->transport.report_output_data(call->conn);
1111 return NT_STATUS_OK;
1115 remove the call from the right list when freed
1117 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1119 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1120 return 0;
1123 _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_local_address(struct dcesrv_connection *conn)
1125 return conn->local_address;
1128 _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_remote_address(struct dcesrv_connection *conn)
1130 return conn->remote_address;
1134 process some input to a dcerpc endpoint server.
1136 NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
1137 struct ncacn_packet *pkt,
1138 DATA_BLOB blob)
1140 NTSTATUS status;
1141 struct dcesrv_call_state *call;
1143 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1144 if (!call) {
1145 data_blob_free(&blob);
1146 talloc_free(pkt);
1147 return NT_STATUS_NO_MEMORY;
1149 call->conn = dce_conn;
1150 call->event_ctx = dce_conn->event_ctx;
1151 call->msg_ctx = dce_conn->msg_ctx;
1152 call->state_flags = call->conn->state_flags;
1153 call->time = timeval_current();
1154 call->list = DCESRV_LIST_NONE;
1156 talloc_steal(call, pkt);
1157 talloc_steal(call, blob.data);
1158 call->pkt = *pkt;
1160 talloc_set_destructor(call, dcesrv_call_dequeue);
1162 /* we have to check the signing here, before combining the
1163 pdus */
1164 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1165 !dcesrv_auth_request(call, &blob)) {
1166 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1169 /* see if this is a continued packet */
1170 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1171 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1172 struct dcesrv_call_state *call2 = call;
1173 uint32_t alloc_size;
1175 /* we only allow fragmented requests, no other packet types */
1176 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1177 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1180 /* this is a continuation of an existing call - find the call then
1181 tack it on the end */
1182 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1183 if (!call) {
1184 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1187 if (call->pkt.ptype != call2->pkt.ptype) {
1188 /* trying to play silly buggers are we? */
1189 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1192 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1193 call2->pkt.u.request.stub_and_verifier.length;
1194 if (call->pkt.u.request.alloc_hint > alloc_size) {
1195 alloc_size = call->pkt.u.request.alloc_hint;
1198 call->pkt.u.request.stub_and_verifier.data =
1199 talloc_realloc(call,
1200 call->pkt.u.request.stub_and_verifier.data,
1201 uint8_t, alloc_size);
1202 if (!call->pkt.u.request.stub_and_verifier.data) {
1203 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1205 memcpy(call->pkt.u.request.stub_and_verifier.data +
1206 call->pkt.u.request.stub_and_verifier.length,
1207 call2->pkt.u.request.stub_and_verifier.data,
1208 call2->pkt.u.request.stub_and_verifier.length);
1209 call->pkt.u.request.stub_and_verifier.length +=
1210 call2->pkt.u.request.stub_and_verifier.length;
1212 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1214 talloc_free(call2);
1217 /* this may not be the last pdu in the chain - if its isn't then
1218 just put it on the incoming_fragmented_call_list and wait for the rest */
1219 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1220 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1221 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1222 return NT_STATUS_OK;
1225 /* This removes any fragments we may have had stashed away */
1226 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1228 switch (call->pkt.ptype) {
1229 case DCERPC_PKT_BIND:
1230 status = dcesrv_bind(call);
1231 break;
1232 case DCERPC_PKT_AUTH3:
1233 status = dcesrv_auth3(call);
1234 break;
1235 case DCERPC_PKT_ALTER:
1236 status = dcesrv_alter(call);
1237 break;
1238 case DCERPC_PKT_REQUEST:
1239 status = dcesrv_request(call);
1240 break;
1241 default:
1242 status = NT_STATUS_INVALID_PARAMETER;
1243 break;
1246 /* if we are going to be sending a reply then add
1247 it to the list of pending calls. We add it to the end to keep the call
1248 list in the order we will answer */
1249 if (!NT_STATUS_IS_OK(status)) {
1250 talloc_free(call);
1253 return status;
1256 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1257 struct loadparm_context *lp_ctx,
1258 const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1260 NTSTATUS status;
1261 struct dcesrv_context *dce_ctx;
1262 int i;
1264 if (!endpoint_servers) {
1265 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1266 return NT_STATUS_INTERNAL_ERROR;
1269 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1270 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1271 dce_ctx->endpoint_list = NULL;
1272 dce_ctx->lp_ctx = lp_ctx;
1273 dce_ctx->assoc_groups_idr = idr_init(dce_ctx);
1274 NT_STATUS_HAVE_NO_MEMORY(dce_ctx->assoc_groups_idr);
1276 for (i=0;endpoint_servers[i];i++) {
1277 const struct dcesrv_endpoint_server *ep_server;
1279 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1280 if (!ep_server) {
1281 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1282 return NT_STATUS_INTERNAL_ERROR;
1285 status = ep_server->init_server(dce_ctx, ep_server);
1286 if (!NT_STATUS_IS_OK(status)) {
1287 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1288 nt_errstr(status)));
1289 return status;
1293 *_dce_ctx = dce_ctx;
1294 return NT_STATUS_OK;
1297 /* the list of currently registered DCERPC endpoint servers.
1299 static struct ep_server {
1300 struct dcesrv_endpoint_server *ep_server;
1301 } *ep_servers = NULL;
1302 static int num_ep_servers;
1305 register a DCERPC endpoint server.
1307 The 'name' can be later used by other backends to find the operations
1308 structure for this backend.
1310 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1312 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1314 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1316 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1317 /* its already registered! */
1318 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1319 ep_server->name));
1320 return NT_STATUS_OBJECT_NAME_COLLISION;
1323 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1324 if (!ep_servers) {
1325 smb_panic("out of memory in dcerpc_register");
1328 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1329 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1331 num_ep_servers++;
1333 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1334 ep_server->name));
1336 return NT_STATUS_OK;
1340 return the operations structure for a named backend of the specified type
1342 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1344 int i;
1346 for (i=0;i<num_ep_servers;i++) {
1347 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1348 return ep_servers[i].ep_server;
1352 return NULL;
1355 void dcerpc_server_init(struct loadparm_context *lp_ctx)
1357 static bool initialized;
1358 extern NTSTATUS dcerpc_server_wkssvc_init(void);
1359 extern NTSTATUS dcerpc_server_drsuapi_init(void);
1360 extern NTSTATUS dcerpc_server_winreg_init(void);
1361 extern NTSTATUS dcerpc_server_spoolss_init(void);
1362 extern NTSTATUS dcerpc_server_epmapper_init(void);
1363 extern NTSTATUS dcerpc_server_srvsvc_init(void);
1364 extern NTSTATUS dcerpc_server_netlogon_init(void);
1365 extern NTSTATUS dcerpc_server_rpcecho_init(void);
1366 extern NTSTATUS dcerpc_server_unixinfo_init(void);
1367 extern NTSTATUS dcerpc_server_samr_init(void);
1368 extern NTSTATUS dcerpc_server_remote_init(void);
1369 extern NTSTATUS dcerpc_server_lsa_init(void);
1370 extern NTSTATUS dcerpc_server_browser_init(void);
1371 init_module_fn static_init[] = { STATIC_dcerpc_server_MODULES };
1372 init_module_fn *shared_init;
1374 if (initialized) {
1375 return;
1377 initialized = true;
1379 shared_init = load_samba_modules(NULL, lp_ctx, "dcerpc_server");
1381 run_init_functions(static_init);
1382 run_init_functions(shared_init);
1384 talloc_free(shared_init);
1388 return the DCERPC module version, and the size of some critical types
1389 This can be used by endpoint server modules to either detect compilation errors, or provide
1390 multiple implementations for different smbd compilation options in one module
1392 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1394 static const struct dcesrv_critical_sizes critical_sizes = {
1395 DCERPC_MODULE_VERSION,
1396 sizeof(struct dcesrv_context),
1397 sizeof(struct dcesrv_endpoint),
1398 sizeof(struct dcesrv_endpoint_server),
1399 sizeof(struct dcesrv_interface),
1400 sizeof(struct dcesrv_if_list),
1401 sizeof(struct dcesrv_connection),
1402 sizeof(struct dcesrv_call_state),
1403 sizeof(struct dcesrv_auth),
1404 sizeof(struct dcesrv_handle)
1407 return &critical_sizes;