replace/waf: add rt to deps at this place
[Samba/gebeck_regimport.git] / source4 / rpc_server / dcerpc_server.c
blob9103923b3e99226d481e0a3e29213c966e6b4c08
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 = lpcfg_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, lpcfg_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, lpcfg_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 lpcfg_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 lpcfg_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, lpcfg_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 lpcfg_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, lpcfg_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 if (call->fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
982 /* we got an unknown call */
983 DEBUG(3,(__location__ ": Unknown RPC call %u on %s\n",
984 call->pkt.u.request.opnum, context->iface->name));
985 dump_data(3, pull->data, pull->data_size);
987 return dcesrv_fault(call, call->fault_code);
990 if (pull->offset != pull->data_size) {
991 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
992 pull->data_size - pull->offset));
993 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
996 /* call the dispatch function */
997 status = context->iface->dispatch(call, call, call->r);
998 if (!NT_STATUS_IS_OK(status)) {
999 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
1000 context->iface->name,
1001 call->pkt.u.request.opnum,
1002 dcerpc_errstr(pull, call->fault_code)));
1003 return dcesrv_fault(call, call->fault_code);
1006 /* add the call to the pending list */
1007 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
1009 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
1010 return NT_STATUS_OK;
1013 return dcesrv_reply(call);
1016 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
1018 struct ndr_push *push;
1019 NTSTATUS status;
1020 DATA_BLOB stub;
1021 uint32_t total_length, chunk_size;
1022 struct dcesrv_connection_context *context = call->context;
1023 size_t sig_size = 0;
1025 /* call the reply function */
1026 status = context->iface->reply(call, call, call->r);
1027 if (!NT_STATUS_IS_OK(status)) {
1028 return dcesrv_fault(call, call->fault_code);
1031 /* form the reply NDR */
1032 push = ndr_push_init_ctx(call);
1033 NT_STATUS_HAVE_NO_MEMORY(push);
1035 /* carry over the pointer count to the reply in case we are
1036 using full pointer. See NDR specification for full
1037 pointers */
1038 push->ptr_count = call->ndr_pull->ptr_count;
1040 if (lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
1041 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1044 status = context->iface->ndr_push(call, call, push, call->r);
1045 if (!NT_STATUS_IS_OK(status)) {
1046 return dcesrv_fault(call, call->fault_code);
1049 stub = ndr_push_blob(push);
1051 total_length = stub.length;
1053 /* we can write a full max_recv_frag size, minus the dcerpc
1054 request header size */
1055 chunk_size = call->conn->cli_max_recv_frag;
1056 chunk_size -= DCERPC_REQUEST_LENGTH;
1057 if (call->conn->auth_state.auth_info &&
1058 call->conn->auth_state.gensec_security) {
1059 sig_size = gensec_sig_size(call->conn->auth_state.gensec_security,
1060 call->conn->cli_max_recv_frag);
1061 if (sig_size) {
1062 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1063 chunk_size -= sig_size;
1066 chunk_size -= (chunk_size % 16);
1068 do {
1069 uint32_t length;
1070 struct data_blob_list_item *rep;
1071 struct ncacn_packet pkt;
1073 rep = talloc(call, struct data_blob_list_item);
1074 NT_STATUS_HAVE_NO_MEMORY(rep);
1076 length = MIN(chunk_size, stub.length);
1078 /* form the dcerpc response packet */
1079 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
1080 pkt.auth_length = 0;
1081 pkt.call_id = call->pkt.call_id;
1082 pkt.ptype = DCERPC_PKT_RESPONSE;
1083 pkt.pfc_flags = 0;
1084 if (stub.length == total_length) {
1085 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1087 if (length == stub.length) {
1088 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1090 pkt.u.response.alloc_hint = stub.length;
1091 pkt.u.response.context_id = call->pkt.u.request.context_id;
1092 pkt.u.response.cancel_count = 0;
1093 pkt.u.response.stub_and_verifier.data = stub.data;
1094 pkt.u.response.stub_and_verifier.length = length;
1096 if (!dcesrv_auth_response(call, &rep->blob, sig_size, &pkt)) {
1097 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
1100 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
1102 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
1104 stub.data += length;
1105 stub.length -= length;
1106 } while (stub.length != 0);
1108 /* move the call from the pending to the finished calls list */
1109 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
1111 if (call->conn->call_list && call->conn->call_list->replies) {
1112 if (call->conn->transport.report_output_data) {
1113 call->conn->transport.report_output_data(call->conn);
1117 return NT_STATUS_OK;
1121 remove the call from the right list when freed
1123 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1125 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1126 return 0;
1129 _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_local_address(struct dcesrv_connection *conn)
1131 return conn->local_address;
1134 _PUBLIC_ const struct tsocket_address *dcesrv_connection_get_remote_address(struct dcesrv_connection *conn)
1136 return conn->remote_address;
1140 process some input to a dcerpc endpoint server.
1142 NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
1143 struct ncacn_packet *pkt,
1144 DATA_BLOB blob)
1146 NTSTATUS status;
1147 struct dcesrv_call_state *call;
1149 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1150 if (!call) {
1151 data_blob_free(&blob);
1152 talloc_free(pkt);
1153 return NT_STATUS_NO_MEMORY;
1155 call->conn = dce_conn;
1156 call->event_ctx = dce_conn->event_ctx;
1157 call->msg_ctx = dce_conn->msg_ctx;
1158 call->state_flags = call->conn->state_flags;
1159 call->time = timeval_current();
1160 call->list = DCESRV_LIST_NONE;
1162 talloc_steal(call, pkt);
1163 talloc_steal(call, blob.data);
1164 call->pkt = *pkt;
1166 talloc_set_destructor(call, dcesrv_call_dequeue);
1168 /* we have to check the signing here, before combining the
1169 pdus */
1170 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1171 !dcesrv_auth_request(call, &blob)) {
1172 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1175 /* see if this is a continued packet */
1176 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1177 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1178 struct dcesrv_call_state *call2 = call;
1179 uint32_t alloc_size;
1181 /* we only allow fragmented requests, no other packet types */
1182 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1183 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1186 /* this is a continuation of an existing call - find the call then
1187 tack it on the end */
1188 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1189 if (!call) {
1190 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1193 if (call->pkt.ptype != call2->pkt.ptype) {
1194 /* trying to play silly buggers are we? */
1195 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1198 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1199 call2->pkt.u.request.stub_and_verifier.length;
1200 if (call->pkt.u.request.alloc_hint > alloc_size) {
1201 alloc_size = call->pkt.u.request.alloc_hint;
1204 call->pkt.u.request.stub_and_verifier.data =
1205 talloc_realloc(call,
1206 call->pkt.u.request.stub_and_verifier.data,
1207 uint8_t, alloc_size);
1208 if (!call->pkt.u.request.stub_and_verifier.data) {
1209 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1211 memcpy(call->pkt.u.request.stub_and_verifier.data +
1212 call->pkt.u.request.stub_and_verifier.length,
1213 call2->pkt.u.request.stub_and_verifier.data,
1214 call2->pkt.u.request.stub_and_verifier.length);
1215 call->pkt.u.request.stub_and_verifier.length +=
1216 call2->pkt.u.request.stub_and_verifier.length;
1218 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1220 talloc_free(call2);
1223 /* this may not be the last pdu in the chain - if its isn't then
1224 just put it on the incoming_fragmented_call_list and wait for the rest */
1225 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1226 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1227 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1228 return NT_STATUS_OK;
1231 /* This removes any fragments we may have had stashed away */
1232 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1234 switch (call->pkt.ptype) {
1235 case DCERPC_PKT_BIND:
1236 status = dcesrv_bind(call);
1237 break;
1238 case DCERPC_PKT_AUTH3:
1239 status = dcesrv_auth3(call);
1240 break;
1241 case DCERPC_PKT_ALTER:
1242 status = dcesrv_alter(call);
1243 break;
1244 case DCERPC_PKT_REQUEST:
1245 status = dcesrv_request(call);
1246 break;
1247 default:
1248 status = NT_STATUS_INVALID_PARAMETER;
1249 break;
1252 /* if we are going to be sending a reply then add
1253 it to the list of pending calls. We add it to the end to keep the call
1254 list in the order we will answer */
1255 if (!NT_STATUS_IS_OK(status)) {
1256 talloc_free(call);
1259 return status;
1262 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1263 struct loadparm_context *lp_ctx,
1264 const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1266 NTSTATUS status;
1267 struct dcesrv_context *dce_ctx;
1268 int i;
1270 if (!endpoint_servers) {
1271 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1272 return NT_STATUS_INTERNAL_ERROR;
1275 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1276 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1277 dce_ctx->endpoint_list = NULL;
1278 dce_ctx->lp_ctx = lp_ctx;
1279 dce_ctx->assoc_groups_idr = idr_init(dce_ctx);
1280 NT_STATUS_HAVE_NO_MEMORY(dce_ctx->assoc_groups_idr);
1282 for (i=0;endpoint_servers[i];i++) {
1283 const struct dcesrv_endpoint_server *ep_server;
1285 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1286 if (!ep_server) {
1287 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1288 return NT_STATUS_INTERNAL_ERROR;
1291 status = ep_server->init_server(dce_ctx, ep_server);
1292 if (!NT_STATUS_IS_OK(status)) {
1293 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1294 nt_errstr(status)));
1295 return status;
1299 *_dce_ctx = dce_ctx;
1300 return NT_STATUS_OK;
1303 /* the list of currently registered DCERPC endpoint servers.
1305 static struct ep_server {
1306 struct dcesrv_endpoint_server *ep_server;
1307 } *ep_servers = NULL;
1308 static int num_ep_servers;
1311 register a DCERPC endpoint server.
1313 The 'name' can be later used by other backends to find the operations
1314 structure for this backend.
1316 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1318 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1320 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1322 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1323 /* its already registered! */
1324 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1325 ep_server->name));
1326 return NT_STATUS_OBJECT_NAME_COLLISION;
1329 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1330 if (!ep_servers) {
1331 smb_panic("out of memory in dcerpc_register");
1334 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1335 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1337 num_ep_servers++;
1339 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1340 ep_server->name));
1342 return NT_STATUS_OK;
1346 return the operations structure for a named backend of the specified type
1348 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1350 int i;
1352 for (i=0;i<num_ep_servers;i++) {
1353 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1354 return ep_servers[i].ep_server;
1358 return NULL;
1361 void dcerpc_server_init(struct loadparm_context *lp_ctx)
1363 static bool initialized;
1364 extern NTSTATUS dcerpc_server_wkssvc_init(void);
1365 extern NTSTATUS dcerpc_server_drsuapi_init(void);
1366 extern NTSTATUS dcerpc_server_winreg_init(void);
1367 extern NTSTATUS dcerpc_server_spoolss_init(void);
1368 extern NTSTATUS dcerpc_server_epmapper_init(void);
1369 extern NTSTATUS dcerpc_server_srvsvc_init(void);
1370 extern NTSTATUS dcerpc_server_netlogon_init(void);
1371 extern NTSTATUS dcerpc_server_rpcecho_init(void);
1372 extern NTSTATUS dcerpc_server_unixinfo_init(void);
1373 extern NTSTATUS dcerpc_server_samr_init(void);
1374 extern NTSTATUS dcerpc_server_remote_init(void);
1375 extern NTSTATUS dcerpc_server_lsa_init(void);
1376 extern NTSTATUS dcerpc_server_browser_init(void);
1377 init_module_fn static_init[] = { STATIC_dcerpc_server_MODULES };
1378 init_module_fn *shared_init;
1380 if (initialized) {
1381 return;
1383 initialized = true;
1385 shared_init = load_samba_modules(NULL, lp_ctx, "dcerpc_server");
1387 run_init_functions(static_init);
1388 run_init_functions(shared_init);
1390 talloc_free(shared_init);
1394 return the DCERPC module version, and the size of some critical types
1395 This can be used by endpoint server modules to either detect compilation errors, or provide
1396 multiple implementations for different smbd compilation options in one module
1398 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1400 static const struct dcesrv_critical_sizes critical_sizes = {
1401 DCERPC_MODULE_VERSION,
1402 sizeof(struct dcesrv_context),
1403 sizeof(struct dcesrv_endpoint),
1404 sizeof(struct dcesrv_endpoint_server),
1405 sizeof(struct dcesrv_interface),
1406 sizeof(struct dcesrv_if_list),
1407 sizeof(struct dcesrv_connection),
1408 sizeof(struct dcesrv_call_state),
1409 sizeof(struct dcesrv_auth),
1410 sizeof(struct dcesrv_handle)
1413 return &critical_sizes;