s4-netlogon: implement dcesrv_netr_DsRAddressToSitenamesExW
[Samba/aatanasov.git] / source4 / rpc_server / dcerpc_server.c
blobe055d1671b42ba2b5bf12db9dd8271089a36fb18
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 "librpc/gen_ndr/ndr_dcerpc.h"
25 #include "auth/auth.h"
26 #include "auth/gensec/gensec.h"
27 #include "../lib/util/dlinklist.h"
28 #include "rpc_server/dcerpc_server.h"
29 #include "rpc_server/dcerpc_server_proto.h"
30 #include "librpc/rpc/dcerpc_proto.h"
31 #include "lib/events/events.h"
32 #include "smbd/service_task.h"
33 #include "smbd/service_stream.h"
34 #include "smbd/service.h"
35 #include "system/filesys.h"
36 #include "libcli/security/security.h"
37 #include "param/param.h"
39 #define SAMBA_ASSOC_GROUP 0x12345678
41 extern const struct dcesrv_interface dcesrv_mgmt_interface;
44 see if two endpoints match
46 static bool endpoints_match(const struct dcerpc_binding *ep1,
47 const struct dcerpc_binding *ep2)
49 if (ep1->transport != ep2->transport) {
50 return false;
53 if (!ep1->endpoint || !ep2->endpoint) {
54 return ep1->endpoint == ep2->endpoint;
57 if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
58 return false;
60 return true;
64 find an endpoint in the dcesrv_context
66 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
67 const struct dcerpc_binding *ep_description)
69 struct dcesrv_endpoint *ep;
70 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
71 if (endpoints_match(ep->ep_description, ep_description)) {
72 return ep;
75 return NULL;
79 find a registered context_id from a bind or alter_context
81 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn,
82 uint32_t context_id)
84 struct dcesrv_connection_context *c;
85 for (c=conn->contexts;c;c=c->next) {
86 if (c->context_id == context_id) return c;
88 return NULL;
92 see if a uuid and if_version match to an interface
94 static bool interface_match(const struct dcesrv_interface *if1,
95 const struct dcesrv_interface *if2)
97 return (if1->syntax_id.if_version == if2->syntax_id.if_version &&
98 GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
102 find the interface operations on an endpoint
104 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
105 const struct dcesrv_interface *iface)
107 struct dcesrv_if_list *ifl;
108 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
109 if (interface_match(&(ifl->iface), iface)) {
110 return &(ifl->iface);
113 return NULL;
117 see if a uuid and if_version match to an interface
119 static bool interface_match_by_uuid(const struct dcesrv_interface *iface,
120 const struct GUID *uuid, uint32_t if_version)
122 return (iface->syntax_id.if_version == if_version &&
123 GUID_equal(&iface->syntax_id.uuid, uuid));
127 find the interface operations on an endpoint by uuid
129 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
130 const struct GUID *uuid, uint32_t if_version)
132 struct dcesrv_if_list *ifl;
133 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
134 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
135 return &(ifl->iface);
138 return NULL;
142 find the earlier parts of a fragmented call awaiting reassembily
144 static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
146 struct dcesrv_call_state *c;
147 for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
148 if (c->pkt.call_id == call_id) {
149 return c;
152 return NULL;
156 register an interface on an endpoint
158 _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
159 const char *ep_name,
160 const struct dcesrv_interface *iface,
161 const struct security_descriptor *sd)
163 struct dcesrv_endpoint *ep;
164 struct dcesrv_if_list *ifl;
165 struct dcerpc_binding *binding;
166 bool add_ep = false;
167 NTSTATUS status;
169 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
171 if (NT_STATUS_IS_ERR(status)) {
172 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
173 return status;
176 /* check if this endpoint exists
178 if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
179 ep = talloc(dce_ctx, struct dcesrv_endpoint);
180 if (!ep) {
181 return NT_STATUS_NO_MEMORY;
183 ZERO_STRUCTP(ep);
184 ep->ep_description = talloc_reference(ep, binding);
185 add_ep = true;
187 /* add mgmt interface */
188 ifl = talloc(dce_ctx, struct dcesrv_if_list);
189 if (!ifl) {
190 return NT_STATUS_NO_MEMORY;
193 memcpy(&(ifl->iface), &dcesrv_mgmt_interface,
194 sizeof(struct dcesrv_interface));
196 DLIST_ADD(ep->interface_list, ifl);
199 /* see if the interface is already registered on te endpoint */
200 if (find_interface(ep, iface)!=NULL) {
201 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
202 iface->name, ep_name));
203 return NT_STATUS_OBJECT_NAME_COLLISION;
206 /* talloc a new interface list element */
207 ifl = talloc(dce_ctx, struct dcesrv_if_list);
208 if (!ifl) {
209 return NT_STATUS_NO_MEMORY;
212 /* copy the given interface struct to the one on the endpoints interface list */
213 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
215 /* if we have a security descriptor given,
216 * we should see if we can set it up on the endpoint
218 if (sd != NULL) {
219 /* if there's currently no security descriptor given on the endpoint
220 * we try to set it
222 if (ep->sd == NULL) {
223 ep->sd = security_descriptor_copy(dce_ctx, sd);
226 /* if now there's no security descriptor given on the endpoint
227 * something goes wrong, either we failed to copy the security descriptor
228 * or there was already one on the endpoint
230 if (ep->sd != NULL) {
231 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
232 " on endpoint '%s'\n",
233 iface->name, ep_name));
234 if (add_ep) free(ep);
235 free(ifl);
236 return NT_STATUS_OBJECT_NAME_COLLISION;
240 /* finally add the interface on the endpoint */
241 DLIST_ADD(ep->interface_list, ifl);
243 /* if it's a new endpoint add it to the dcesrv_context */
244 if (add_ep) {
245 DLIST_ADD(dce_ctx->endpoint_list, ep);
248 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
249 iface->name, ep_name));
251 return NT_STATUS_OK;
254 NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
255 DATA_BLOB *session_key)
257 if (p->auth_state.session_info->session_key.length) {
258 *session_key = p->auth_state.session_info->session_key;
259 return NT_STATUS_OK;
261 return NT_STATUS_NO_USER_SESSION_KEY;
264 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
265 DATA_BLOB *session_key)
267 /* this took quite a few CPU cycles to find ... */
268 session_key->data = discard_const_p(uint8_t, "SystemLibraryDTC");
269 session_key->length = 16;
270 return NT_STATUS_OK;
274 fetch the user session key - may be default (above) or the SMB session key
276 The key is always truncated to 16 bytes
278 _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
279 DATA_BLOB *session_key)
281 NTSTATUS status = p->auth_state.session_key(p, session_key);
282 if (!NT_STATUS_IS_OK(status)) {
283 return status;
286 session_key->length = MIN(session_key->length, 16);
288 return NT_STATUS_OK;
292 connect to a dcerpc endpoint
294 _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
295 TALLOC_CTX *mem_ctx,
296 const struct dcesrv_endpoint *ep,
297 struct auth_session_info *session_info,
298 struct tevent_context *event_ctx,
299 struct messaging_context *msg_ctx,
300 struct server_id server_id,
301 uint32_t state_flags,
302 struct dcesrv_connection **_p)
304 struct dcesrv_connection *p;
306 if (!session_info) {
307 return NT_STATUS_ACCESS_DENIED;
310 p = talloc(mem_ctx, struct dcesrv_connection);
311 NT_STATUS_HAVE_NO_MEMORY(p);
313 if (!talloc_reference(p, session_info)) {
314 talloc_free(p);
315 return NT_STATUS_NO_MEMORY;
318 p->dce_ctx = dce_ctx;
319 p->endpoint = ep;
320 p->contexts = NULL;
321 p->call_list = NULL;
322 p->packet_log_dir = lp_lockdir(dce_ctx->lp_ctx);
323 p->incoming_fragmented_call_list = NULL;
324 p->pending_call_list = NULL;
325 p->cli_max_recv_frag = 0;
326 p->partial_input = data_blob(NULL, 0);
327 p->auth_state.auth_info = NULL;
328 p->auth_state.gensec_security = NULL;
329 p->auth_state.session_info = session_info;
330 p->auth_state.session_key = dcesrv_generic_session_key;
331 p->event_ctx = event_ctx;
332 p->msg_ctx = msg_ctx;
333 p->server_id = server_id;
334 p->processing = false;
335 p->state_flags = state_flags;
336 ZERO_STRUCT(p->transport);
338 *_p = p;
339 return NT_STATUS_OK;
342 static void dcesrv_init_hdr(struct ncacn_packet *pkt, bool bigendian)
344 pkt->rpc_vers = 5;
345 pkt->rpc_vers_minor = 0;
346 if (bigendian) {
347 pkt->drep[0] = 0;
348 } else {
349 pkt->drep[0] = DCERPC_DREP_LE;
351 pkt->drep[1] = 0;
352 pkt->drep[2] = 0;
353 pkt->drep[3] = 0;
357 move a call from an existing linked list to the specified list. This
358 prevents bugs where we forget to remove the call from a previous
359 list when moving it.
361 static void dcesrv_call_set_list(struct dcesrv_call_state *call,
362 enum dcesrv_call_list list)
364 switch (call->list) {
365 case DCESRV_LIST_NONE:
366 break;
367 case DCESRV_LIST_CALL_LIST:
368 DLIST_REMOVE(call->conn->call_list, call);
369 break;
370 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
371 DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
372 break;
373 case DCESRV_LIST_PENDING_CALL_LIST:
374 DLIST_REMOVE(call->conn->pending_call_list, call);
375 break;
377 call->list = list;
378 switch (list) {
379 case DCESRV_LIST_NONE:
380 break;
381 case DCESRV_LIST_CALL_LIST:
382 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
383 break;
384 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
385 DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
386 break;
387 case DCESRV_LIST_PENDING_CALL_LIST:
388 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
389 break;
394 return a dcerpc fault
396 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
398 struct ncacn_packet pkt;
399 struct data_blob_list_item *rep;
400 uint8_t zeros[4];
401 NTSTATUS status;
403 /* setup a bind_ack */
404 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
405 pkt.auth_length = 0;
406 pkt.call_id = call->pkt.call_id;
407 pkt.ptype = DCERPC_PKT_FAULT;
408 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
409 pkt.u.fault.alloc_hint = 0;
410 pkt.u.fault.context_id = 0;
411 pkt.u.fault.cancel_count = 0;
412 pkt.u.fault.status = fault_code;
414 ZERO_STRUCT(zeros);
415 pkt.u.fault._pad = data_blob_const(zeros, sizeof(zeros));
417 rep = talloc(call, struct data_blob_list_item);
418 if (!rep) {
419 return NT_STATUS_NO_MEMORY;
422 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
423 if (!NT_STATUS_IS_OK(status)) {
424 return status;
427 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
429 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
430 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
432 if (call->conn->call_list && call->conn->call_list->replies) {
433 if (call->conn->transport.report_output_data) {
434 call->conn->transport.report_output_data(call->conn);
438 return NT_STATUS_OK;
443 return a dcerpc bind_nak
445 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
447 struct ncacn_packet pkt;
448 struct data_blob_list_item *rep;
449 NTSTATUS status;
451 /* setup a bind_nak */
452 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
453 pkt.auth_length = 0;
454 pkt.call_id = call->pkt.call_id;
455 pkt.ptype = DCERPC_PKT_BIND_NAK;
456 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
457 pkt.u.bind_nak.reject_reason = reason;
458 if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
459 pkt.u.bind_nak.versions.v.num_versions = 0;
462 rep = talloc(call, struct data_blob_list_item);
463 if (!rep) {
464 return NT_STATUS_NO_MEMORY;
467 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
468 if (!NT_STATUS_IS_OK(status)) {
469 return status;
472 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
474 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
475 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
477 if (call->conn->call_list && call->conn->call_list->replies) {
478 if (call->conn->transport.report_output_data) {
479 call->conn->transport.report_output_data(call->conn);
483 return NT_STATUS_OK;
486 static int dcesrv_connection_context_destructor(struct dcesrv_connection_context *c)
488 DLIST_REMOVE(c->conn->contexts, c);
490 if (c->iface) {
491 c->iface->unbind(c, c->iface);
494 return 0;
498 handle a bind request
500 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
502 uint32_t if_version, transfer_syntax_version;
503 struct GUID uuid, *transfer_syntax_uuid;
504 struct ncacn_packet pkt;
505 struct data_blob_list_item *rep;
506 NTSTATUS status;
507 uint32_t result=0, reason=0;
508 uint32_t context_id;
509 const struct dcesrv_interface *iface;
510 uint32_t extra_flags = 0;
513 * Association groups allow policy handles to be shared across
514 * multiple client connections. We don't implement this yet.
516 * So we just allow 0 if the client wants to create a new
517 * association group.
519 * And we allow the 0x12345678 value, we give away as
520 * assoc_group_id back to the clients
522 if (call->pkt.u.bind.assoc_group_id != 0 &&
523 lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
524 call->pkt.u.bind.assoc_group_id != SAMBA_ASSOC_GROUP) {
525 return dcesrv_bind_nak(call, 0);
528 if (call->pkt.u.bind.num_contexts < 1 ||
529 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
530 return dcesrv_bind_nak(call, 0);
533 context_id = call->pkt.u.bind.ctx_list[0].context_id;
535 /* you can't bind twice on one context */
536 if (dcesrv_find_context(call->conn, context_id) != NULL) {
537 return dcesrv_bind_nak(call, 0);
540 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
541 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
543 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
544 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
545 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
546 ndr_transfer_syntax.if_version != transfer_syntax_version) {
547 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
548 /* we only do NDR encoded dcerpc */
549 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
550 talloc_free(uuid_str);
551 return dcesrv_bind_nak(call, 0);
554 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
555 if (iface == NULL) {
556 char *uuid_str = GUID_string(call, &uuid);
557 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
558 talloc_free(uuid_str);
560 /* we don't know about that interface */
561 result = DCERPC_BIND_PROVIDER_REJECT;
562 reason = DCERPC_BIND_REASON_ASYNTAX;
565 if (iface) {
566 /* add this context to the list of available context_ids */
567 struct dcesrv_connection_context *context = talloc(call->conn,
568 struct dcesrv_connection_context);
569 if (context == NULL) {
570 return dcesrv_bind_nak(call, 0);
572 context->conn = call->conn;
573 context->iface = iface;
574 context->context_id = context_id;
576 * we need to send a non zero assoc_group_id here to make longhorn happy,
577 * it also matches samba3
579 context->assoc_group_id = SAMBA_ASSOC_GROUP;
580 context->private_data = NULL;
581 context->handles = NULL;
582 DLIST_ADD(call->conn->contexts, context);
583 call->context = context;
584 talloc_set_destructor(context, dcesrv_connection_context_destructor);
586 status = iface->bind(call, iface);
587 if (!NT_STATUS_IS_OK(status)) {
588 char *uuid_str = GUID_string(call, &uuid);
589 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
590 uuid_str, if_version, nt_errstr(status)));
591 talloc_free(uuid_str);
592 /* we don't want to trigger the iface->unbind() hook */
593 context->iface = NULL;
594 talloc_free(call->context);
595 call->context = NULL;
596 return dcesrv_bind_nak(call, 0);
600 if (call->conn->cli_max_recv_frag == 0) {
601 call->conn->cli_max_recv_frag = MIN(0x2000, call->pkt.u.bind.max_recv_frag);
604 if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) &&
605 lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","header signing", false)) {
606 call->conn->state_flags |= DCESRV_CALL_STATE_FLAG_HEADER_SIGNING;
607 extra_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
610 /* handle any authentication that is being requested */
611 if (!dcesrv_auth_bind(call)) {
612 talloc_free(call->context);
613 call->context = NULL;
614 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
617 /* setup a bind_ack */
618 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
619 pkt.auth_length = 0;
620 pkt.call_id = call->pkt.call_id;
621 pkt.ptype = DCERPC_PKT_BIND_ACK;
622 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
623 pkt.u.bind_ack.max_xmit_frag = call->conn->cli_max_recv_frag;
624 pkt.u.bind_ack.max_recv_frag = 0x2000;
627 make it possible for iface->bind() to specify the assoc_group_id
628 This helps the openchange mapiproxy plugin to work correctly.
630 metze
632 if (call->context) {
633 pkt.u.bind_ack.assoc_group_id = call->context->assoc_group_id;
634 } else {
635 /* we better pick something - this chosen so as to send a non zero assoc_group_id (matching windows), it also matches samba3 */
636 pkt.u.bind_ack.assoc_group_id = SAMBA_ASSOC_GROUP;
639 if (iface) {
640 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
641 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
642 } else {
643 pkt.u.bind_ack.secondary_address = "";
645 pkt.u.bind_ack.num_results = 1;
646 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
647 if (!pkt.u.bind_ack.ctx_list) {
648 talloc_free(call->context);
649 call->context = NULL;
650 return NT_STATUS_NO_MEMORY;
652 pkt.u.bind_ack.ctx_list[0].result = result;
653 pkt.u.bind_ack.ctx_list[0].reason = reason;
654 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
655 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
657 status = dcesrv_auth_bind_ack(call, &pkt);
658 if (!NT_STATUS_IS_OK(status)) {
659 talloc_free(call->context);
660 call->context = NULL;
661 return dcesrv_bind_nak(call, 0);
664 rep = talloc(call, struct data_blob_list_item);
665 if (!rep) {
666 talloc_free(call->context);
667 call->context = NULL;
668 return NT_STATUS_NO_MEMORY;
671 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
672 if (!NT_STATUS_IS_OK(status)) {
673 talloc_free(call->context);
674 call->context = NULL;
675 return status;
678 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
680 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
681 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
683 if (call->conn->call_list && call->conn->call_list->replies) {
684 if (call->conn->transport.report_output_data) {
685 call->conn->transport.report_output_data(call->conn);
689 return NT_STATUS_OK;
694 handle a auth3 request
696 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
698 /* handle the auth3 in the auth code */
699 if (!dcesrv_auth_auth3(call)) {
700 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
703 talloc_free(call);
705 /* we don't send a reply to a auth3 request, except by a
706 fault */
707 return NT_STATUS_OK;
712 handle a bind request
714 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
716 uint32_t if_version, transfer_syntax_version;
717 struct dcesrv_connection_context *context;
718 const struct dcesrv_interface *iface;
719 struct GUID uuid, *transfer_syntax_uuid;
720 NTSTATUS status;
722 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
723 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
725 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
726 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
727 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
728 ndr_transfer_syntax.if_version != transfer_syntax_version) {
729 /* we only do NDR encoded dcerpc */
730 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
733 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
734 if (iface == NULL) {
735 char *uuid_str = GUID_string(call, &uuid);
736 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
737 talloc_free(uuid_str);
738 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
741 /* add this context to the list of available context_ids */
742 context = talloc(call->conn, struct dcesrv_connection_context);
743 if (context == NULL) {
744 return NT_STATUS_NO_MEMORY;
746 context->conn = call->conn;
747 context->iface = iface;
748 context->context_id = context_id;
749 context->assoc_group_id = SAMBA_ASSOC_GROUP;
750 context->private_data = NULL;
751 context->handles = NULL;
752 DLIST_ADD(call->conn->contexts, context);
753 call->context = context;
754 talloc_set_destructor(context, dcesrv_connection_context_destructor);
756 status = iface->bind(call, iface);
757 if (!NT_STATUS_IS_OK(status)) {
758 /* we don't want to trigger the iface->unbind() hook */
759 context->iface = NULL;
760 talloc_free(context);
761 call->context = NULL;
762 return status;
765 return NT_STATUS_OK;
770 handle a alter context request
772 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
774 struct ncacn_packet pkt;
775 struct data_blob_list_item *rep;
776 NTSTATUS status;
777 uint32_t result=0, reason=0;
778 uint32_t context_id;
780 /* handle any authentication that is being requested */
781 if (!dcesrv_auth_alter(call)) {
782 /* TODO: work out the right reject code */
783 result = DCERPC_BIND_PROVIDER_REJECT;
784 reason = DCERPC_BIND_REASON_ASYNTAX;
787 context_id = call->pkt.u.alter.ctx_list[0].context_id;
789 /* see if they are asking for a new interface */
790 if (result == 0) {
791 call->context = dcesrv_find_context(call->conn, context_id);
792 if (!call->context) {
793 status = dcesrv_alter_new_context(call, context_id);
794 if (!NT_STATUS_IS_OK(status)) {
795 result = DCERPC_BIND_PROVIDER_REJECT;
796 reason = DCERPC_BIND_REASON_ASYNTAX;
801 if (result == 0 &&
802 call->pkt.u.alter.assoc_group_id != 0 &&
803 lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
804 call->pkt.u.alter.assoc_group_id != call->context->assoc_group_id) {
805 /* TODO: work out what to return here */
806 result = DCERPC_BIND_PROVIDER_REJECT;
807 reason = DCERPC_BIND_REASON_ASYNTAX;
810 /* setup a alter_resp */
811 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
812 pkt.auth_length = 0;
813 pkt.call_id = call->pkt.call_id;
814 pkt.ptype = DCERPC_PKT_ALTER_RESP;
815 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
816 pkt.u.alter_resp.max_xmit_frag = 0x2000;
817 pkt.u.alter_resp.max_recv_frag = 0x2000;
818 if (result == 0) {
819 pkt.u.alter_resp.assoc_group_id = call->context->assoc_group_id;
820 } else {
821 pkt.u.alter_resp.assoc_group_id = 0;
823 pkt.u.alter_resp.num_results = 1;
824 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
825 if (!pkt.u.alter_resp.ctx_list) {
826 return NT_STATUS_NO_MEMORY;
828 pkt.u.alter_resp.ctx_list[0].result = result;
829 pkt.u.alter_resp.ctx_list[0].reason = reason;
830 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
831 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
832 pkt.u.alter_resp.secondary_address = "";
834 status = dcesrv_auth_alter_ack(call, &pkt);
835 if (!NT_STATUS_IS_OK(status)) {
836 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
837 || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
838 || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
839 || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
840 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
842 return dcesrv_fault(call, 0);
845 rep = talloc(call, struct data_blob_list_item);
846 if (!rep) {
847 return NT_STATUS_NO_MEMORY;
850 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
851 if (!NT_STATUS_IS_OK(status)) {
852 return status;
855 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
857 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
858 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
860 if (call->conn->call_list && call->conn->call_list->replies) {
861 if (call->conn->transport.report_output_data) {
862 call->conn->transport.report_output_data(call->conn);
866 return NT_STATUS_OK;
870 handle a dcerpc request packet
872 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
874 struct ndr_pull *pull;
875 NTSTATUS status;
876 struct dcesrv_connection_context *context;
878 /* if authenticated, and the mech we use can't do async replies, don't use them... */
879 if (call->conn->auth_state.gensec_security &&
880 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
881 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
884 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
885 if (context == NULL) {
886 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
889 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call,
890 lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
891 NT_STATUS_HAVE_NO_MEMORY(pull);
893 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
895 call->context = context;
896 call->ndr_pull = pull;
898 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
899 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
902 /* unravel the NDR for the packet */
903 status = context->iface->ndr_pull(call, call, pull, &call->r);
904 if (!NT_STATUS_IS_OK(status)) {
905 return dcesrv_fault(call, call->fault_code);
908 if (pull->offset != pull->data_size) {
909 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
910 pull->data_size - pull->offset));
911 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
914 /* call the dispatch function */
915 status = context->iface->dispatch(call, call, call->r);
916 if (!NT_STATUS_IS_OK(status)) {
917 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
918 context->iface->name,
919 call->pkt.u.request.opnum,
920 dcerpc_errstr(pull, call->fault_code)));
921 return dcesrv_fault(call, call->fault_code);
924 /* add the call to the pending list */
925 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
927 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
928 return NT_STATUS_OK;
931 return dcesrv_reply(call);
934 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
936 struct ndr_push *push;
937 NTSTATUS status;
938 DATA_BLOB stub;
939 uint32_t total_length, chunk_size;
940 struct dcesrv_connection_context *context = call->context;
941 size_t sig_size = 0;
943 /* call the reply function */
944 status = context->iface->reply(call, call, call->r);
945 if (!NT_STATUS_IS_OK(status)) {
946 return dcesrv_fault(call, call->fault_code);
949 /* form the reply NDR */
950 push = ndr_push_init_ctx(call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
951 NT_STATUS_HAVE_NO_MEMORY(push);
953 /* carry over the pointer count to the reply in case we are
954 using full pointer. See NDR specification for full
955 pointers */
956 push->ptr_count = call->ndr_pull->ptr_count;
958 if (lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
959 push->flags |= LIBNDR_FLAG_BIGENDIAN;
962 status = context->iface->ndr_push(call, call, push, call->r);
963 if (!NT_STATUS_IS_OK(status)) {
964 return dcesrv_fault(call, call->fault_code);
967 stub = ndr_push_blob(push);
969 total_length = stub.length;
971 /* we can write a full max_recv_frag size, minus the dcerpc
972 request header size */
973 chunk_size = call->conn->cli_max_recv_frag;
974 chunk_size -= DCERPC_REQUEST_LENGTH;
975 if (call->conn->auth_state.auth_info &&
976 call->conn->auth_state.gensec_security) {
977 sig_size = gensec_sig_size(call->conn->auth_state.gensec_security,
978 call->conn->cli_max_recv_frag);
979 if (sig_size) {
980 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
981 chunk_size -= sig_size;
984 chunk_size -= (chunk_size % 16);
986 do {
987 uint32_t length;
988 struct data_blob_list_item *rep;
989 struct ncacn_packet pkt;
991 rep = talloc(call, struct data_blob_list_item);
992 NT_STATUS_HAVE_NO_MEMORY(rep);
994 length = MIN(chunk_size, stub.length);
996 /* form the dcerpc response packet */
997 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
998 pkt.auth_length = 0;
999 pkt.call_id = call->pkt.call_id;
1000 pkt.ptype = DCERPC_PKT_RESPONSE;
1001 pkt.pfc_flags = 0;
1002 if (stub.length == total_length) {
1003 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1005 if (length == stub.length) {
1006 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1008 pkt.u.response.alloc_hint = stub.length;
1009 pkt.u.response.context_id = call->pkt.u.request.context_id;
1010 pkt.u.response.cancel_count = 0;
1011 pkt.u.response.stub_and_verifier.data = stub.data;
1012 pkt.u.response.stub_and_verifier.length = length;
1014 if (!dcesrv_auth_response(call, &rep->blob, sig_size, &pkt)) {
1015 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
1018 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
1020 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
1022 stub.data += length;
1023 stub.length -= length;
1024 } while (stub.length != 0);
1026 /* move the call from the pending to the finished calls list */
1027 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
1029 if (call->conn->call_list && call->conn->call_list->replies) {
1030 if (call->conn->transport.report_output_data) {
1031 call->conn->transport.report_output_data(call->conn);
1035 return NT_STATUS_OK;
1038 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1040 if (!conn->transport.get_my_addr) {
1041 return NULL;
1044 return conn->transport.get_my_addr(conn, mem_ctx);
1047 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1049 if (!conn->transport.get_peer_addr) {
1050 return NULL;
1053 return conn->transport.get_peer_addr(conn, mem_ctx);
1057 work out if we have a full packet yet
1059 static bool dce_full_packet(const DATA_BLOB *data)
1061 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
1062 return false;
1064 if (dcerpc_get_frag_length(data) > data->length) {
1065 return false;
1067 return true;
1071 we might have consumed only part of our input - advance past that part
1073 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
1075 DATA_BLOB blob;
1077 if (dce_conn->partial_input.length == offset) {
1078 data_blob_free(&dce_conn->partial_input);
1079 return;
1082 blob = dce_conn->partial_input;
1083 dce_conn->partial_input = data_blob(blob.data + offset,
1084 blob.length - offset);
1085 data_blob_free(&blob);
1089 remove the call from the right list when freed
1091 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1093 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1094 return 0;
1098 process some input to a dcerpc endpoint server.
1100 NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
1101 struct ncacn_packet *pkt,
1102 DATA_BLOB blob)
1104 NTSTATUS status;
1105 struct dcesrv_call_state *call;
1107 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1108 if (!call) {
1109 data_blob_free(&blob);
1110 talloc_free(pkt);
1111 return NT_STATUS_NO_MEMORY;
1113 call->conn = dce_conn;
1114 call->event_ctx = dce_conn->event_ctx;
1115 call->msg_ctx = dce_conn->msg_ctx;
1116 call->state_flags = call->conn->state_flags;
1117 call->time = timeval_current();
1118 call->list = DCESRV_LIST_NONE;
1120 talloc_steal(call, pkt);
1121 talloc_steal(call, blob.data);
1122 call->pkt = *pkt;
1124 talloc_set_destructor(call, dcesrv_call_dequeue);
1126 /* we have to check the signing here, before combining the
1127 pdus */
1128 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1129 !dcesrv_auth_request(call, &blob)) {
1130 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1133 /* see if this is a continued packet */
1134 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1135 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1136 struct dcesrv_call_state *call2 = call;
1137 uint32_t alloc_size;
1139 /* we only allow fragmented requests, no other packet types */
1140 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1141 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1144 /* this is a continuation of an existing call - find the call then
1145 tack it on the end */
1146 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1147 if (!call) {
1148 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1151 if (call->pkt.ptype != call2->pkt.ptype) {
1152 /* trying to play silly buggers are we? */
1153 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1156 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1157 call2->pkt.u.request.stub_and_verifier.length;
1158 if (call->pkt.u.request.alloc_hint > alloc_size) {
1159 alloc_size = call->pkt.u.request.alloc_hint;
1162 call->pkt.u.request.stub_and_verifier.data =
1163 talloc_realloc(call,
1164 call->pkt.u.request.stub_and_verifier.data,
1165 uint8_t, alloc_size);
1166 if (!call->pkt.u.request.stub_and_verifier.data) {
1167 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1169 memcpy(call->pkt.u.request.stub_and_verifier.data +
1170 call->pkt.u.request.stub_and_verifier.length,
1171 call2->pkt.u.request.stub_and_verifier.data,
1172 call2->pkt.u.request.stub_and_verifier.length);
1173 call->pkt.u.request.stub_and_verifier.length +=
1174 call2->pkt.u.request.stub_and_verifier.length;
1176 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1178 talloc_free(call2);
1181 /* this may not be the last pdu in the chain - if its isn't then
1182 just put it on the incoming_fragmented_call_list and wait for the rest */
1183 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1184 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1185 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1186 return NT_STATUS_OK;
1189 /* This removes any fragments we may have had stashed away */
1190 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1192 switch (call->pkt.ptype) {
1193 case DCERPC_PKT_BIND:
1194 status = dcesrv_bind(call);
1195 break;
1196 case DCERPC_PKT_AUTH3:
1197 status = dcesrv_auth3(call);
1198 break;
1199 case DCERPC_PKT_ALTER:
1200 status = dcesrv_alter(call);
1201 break;
1202 case DCERPC_PKT_REQUEST:
1203 status = dcesrv_request(call);
1204 break;
1205 default:
1206 status = NT_STATUS_INVALID_PARAMETER;
1207 break;
1210 /* if we are going to be sending a reply then add
1211 it to the list of pending calls. We add it to the end to keep the call
1212 list in the order we will answer */
1213 if (!NT_STATUS_IS_OK(status)) {
1214 talloc_free(call);
1217 return status;
1220 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1221 struct loadparm_context *lp_ctx,
1222 const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1224 NTSTATUS status;
1225 struct dcesrv_context *dce_ctx;
1226 int i;
1228 if (!endpoint_servers) {
1229 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1230 return NT_STATUS_INTERNAL_ERROR;
1233 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1234 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1235 dce_ctx->endpoint_list = NULL;
1236 dce_ctx->lp_ctx = lp_ctx;
1238 for (i=0;endpoint_servers[i];i++) {
1239 const struct dcesrv_endpoint_server *ep_server;
1241 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1242 if (!ep_server) {
1243 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1244 return NT_STATUS_INTERNAL_ERROR;
1247 status = ep_server->init_server(dce_ctx, ep_server);
1248 if (!NT_STATUS_IS_OK(status)) {
1249 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1250 nt_errstr(status)));
1251 return status;
1255 *_dce_ctx = dce_ctx;
1256 return NT_STATUS_OK;
1259 /* the list of currently registered DCERPC endpoint servers.
1261 static struct ep_server {
1262 struct dcesrv_endpoint_server *ep_server;
1263 } *ep_servers = NULL;
1264 static int num_ep_servers;
1267 register a DCERPC endpoint server.
1269 The 'name' can be later used by other backends to find the operations
1270 structure for this backend.
1272 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1274 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1276 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1278 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1279 /* its already registered! */
1280 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1281 ep_server->name));
1282 return NT_STATUS_OBJECT_NAME_COLLISION;
1285 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1286 if (!ep_servers) {
1287 smb_panic("out of memory in dcerpc_register");
1290 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1291 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1293 num_ep_servers++;
1295 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1296 ep_server->name));
1298 return NT_STATUS_OK;
1302 return the operations structure for a named backend of the specified type
1304 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1306 int i;
1308 for (i=0;i<num_ep_servers;i++) {
1309 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1310 return ep_servers[i].ep_server;
1314 return NULL;
1317 void dcerpc_server_init(struct loadparm_context *lp_ctx)
1319 static bool initialized;
1320 extern NTSTATUS dcerpc_server_wkssvc_init(void);
1321 extern NTSTATUS dcerpc_server_drsuapi_init(void);
1322 extern NTSTATUS dcerpc_server_winreg_init(void);
1323 extern NTSTATUS dcerpc_server_spoolss_init(void);
1324 extern NTSTATUS dcerpc_server_epmapper_init(void);
1325 extern NTSTATUS dcerpc_server_srvsvc_init(void);
1326 extern NTSTATUS dcerpc_server_netlogon_init(void);
1327 extern NTSTATUS dcerpc_server_rpcecho_init(void);
1328 extern NTSTATUS dcerpc_server_unixinfo_init(void);
1329 extern NTSTATUS dcerpc_server_samr_init(void);
1330 extern NTSTATUS dcerpc_server_remote_init(void);
1331 extern NTSTATUS dcerpc_server_lsa_init(void);
1332 extern NTSTATUS dcerpc_server_browser_init(void);
1333 init_module_fn static_init[] = { STATIC_dcerpc_server_MODULES };
1334 init_module_fn *shared_init;
1336 if (initialized) {
1337 return;
1339 initialized = true;
1341 shared_init = load_samba_modules(NULL, lp_ctx, "dcerpc_server");
1343 run_init_functions(static_init);
1344 run_init_functions(shared_init);
1346 talloc_free(shared_init);
1350 return the DCERPC module version, and the size of some critical types
1351 This can be used by endpoint server modules to either detect compilation errors, or provide
1352 multiple implementations for different smbd compilation options in one module
1354 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1356 static const struct dcesrv_critical_sizes critical_sizes = {
1357 DCERPC_MODULE_VERSION,
1358 sizeof(struct dcesrv_context),
1359 sizeof(struct dcesrv_endpoint),
1360 sizeof(struct dcesrv_endpoint_server),
1361 sizeof(struct dcesrv_interface),
1362 sizeof(struct dcesrv_if_list),
1363 sizeof(struct dcesrv_connection),
1364 sizeof(struct dcesrv_call_state),
1365 sizeof(struct dcesrv_auth),
1366 sizeof(struct dcesrv_handle)
1369 return &critical_sizes;