s3:registry: add an extra check for dsize==0 to regdb_fetch_keys_internal()
[Samba/fernandojvsilva.git] / source4 / rpc_server / dcerpc_server.c
blob918646ff06cbf405c0c47d2df7fbec722c287262
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, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &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, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &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);
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, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
736 if (!NT_STATUS_IS_OK(status)) {
737 talloc_free(call->context);
738 call->context = NULL;
739 return status;
742 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
744 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
745 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
747 if (call->conn->call_list && call->conn->call_list->replies) {
748 if (call->conn->transport.report_output_data) {
749 call->conn->transport.report_output_data(call->conn);
753 return NT_STATUS_OK;
758 handle a auth3 request
760 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
762 /* handle the auth3 in the auth code */
763 if (!dcesrv_auth_auth3(call)) {
764 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
767 talloc_free(call);
769 /* we don't send a reply to a auth3 request, except by a
770 fault */
771 return NT_STATUS_OK;
776 handle a bind request
778 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
780 uint32_t if_version, transfer_syntax_version;
781 struct dcesrv_connection_context *context;
782 const struct dcesrv_interface *iface;
783 struct GUID uuid, *transfer_syntax_uuid;
784 NTSTATUS status;
786 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
787 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
789 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
790 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
791 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
792 ndr_transfer_syntax.if_version != transfer_syntax_version) {
793 /* we only do NDR encoded dcerpc */
794 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
797 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
798 if (iface == NULL) {
799 char *uuid_str = GUID_string(call, &uuid);
800 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
801 talloc_free(uuid_str);
802 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
805 /* add this context to the list of available context_ids */
806 context = talloc(call->conn, struct dcesrv_connection_context);
807 if (context == NULL) {
808 return NT_STATUS_NO_MEMORY;
810 context->conn = call->conn;
811 context->iface = iface;
812 context->context_id = context_id;
813 if (call->pkt.u.alter.assoc_group_id != 0) {
814 context->assoc_group = dcesrv_assoc_group_reference(context,
815 call->conn->dce_ctx,
816 call->pkt.u.alter.assoc_group_id);
817 } else {
818 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
820 if (context->assoc_group == NULL) {
821 talloc_free(context);
822 call->context = NULL;
823 return NT_STATUS_NO_MEMORY;
825 context->private_data = NULL;
826 DLIST_ADD(call->conn->contexts, context);
827 call->context = context;
828 talloc_set_destructor(context, dcesrv_connection_context_destructor);
830 status = iface->bind(call, iface);
831 if (!NT_STATUS_IS_OK(status)) {
832 /* we don't want to trigger the iface->unbind() hook */
833 context->iface = NULL;
834 talloc_free(context);
835 call->context = NULL;
836 return status;
839 return NT_STATUS_OK;
844 handle a alter context request
846 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
848 struct ncacn_packet pkt;
849 struct data_blob_list_item *rep;
850 NTSTATUS status;
851 uint32_t result=0, reason=0;
852 uint32_t context_id;
854 /* handle any authentication that is being requested */
855 if (!dcesrv_auth_alter(call)) {
856 /* TODO: work out the right reject code */
857 result = DCERPC_BIND_PROVIDER_REJECT;
858 reason = DCERPC_BIND_REASON_ASYNTAX;
861 context_id = call->pkt.u.alter.ctx_list[0].context_id;
863 /* see if they are asking for a new interface */
864 if (result == 0) {
865 call->context = dcesrv_find_context(call->conn, context_id);
866 if (!call->context) {
867 status = dcesrv_alter_new_context(call, context_id);
868 if (!NT_STATUS_IS_OK(status)) {
869 result = DCERPC_BIND_PROVIDER_REJECT;
870 reason = DCERPC_BIND_REASON_ASYNTAX;
875 if (result == 0 &&
876 call->pkt.u.alter.assoc_group_id != 0 &&
877 lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
878 call->pkt.u.alter.assoc_group_id != call->context->assoc_group->id) {
879 DEBUG(0,(__location__ ": Failed attempt to use new assoc_group in alter context (0x%08x 0x%08x)\n",
880 call->context->assoc_group->id, call->pkt.u.alter.assoc_group_id));
881 /* TODO: can they ask for a new association group? */
882 result = DCERPC_BIND_PROVIDER_REJECT;
883 reason = DCERPC_BIND_REASON_ASYNTAX;
886 /* setup a alter_resp */
887 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
888 pkt.auth_length = 0;
889 pkt.call_id = call->pkt.call_id;
890 pkt.ptype = DCERPC_PKT_ALTER_RESP;
891 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
892 pkt.u.alter_resp.max_xmit_frag = 0x2000;
893 pkt.u.alter_resp.max_recv_frag = 0x2000;
894 if (result == 0) {
895 pkt.u.alter_resp.assoc_group_id = call->context->assoc_group->id;
896 } else {
897 pkt.u.alter_resp.assoc_group_id = 0;
899 pkt.u.alter_resp.num_results = 1;
900 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
901 if (!pkt.u.alter_resp.ctx_list) {
902 return NT_STATUS_NO_MEMORY;
904 pkt.u.alter_resp.ctx_list[0].result = result;
905 pkt.u.alter_resp.ctx_list[0].reason = reason;
906 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
907 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
908 pkt.u.alter_resp.secondary_address = "";
910 status = dcesrv_auth_alter_ack(call, &pkt);
911 if (!NT_STATUS_IS_OK(status)) {
912 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
913 || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
914 || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
915 || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
916 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
918 return dcesrv_fault(call, 0);
921 rep = talloc(call, struct data_blob_list_item);
922 if (!rep) {
923 return NT_STATUS_NO_MEMORY;
926 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
927 if (!NT_STATUS_IS_OK(status)) {
928 return status;
931 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
933 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
934 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
936 if (call->conn->call_list && call->conn->call_list->replies) {
937 if (call->conn->transport.report_output_data) {
938 call->conn->transport.report_output_data(call->conn);
942 return NT_STATUS_OK;
946 handle a dcerpc request packet
948 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
950 struct ndr_pull *pull;
951 NTSTATUS status;
952 struct dcesrv_connection_context *context;
954 /* if authenticated, and the mech we use can't do async replies, don't use them... */
955 if (call->conn->auth_state.gensec_security &&
956 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
957 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
960 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
961 if (context == NULL) {
962 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
965 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call,
966 lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
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, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
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;
1114 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1116 if (!conn->transport.get_my_addr) {
1117 return NULL;
1120 return conn->transport.get_my_addr(conn, mem_ctx);
1123 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1125 if (!conn->transport.get_peer_addr) {
1126 return NULL;
1129 return conn->transport.get_peer_addr(conn, mem_ctx);
1134 remove the call from the right list when freed
1136 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1138 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1139 return 0;
1143 process some input to a dcerpc endpoint server.
1145 NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
1146 struct ncacn_packet *pkt,
1147 DATA_BLOB blob)
1149 NTSTATUS status;
1150 struct dcesrv_call_state *call;
1152 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1153 if (!call) {
1154 data_blob_free(&blob);
1155 talloc_free(pkt);
1156 return NT_STATUS_NO_MEMORY;
1158 call->conn = dce_conn;
1159 call->event_ctx = dce_conn->event_ctx;
1160 call->msg_ctx = dce_conn->msg_ctx;
1161 call->state_flags = call->conn->state_flags;
1162 call->time = timeval_current();
1163 call->list = DCESRV_LIST_NONE;
1165 talloc_steal(call, pkt);
1166 talloc_steal(call, blob.data);
1167 call->pkt = *pkt;
1169 talloc_set_destructor(call, dcesrv_call_dequeue);
1171 /* we have to check the signing here, before combining the
1172 pdus */
1173 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1174 !dcesrv_auth_request(call, &blob)) {
1175 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1178 /* see if this is a continued packet */
1179 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1180 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1181 struct dcesrv_call_state *call2 = call;
1182 uint32_t alloc_size;
1184 /* we only allow fragmented requests, no other packet types */
1185 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1186 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1189 /* this is a continuation of an existing call - find the call then
1190 tack it on the end */
1191 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1192 if (!call) {
1193 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1196 if (call->pkt.ptype != call2->pkt.ptype) {
1197 /* trying to play silly buggers are we? */
1198 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1201 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1202 call2->pkt.u.request.stub_and_verifier.length;
1203 if (call->pkt.u.request.alloc_hint > alloc_size) {
1204 alloc_size = call->pkt.u.request.alloc_hint;
1207 call->pkt.u.request.stub_and_verifier.data =
1208 talloc_realloc(call,
1209 call->pkt.u.request.stub_and_verifier.data,
1210 uint8_t, alloc_size);
1211 if (!call->pkt.u.request.stub_and_verifier.data) {
1212 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1214 memcpy(call->pkt.u.request.stub_and_verifier.data +
1215 call->pkt.u.request.stub_and_verifier.length,
1216 call2->pkt.u.request.stub_and_verifier.data,
1217 call2->pkt.u.request.stub_and_verifier.length);
1218 call->pkt.u.request.stub_and_verifier.length +=
1219 call2->pkt.u.request.stub_and_verifier.length;
1221 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1223 talloc_free(call2);
1226 /* this may not be the last pdu in the chain - if its isn't then
1227 just put it on the incoming_fragmented_call_list and wait for the rest */
1228 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1229 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1230 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1231 return NT_STATUS_OK;
1234 /* This removes any fragments we may have had stashed away */
1235 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1237 switch (call->pkt.ptype) {
1238 case DCERPC_PKT_BIND:
1239 status = dcesrv_bind(call);
1240 break;
1241 case DCERPC_PKT_AUTH3:
1242 status = dcesrv_auth3(call);
1243 break;
1244 case DCERPC_PKT_ALTER:
1245 status = dcesrv_alter(call);
1246 break;
1247 case DCERPC_PKT_REQUEST:
1248 status = dcesrv_request(call);
1249 break;
1250 default:
1251 status = NT_STATUS_INVALID_PARAMETER;
1252 break;
1255 /* if we are going to be sending a reply then add
1256 it to the list of pending calls. We add it to the end to keep the call
1257 list in the order we will answer */
1258 if (!NT_STATUS_IS_OK(status)) {
1259 talloc_free(call);
1262 return status;
1265 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1266 struct loadparm_context *lp_ctx,
1267 const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1269 NTSTATUS status;
1270 struct dcesrv_context *dce_ctx;
1271 int i;
1273 if (!endpoint_servers) {
1274 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1275 return NT_STATUS_INTERNAL_ERROR;
1278 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1279 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1280 dce_ctx->endpoint_list = NULL;
1281 dce_ctx->lp_ctx = lp_ctx;
1282 dce_ctx->assoc_groups_idr = idr_init(dce_ctx);
1283 NT_STATUS_HAVE_NO_MEMORY(dce_ctx->assoc_groups_idr);
1285 for (i=0;endpoint_servers[i];i++) {
1286 const struct dcesrv_endpoint_server *ep_server;
1288 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1289 if (!ep_server) {
1290 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1291 return NT_STATUS_INTERNAL_ERROR;
1294 status = ep_server->init_server(dce_ctx, ep_server);
1295 if (!NT_STATUS_IS_OK(status)) {
1296 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1297 nt_errstr(status)));
1298 return status;
1302 *_dce_ctx = dce_ctx;
1303 return NT_STATUS_OK;
1306 /* the list of currently registered DCERPC endpoint servers.
1308 static struct ep_server {
1309 struct dcesrv_endpoint_server *ep_server;
1310 } *ep_servers = NULL;
1311 static int num_ep_servers;
1314 register a DCERPC endpoint server.
1316 The 'name' can be later used by other backends to find the operations
1317 structure for this backend.
1319 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1321 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1323 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1325 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1326 /* its already registered! */
1327 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1328 ep_server->name));
1329 return NT_STATUS_OBJECT_NAME_COLLISION;
1332 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1333 if (!ep_servers) {
1334 smb_panic("out of memory in dcerpc_register");
1337 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1338 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1340 num_ep_servers++;
1342 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1343 ep_server->name));
1345 return NT_STATUS_OK;
1349 return the operations structure for a named backend of the specified type
1351 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1353 int i;
1355 for (i=0;i<num_ep_servers;i++) {
1356 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1357 return ep_servers[i].ep_server;
1361 return NULL;
1364 void dcerpc_server_init(struct loadparm_context *lp_ctx)
1366 static bool initialized;
1367 extern NTSTATUS dcerpc_server_wkssvc_init(void);
1368 extern NTSTATUS dcerpc_server_drsuapi_init(void);
1369 extern NTSTATUS dcerpc_server_winreg_init(void);
1370 extern NTSTATUS dcerpc_server_spoolss_init(void);
1371 extern NTSTATUS dcerpc_server_epmapper_init(void);
1372 extern NTSTATUS dcerpc_server_srvsvc_init(void);
1373 extern NTSTATUS dcerpc_server_netlogon_init(void);
1374 extern NTSTATUS dcerpc_server_rpcecho_init(void);
1375 extern NTSTATUS dcerpc_server_unixinfo_init(void);
1376 extern NTSTATUS dcerpc_server_samr_init(void);
1377 extern NTSTATUS dcerpc_server_remote_init(void);
1378 extern NTSTATUS dcerpc_server_lsa_init(void);
1379 extern NTSTATUS dcerpc_server_browser_init(void);
1380 init_module_fn static_init[] = { STATIC_dcerpc_server_MODULES };
1381 init_module_fn *shared_init;
1383 if (initialized) {
1384 return;
1386 initialized = true;
1388 shared_init = load_samba_modules(NULL, lp_ctx, "dcerpc_server");
1390 run_init_functions(static_init);
1391 run_init_functions(shared_init);
1393 talloc_free(shared_init);
1397 return the DCERPC module version, and the size of some critical types
1398 This can be used by endpoint server modules to either detect compilation errors, or provide
1399 multiple implementations for different smbd compilation options in one module
1401 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1403 static const struct dcesrv_critical_sizes critical_sizes = {
1404 DCERPC_MODULE_VERSION,
1405 sizeof(struct dcesrv_context),
1406 sizeof(struct dcesrv_endpoint),
1407 sizeof(struct dcesrv_endpoint_server),
1408 sizeof(struct dcesrv_interface),
1409 sizeof(struct dcesrv_if_list),
1410 sizeof(struct dcesrv_connection),
1411 sizeof(struct dcesrv_call_state),
1412 sizeof(struct dcesrv_auth),
1413 sizeof(struct dcesrv_handle)
1416 return &critical_sizes;