s3:smbd:password_in_history: treat entry with 0 salt as 0 + plain nt hash
[Samba.git] / source4 / rpc_server / dcerpc_server.c
blobdf0c2e73453a2f3106ea80ebfed5c684765112d4
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 /* this is only used when the client asks for an unknown interface */
40 #define DUMMY_ASSOC_GROUP 0x0FFFFFFF
42 extern const struct dcesrv_interface dcesrv_mgmt_interface;
46 find an association group given a assoc_group_id
48 static struct dcesrv_assoc_group *dcesrv_assoc_group_find(struct dcesrv_context *dce_ctx,
49 uint32_t id)
51 void *id_ptr;
53 id_ptr = idr_find(dce_ctx->assoc_groups_idr, id);
54 if (id_ptr == NULL) {
55 return NULL;
57 return talloc_get_type_abort(id_ptr, struct dcesrv_assoc_group);
61 take a reference to an existing association group
63 static struct dcesrv_assoc_group *dcesrv_assoc_group_reference(TALLOC_CTX *mem_ctx,
64 struct dcesrv_context *dce_ctx,
65 uint32_t id)
67 struct dcesrv_assoc_group *assoc_group;
69 assoc_group = dcesrv_assoc_group_find(dce_ctx, id);
70 if (assoc_group == NULL) {
71 DEBUG(0,(__location__ ": Failed to find assoc_group 0x%08x\n", id));
72 return NULL;
74 return talloc_reference(mem_ctx, assoc_group);
77 static int dcesrv_assoc_group_destructor(struct dcesrv_assoc_group *assoc_group)
79 int ret;
80 ret = idr_remove(assoc_group->dce_ctx->assoc_groups_idr, assoc_group->id);
81 if (ret != 0) {
82 DEBUG(0,(__location__ ": Failed to remove assoc_group 0x%08x\n",
83 assoc_group->id));
85 return 0;
89 allocate a new association group
91 static struct dcesrv_assoc_group *dcesrv_assoc_group_new(TALLOC_CTX *mem_ctx,
92 struct dcesrv_context *dce_ctx)
94 struct dcesrv_assoc_group *assoc_group;
95 int id;
97 assoc_group = talloc_zero(mem_ctx, struct dcesrv_assoc_group);
98 if (assoc_group == NULL) {
99 return NULL;
102 id = idr_get_new_random(dce_ctx->assoc_groups_idr, assoc_group, UINT16_MAX);
103 if (id == -1) {
104 talloc_free(assoc_group);
105 DEBUG(0,(__location__ ": Out of association groups!\n"));
106 return NULL;
109 assoc_group->id = id;
110 assoc_group->dce_ctx = dce_ctx;
112 talloc_set_destructor(assoc_group, dcesrv_assoc_group_destructor);
114 return assoc_group;
119 see if two endpoints match
121 static bool endpoints_match(const struct dcerpc_binding *ep1,
122 const struct dcerpc_binding *ep2)
124 if (ep1->transport != ep2->transport) {
125 return false;
128 if (!ep1->endpoint || !ep2->endpoint) {
129 return ep1->endpoint == ep2->endpoint;
132 if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
133 return false;
135 return true;
139 find an endpoint in the dcesrv_context
141 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
142 const struct dcerpc_binding *ep_description)
144 struct dcesrv_endpoint *ep;
145 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
146 if (endpoints_match(ep->ep_description, ep_description)) {
147 return ep;
150 return NULL;
154 find a registered context_id from a bind or alter_context
156 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn,
157 uint32_t context_id)
159 struct dcesrv_connection_context *c;
160 for (c=conn->contexts;c;c=c->next) {
161 if (c->context_id == context_id) return c;
163 return NULL;
167 see if a uuid and if_version match to an interface
169 static bool interface_match(const struct dcesrv_interface *if1,
170 const struct dcesrv_interface *if2)
172 return (if1->syntax_id.if_version == if2->syntax_id.if_version &&
173 GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
177 find the interface operations on an endpoint
179 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
180 const struct dcesrv_interface *iface)
182 struct dcesrv_if_list *ifl;
183 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
184 if (interface_match(&(ifl->iface), iface)) {
185 return &(ifl->iface);
188 return NULL;
192 see if a uuid and if_version match to an interface
194 static bool interface_match_by_uuid(const struct dcesrv_interface *iface,
195 const struct GUID *uuid, uint32_t if_version)
197 return (iface->syntax_id.if_version == if_version &&
198 GUID_equal(&iface->syntax_id.uuid, uuid));
202 find the interface operations on an endpoint by uuid
204 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
205 const struct GUID *uuid, uint32_t if_version)
207 struct dcesrv_if_list *ifl;
208 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
209 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
210 return &(ifl->iface);
213 return NULL;
217 find the earlier parts of a fragmented call awaiting reassembily
219 static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
221 struct dcesrv_call_state *c;
222 for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
223 if (c->pkt.call_id == call_id) {
224 return c;
227 return NULL;
231 register an interface on an endpoint
233 _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
234 const char *ep_name,
235 const struct dcesrv_interface *iface,
236 const struct security_descriptor *sd)
238 struct dcesrv_endpoint *ep;
239 struct dcesrv_if_list *ifl;
240 struct dcerpc_binding *binding;
241 bool add_ep = false;
242 NTSTATUS status;
244 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
246 if (NT_STATUS_IS_ERR(status)) {
247 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
248 return status;
251 /* check if this endpoint exists
253 if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
254 ep = talloc(dce_ctx, struct dcesrv_endpoint);
255 if (!ep) {
256 return NT_STATUS_NO_MEMORY;
258 ZERO_STRUCTP(ep);
259 ep->ep_description = talloc_reference(ep, binding);
260 add_ep = true;
262 /* add mgmt interface */
263 ifl = talloc(dce_ctx, struct dcesrv_if_list);
264 if (!ifl) {
265 return NT_STATUS_NO_MEMORY;
268 memcpy(&(ifl->iface), &dcesrv_mgmt_interface,
269 sizeof(struct dcesrv_interface));
271 DLIST_ADD(ep->interface_list, ifl);
274 /* see if the interface is already registered on te endpoint */
275 if (find_interface(ep, iface)!=NULL) {
276 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
277 iface->name, ep_name));
278 return NT_STATUS_OBJECT_NAME_COLLISION;
281 /* talloc a new interface list element */
282 ifl = talloc(dce_ctx, struct dcesrv_if_list);
283 if (!ifl) {
284 return NT_STATUS_NO_MEMORY;
287 /* copy the given interface struct to the one on the endpoints interface list */
288 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
290 /* if we have a security descriptor given,
291 * we should see if we can set it up on the endpoint
293 if (sd != NULL) {
294 /* if there's currently no security descriptor given on the endpoint
295 * we try to set it
297 if (ep->sd == NULL) {
298 ep->sd = security_descriptor_copy(dce_ctx, sd);
301 /* if now there's no security descriptor given on the endpoint
302 * something goes wrong, either we failed to copy the security descriptor
303 * or there was already one on the endpoint
305 if (ep->sd != NULL) {
306 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
307 " on endpoint '%s'\n",
308 iface->name, ep_name));
309 if (add_ep) free(ep);
310 free(ifl);
311 return NT_STATUS_OBJECT_NAME_COLLISION;
315 /* finally add the interface on the endpoint */
316 DLIST_ADD(ep->interface_list, ifl);
318 /* if it's a new endpoint add it to the dcesrv_context */
319 if (add_ep) {
320 DLIST_ADD(dce_ctx->endpoint_list, ep);
323 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
324 iface->name, ep_name));
326 return NT_STATUS_OK;
329 NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
330 DATA_BLOB *session_key)
332 if (p->auth_state.session_info->session_key.length) {
333 *session_key = p->auth_state.session_info->session_key;
334 return NT_STATUS_OK;
336 return NT_STATUS_NO_USER_SESSION_KEY;
339 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
340 DATA_BLOB *session_key)
342 /* this took quite a few CPU cycles to find ... */
343 session_key->data = discard_const_p(uint8_t, "SystemLibraryDTC");
344 session_key->length = 16;
345 return NT_STATUS_OK;
349 fetch the user session key - may be default (above) or the SMB session key
351 The key is always truncated to 16 bytes
353 _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
354 DATA_BLOB *session_key)
356 NTSTATUS status = p->auth_state.session_key(p, session_key);
357 if (!NT_STATUS_IS_OK(status)) {
358 return status;
361 session_key->length = MIN(session_key->length, 16);
363 return NT_STATUS_OK;
367 connect to a dcerpc endpoint
369 _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
370 TALLOC_CTX *mem_ctx,
371 const struct dcesrv_endpoint *ep,
372 struct auth_session_info *session_info,
373 struct tevent_context *event_ctx,
374 struct messaging_context *msg_ctx,
375 struct server_id server_id,
376 uint32_t state_flags,
377 struct dcesrv_connection **_p)
379 struct dcesrv_connection *p;
381 if (!session_info) {
382 return NT_STATUS_ACCESS_DENIED;
385 p = talloc(mem_ctx, struct dcesrv_connection);
386 NT_STATUS_HAVE_NO_MEMORY(p);
388 if (!talloc_reference(p, session_info)) {
389 talloc_free(p);
390 return NT_STATUS_NO_MEMORY;
393 p->dce_ctx = dce_ctx;
394 p->endpoint = ep;
395 p->contexts = NULL;
396 p->call_list = NULL;
397 p->packet_log_dir = lp_lockdir(dce_ctx->lp_ctx);
398 p->incoming_fragmented_call_list = NULL;
399 p->pending_call_list = NULL;
400 p->cli_max_recv_frag = 0;
401 p->partial_input = data_blob(NULL, 0);
402 p->auth_state.auth_info = NULL;
403 p->auth_state.gensec_security = NULL;
404 p->auth_state.session_info = session_info;
405 p->auth_state.session_key = dcesrv_generic_session_key;
406 p->event_ctx = event_ctx;
407 p->msg_ctx = msg_ctx;
408 p->server_id = server_id;
409 p->processing = false;
410 p->state_flags = state_flags;
411 ZERO_STRUCT(p->transport);
413 *_p = p;
414 return NT_STATUS_OK;
417 static void dcesrv_init_hdr(struct ncacn_packet *pkt, bool bigendian)
419 pkt->rpc_vers = 5;
420 pkt->rpc_vers_minor = 0;
421 if (bigendian) {
422 pkt->drep[0] = 0;
423 } else {
424 pkt->drep[0] = DCERPC_DREP_LE;
426 pkt->drep[1] = 0;
427 pkt->drep[2] = 0;
428 pkt->drep[3] = 0;
432 move a call from an existing linked list to the specified list. This
433 prevents bugs where we forget to remove the call from a previous
434 list when moving it.
436 static void dcesrv_call_set_list(struct dcesrv_call_state *call,
437 enum dcesrv_call_list list)
439 switch (call->list) {
440 case DCESRV_LIST_NONE:
441 break;
442 case DCESRV_LIST_CALL_LIST:
443 DLIST_REMOVE(call->conn->call_list, call);
444 break;
445 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
446 DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
447 break;
448 case DCESRV_LIST_PENDING_CALL_LIST:
449 DLIST_REMOVE(call->conn->pending_call_list, call);
450 break;
452 call->list = list;
453 switch (list) {
454 case DCESRV_LIST_NONE:
455 break;
456 case DCESRV_LIST_CALL_LIST:
457 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
458 break;
459 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
460 DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
461 break;
462 case DCESRV_LIST_PENDING_CALL_LIST:
463 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
464 break;
469 return a dcerpc fault
471 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
473 struct ncacn_packet pkt;
474 struct data_blob_list_item *rep;
475 uint8_t zeros[4];
476 NTSTATUS status;
478 /* setup a bind_ack */
479 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
480 pkt.auth_length = 0;
481 pkt.call_id = call->pkt.call_id;
482 pkt.ptype = DCERPC_PKT_FAULT;
483 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
484 pkt.u.fault.alloc_hint = 0;
485 pkt.u.fault.context_id = 0;
486 pkt.u.fault.cancel_count = 0;
487 pkt.u.fault.status = fault_code;
489 ZERO_STRUCT(zeros);
490 pkt.u.fault._pad = data_blob_const(zeros, sizeof(zeros));
492 rep = talloc(call, struct data_blob_list_item);
493 if (!rep) {
494 return NT_STATUS_NO_MEMORY;
497 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
498 if (!NT_STATUS_IS_OK(status)) {
499 return status;
502 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
504 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
505 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
507 if (call->conn->call_list && call->conn->call_list->replies) {
508 if (call->conn->transport.report_output_data) {
509 call->conn->transport.report_output_data(call->conn);
513 return NT_STATUS_OK;
518 return a dcerpc bind_nak
520 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
522 struct ncacn_packet pkt;
523 struct data_blob_list_item *rep;
524 NTSTATUS status;
526 /* setup a bind_nak */
527 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
528 pkt.auth_length = 0;
529 pkt.call_id = call->pkt.call_id;
530 pkt.ptype = DCERPC_PKT_BIND_NAK;
531 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
532 pkt.u.bind_nak.reject_reason = reason;
533 if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
534 pkt.u.bind_nak.versions.v.num_versions = 0;
537 rep = talloc(call, struct data_blob_list_item);
538 if (!rep) {
539 return NT_STATUS_NO_MEMORY;
542 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
543 if (!NT_STATUS_IS_OK(status)) {
544 return status;
547 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
549 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
550 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
552 if (call->conn->call_list && call->conn->call_list->replies) {
553 if (call->conn->transport.report_output_data) {
554 call->conn->transport.report_output_data(call->conn);
558 return NT_STATUS_OK;
561 static int dcesrv_connection_context_destructor(struct dcesrv_connection_context *c)
563 DLIST_REMOVE(c->conn->contexts, c);
565 if (c->iface) {
566 c->iface->unbind(c, c->iface);
569 return 0;
573 handle a bind request
575 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
577 uint32_t if_version, transfer_syntax_version;
578 struct GUID uuid, *transfer_syntax_uuid;
579 struct ncacn_packet pkt;
580 struct data_blob_list_item *rep;
581 NTSTATUS status;
582 uint32_t result=0, reason=0;
583 uint32_t context_id;
584 const struct dcesrv_interface *iface;
585 uint32_t extra_flags = 0;
588 if provided, check the assoc_group is valid
590 if (call->pkt.u.bind.assoc_group_id != 0 &&
591 lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
592 dcesrv_assoc_group_find(call->conn->dce_ctx, call->pkt.u.bind.assoc_group_id) == NULL) {
593 return dcesrv_bind_nak(call, 0);
596 if (call->pkt.u.bind.num_contexts < 1 ||
597 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
598 return dcesrv_bind_nak(call, 0);
601 context_id = call->pkt.u.bind.ctx_list[0].context_id;
603 /* you can't bind twice on one context */
604 if (dcesrv_find_context(call->conn, context_id) != NULL) {
605 return dcesrv_bind_nak(call, 0);
608 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
609 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
611 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
612 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
613 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
614 ndr_transfer_syntax.if_version != transfer_syntax_version) {
615 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
616 /* we only do NDR encoded dcerpc */
617 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
618 talloc_free(uuid_str);
619 return dcesrv_bind_nak(call, 0);
622 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
623 if (iface == NULL) {
624 char *uuid_str = GUID_string(call, &uuid);
625 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
626 talloc_free(uuid_str);
628 /* we don't know about that interface */
629 result = DCERPC_BIND_PROVIDER_REJECT;
630 reason = DCERPC_BIND_REASON_ASYNTAX;
633 if (iface) {
634 /* add this context to the list of available context_ids */
635 struct dcesrv_connection_context *context = talloc(call->conn,
636 struct dcesrv_connection_context);
637 if (context == NULL) {
638 return dcesrv_bind_nak(call, 0);
640 context->conn = call->conn;
641 context->iface = iface;
642 context->context_id = context_id;
643 if (call->pkt.u.bind.assoc_group_id != 0) {
644 context->assoc_group = dcesrv_assoc_group_reference(context,
645 call->conn->dce_ctx,
646 call->pkt.u.bind.assoc_group_id);
647 } else {
648 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
650 if (context->assoc_group == NULL) {
651 talloc_free(context);
652 return dcesrv_bind_nak(call, 0);
654 context->private_data = NULL;
655 DLIST_ADD(call->conn->contexts, context);
656 call->context = context;
657 talloc_set_destructor(context, dcesrv_connection_context_destructor);
659 status = iface->bind(call, iface);
660 if (!NT_STATUS_IS_OK(status)) {
661 char *uuid_str = GUID_string(call, &uuid);
662 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
663 uuid_str, if_version, nt_errstr(status)));
664 talloc_free(uuid_str);
665 /* we don't want to trigger the iface->unbind() hook */
666 context->iface = NULL;
667 talloc_free(call->context);
668 call->context = NULL;
669 return dcesrv_bind_nak(call, 0);
673 if (call->conn->cli_max_recv_frag == 0) {
674 call->conn->cli_max_recv_frag = MIN(0x2000, call->pkt.u.bind.max_recv_frag);
677 if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) &&
678 lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","header signing", false)) {
679 call->conn->state_flags |= DCESRV_CALL_STATE_FLAG_HEADER_SIGNING;
680 extra_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
683 /* handle any authentication that is being requested */
684 if (!dcesrv_auth_bind(call)) {
685 talloc_free(call->context);
686 call->context = NULL;
687 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
690 /* setup a bind_ack */
691 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
692 pkt.auth_length = 0;
693 pkt.call_id = call->pkt.call_id;
694 pkt.ptype = DCERPC_PKT_BIND_ACK;
695 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
696 pkt.u.bind_ack.max_xmit_frag = call->conn->cli_max_recv_frag;
697 pkt.u.bind_ack.max_recv_frag = 0x2000;
700 make it possible for iface->bind() to specify the assoc_group_id
701 This helps the openchange mapiproxy plugin to work correctly.
703 metze
705 if (call->context) {
706 pkt.u.bind_ack.assoc_group_id = call->context->assoc_group->id;
707 } else {
708 pkt.u.bind_ack.assoc_group_id = DUMMY_ASSOC_GROUP;
711 if (iface) {
712 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
713 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
714 } else {
715 pkt.u.bind_ack.secondary_address = "";
717 pkt.u.bind_ack.num_results = 1;
718 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
719 if (!pkt.u.bind_ack.ctx_list) {
720 talloc_free(call->context);
721 call->context = NULL;
722 return NT_STATUS_NO_MEMORY;
724 pkt.u.bind_ack.ctx_list[0].result = result;
725 pkt.u.bind_ack.ctx_list[0].reason = reason;
726 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
727 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
729 status = dcesrv_auth_bind_ack(call, &pkt);
730 if (!NT_STATUS_IS_OK(status)) {
731 talloc_free(call->context);
732 call->context = NULL;
733 return dcesrv_bind_nak(call, 0);
736 rep = talloc(call, struct data_blob_list_item);
737 if (!rep) {
738 talloc_free(call->context);
739 call->context = NULL;
740 return NT_STATUS_NO_MEMORY;
743 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
744 if (!NT_STATUS_IS_OK(status)) {
745 talloc_free(call->context);
746 call->context = NULL;
747 return status;
750 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
752 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
753 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
755 if (call->conn->call_list && call->conn->call_list->replies) {
756 if (call->conn->transport.report_output_data) {
757 call->conn->transport.report_output_data(call->conn);
761 return NT_STATUS_OK;
766 handle a auth3 request
768 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
770 /* handle the auth3 in the auth code */
771 if (!dcesrv_auth_auth3(call)) {
772 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
775 talloc_free(call);
777 /* we don't send a reply to a auth3 request, except by a
778 fault */
779 return NT_STATUS_OK;
784 handle a bind request
786 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
788 uint32_t if_version, transfer_syntax_version;
789 struct dcesrv_connection_context *context;
790 const struct dcesrv_interface *iface;
791 struct GUID uuid, *transfer_syntax_uuid;
792 NTSTATUS status;
794 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
795 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
797 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
798 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
799 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
800 ndr_transfer_syntax.if_version != transfer_syntax_version) {
801 /* we only do NDR encoded dcerpc */
802 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
805 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
806 if (iface == NULL) {
807 char *uuid_str = GUID_string(call, &uuid);
808 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
809 talloc_free(uuid_str);
810 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
813 /* add this context to the list of available context_ids */
814 context = talloc(call->conn, struct dcesrv_connection_context);
815 if (context == NULL) {
816 return NT_STATUS_NO_MEMORY;
818 context->conn = call->conn;
819 context->iface = iface;
820 context->context_id = context_id;
821 if (call->pkt.u.alter.assoc_group_id != 0) {
822 context->assoc_group = dcesrv_assoc_group_reference(context,
823 call->conn->dce_ctx,
824 call->pkt.u.alter.assoc_group_id);
825 } else {
826 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
828 if (context->assoc_group == NULL) {
829 talloc_free(context);
830 call->context = NULL;
831 return NT_STATUS_NO_MEMORY;
833 context->private_data = NULL;
834 DLIST_ADD(call->conn->contexts, context);
835 call->context = context;
836 talloc_set_destructor(context, dcesrv_connection_context_destructor);
838 status = iface->bind(call, iface);
839 if (!NT_STATUS_IS_OK(status)) {
840 /* we don't want to trigger the iface->unbind() hook */
841 context->iface = NULL;
842 talloc_free(context);
843 call->context = NULL;
844 return status;
847 return NT_STATUS_OK;
852 handle a alter context request
854 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
856 struct ncacn_packet pkt;
857 struct data_blob_list_item *rep;
858 NTSTATUS status;
859 uint32_t result=0, reason=0;
860 uint32_t context_id;
862 /* handle any authentication that is being requested */
863 if (!dcesrv_auth_alter(call)) {
864 /* TODO: work out the right reject code */
865 result = DCERPC_BIND_PROVIDER_REJECT;
866 reason = DCERPC_BIND_REASON_ASYNTAX;
869 context_id = call->pkt.u.alter.ctx_list[0].context_id;
871 /* see if they are asking for a new interface */
872 if (result == 0) {
873 call->context = dcesrv_find_context(call->conn, context_id);
874 if (!call->context) {
875 status = dcesrv_alter_new_context(call, context_id);
876 if (!NT_STATUS_IS_OK(status)) {
877 result = DCERPC_BIND_PROVIDER_REJECT;
878 reason = DCERPC_BIND_REASON_ASYNTAX;
883 if (result == 0 &&
884 call->pkt.u.alter.assoc_group_id != 0 &&
885 lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
886 call->pkt.u.alter.assoc_group_id != call->context->assoc_group->id) {
887 DEBUG(0,(__location__ ": Failed attempt to use new assoc_group in alter context (0x%08x 0x%08x)\n",
888 call->context->assoc_group->id, call->pkt.u.alter.assoc_group_id));
889 /* TODO: can they ask for a new association group? */
890 result = DCERPC_BIND_PROVIDER_REJECT;
891 reason = DCERPC_BIND_REASON_ASYNTAX;
894 /* setup a alter_resp */
895 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
896 pkt.auth_length = 0;
897 pkt.call_id = call->pkt.call_id;
898 pkt.ptype = DCERPC_PKT_ALTER_RESP;
899 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
900 pkt.u.alter_resp.max_xmit_frag = 0x2000;
901 pkt.u.alter_resp.max_recv_frag = 0x2000;
902 if (result == 0) {
903 pkt.u.alter_resp.assoc_group_id = call->context->assoc_group->id;
904 } else {
905 pkt.u.alter_resp.assoc_group_id = 0;
907 pkt.u.alter_resp.num_results = 1;
908 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
909 if (!pkt.u.alter_resp.ctx_list) {
910 return NT_STATUS_NO_MEMORY;
912 pkt.u.alter_resp.ctx_list[0].result = result;
913 pkt.u.alter_resp.ctx_list[0].reason = reason;
914 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
915 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
916 pkt.u.alter_resp.secondary_address = "";
918 status = dcesrv_auth_alter_ack(call, &pkt);
919 if (!NT_STATUS_IS_OK(status)) {
920 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
921 || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
922 || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
923 || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
924 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
926 return dcesrv_fault(call, 0);
929 rep = talloc(call, struct data_blob_list_item);
930 if (!rep) {
931 return NT_STATUS_NO_MEMORY;
934 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
935 if (!NT_STATUS_IS_OK(status)) {
936 return status;
939 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
941 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
942 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
944 if (call->conn->call_list && call->conn->call_list->replies) {
945 if (call->conn->transport.report_output_data) {
946 call->conn->transport.report_output_data(call->conn);
950 return NT_STATUS_OK;
954 handle a dcerpc request packet
956 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
958 struct ndr_pull *pull;
959 NTSTATUS status;
960 struct dcesrv_connection_context *context;
962 /* if authenticated, and the mech we use can't do async replies, don't use them... */
963 if (call->conn->auth_state.gensec_security &&
964 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
965 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
968 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
969 if (context == NULL) {
970 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
973 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call,
974 lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
975 NT_STATUS_HAVE_NO_MEMORY(pull);
977 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
979 call->context = context;
980 call->ndr_pull = pull;
982 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
983 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
986 /* unravel the NDR for the packet */
987 status = context->iface->ndr_pull(call, call, pull, &call->r);
988 if (!NT_STATUS_IS_OK(status)) {
989 return dcesrv_fault(call, call->fault_code);
992 if (pull->offset != pull->data_size) {
993 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
994 pull->data_size - pull->offset));
995 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
998 /* call the dispatch function */
999 status = context->iface->dispatch(call, call, call->r);
1000 if (!NT_STATUS_IS_OK(status)) {
1001 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
1002 context->iface->name,
1003 call->pkt.u.request.opnum,
1004 dcerpc_errstr(pull, call->fault_code)));
1005 return dcesrv_fault(call, call->fault_code);
1008 /* add the call to the pending list */
1009 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
1011 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
1012 return NT_STATUS_OK;
1015 return dcesrv_reply(call);
1018 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
1020 struct ndr_push *push;
1021 NTSTATUS status;
1022 DATA_BLOB stub;
1023 uint32_t total_length, chunk_size;
1024 struct dcesrv_connection_context *context = call->context;
1025 size_t sig_size = 0;
1027 /* call the reply function */
1028 status = context->iface->reply(call, call, call->r);
1029 if (!NT_STATUS_IS_OK(status)) {
1030 return dcesrv_fault(call, call->fault_code);
1033 /* form the reply NDR */
1034 push = ndr_push_init_ctx(call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
1035 NT_STATUS_HAVE_NO_MEMORY(push);
1037 /* carry over the pointer count to the reply in case we are
1038 using full pointer. See NDR specification for full
1039 pointers */
1040 push->ptr_count = call->ndr_pull->ptr_count;
1042 if (lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
1043 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1046 status = context->iface->ndr_push(call, call, push, call->r);
1047 if (!NT_STATUS_IS_OK(status)) {
1048 return dcesrv_fault(call, call->fault_code);
1051 stub = ndr_push_blob(push);
1053 total_length = stub.length;
1055 /* we can write a full max_recv_frag size, minus the dcerpc
1056 request header size */
1057 chunk_size = call->conn->cli_max_recv_frag;
1058 chunk_size -= DCERPC_REQUEST_LENGTH;
1059 if (call->conn->auth_state.auth_info &&
1060 call->conn->auth_state.gensec_security) {
1061 sig_size = gensec_sig_size(call->conn->auth_state.gensec_security,
1062 call->conn->cli_max_recv_frag);
1063 if (sig_size) {
1064 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1065 chunk_size -= sig_size;
1068 chunk_size -= (chunk_size % 16);
1070 do {
1071 uint32_t length;
1072 struct data_blob_list_item *rep;
1073 struct ncacn_packet pkt;
1075 rep = talloc(call, struct data_blob_list_item);
1076 NT_STATUS_HAVE_NO_MEMORY(rep);
1078 length = MIN(chunk_size, stub.length);
1080 /* form the dcerpc response packet */
1081 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
1082 pkt.auth_length = 0;
1083 pkt.call_id = call->pkt.call_id;
1084 pkt.ptype = DCERPC_PKT_RESPONSE;
1085 pkt.pfc_flags = 0;
1086 if (stub.length == total_length) {
1087 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1089 if (length == stub.length) {
1090 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1092 pkt.u.response.alloc_hint = stub.length;
1093 pkt.u.response.context_id = call->pkt.u.request.context_id;
1094 pkt.u.response.cancel_count = 0;
1095 pkt.u.response.stub_and_verifier.data = stub.data;
1096 pkt.u.response.stub_and_verifier.length = length;
1098 if (!dcesrv_auth_response(call, &rep->blob, sig_size, &pkt)) {
1099 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
1102 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
1104 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
1106 stub.data += length;
1107 stub.length -= length;
1108 } while (stub.length != 0);
1110 /* move the call from the pending to the finished calls list */
1111 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
1113 if (call->conn->call_list && call->conn->call_list->replies) {
1114 if (call->conn->transport.report_output_data) {
1115 call->conn->transport.report_output_data(call->conn);
1119 return NT_STATUS_OK;
1122 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1124 if (!conn->transport.get_my_addr) {
1125 return NULL;
1128 return conn->transport.get_my_addr(conn, mem_ctx);
1131 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1133 if (!conn->transport.get_peer_addr) {
1134 return NULL;
1137 return conn->transport.get_peer_addr(conn, mem_ctx);
1142 remove the call from the right list when freed
1144 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1146 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1147 return 0;
1151 process some input to a dcerpc endpoint server.
1153 NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
1154 struct ncacn_packet *pkt,
1155 DATA_BLOB blob)
1157 NTSTATUS status;
1158 struct dcesrv_call_state *call;
1160 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1161 if (!call) {
1162 data_blob_free(&blob);
1163 talloc_free(pkt);
1164 return NT_STATUS_NO_MEMORY;
1166 call->conn = dce_conn;
1167 call->event_ctx = dce_conn->event_ctx;
1168 call->msg_ctx = dce_conn->msg_ctx;
1169 call->state_flags = call->conn->state_flags;
1170 call->time = timeval_current();
1171 call->list = DCESRV_LIST_NONE;
1173 talloc_steal(call, pkt);
1174 talloc_steal(call, blob.data);
1175 call->pkt = *pkt;
1177 talloc_set_destructor(call, dcesrv_call_dequeue);
1179 /* we have to check the signing here, before combining the
1180 pdus */
1181 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1182 !dcesrv_auth_request(call, &blob)) {
1183 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1186 /* see if this is a continued packet */
1187 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1188 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1189 struct dcesrv_call_state *call2 = call;
1190 uint32_t alloc_size;
1192 /* we only allow fragmented requests, no other packet types */
1193 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1194 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1197 /* this is a continuation of an existing call - find the call then
1198 tack it on the end */
1199 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1200 if (!call) {
1201 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1204 if (call->pkt.ptype != call2->pkt.ptype) {
1205 /* trying to play silly buggers are we? */
1206 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1209 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1210 call2->pkt.u.request.stub_and_verifier.length;
1211 if (call->pkt.u.request.alloc_hint > alloc_size) {
1212 alloc_size = call->pkt.u.request.alloc_hint;
1215 call->pkt.u.request.stub_and_verifier.data =
1216 talloc_realloc(call,
1217 call->pkt.u.request.stub_and_verifier.data,
1218 uint8_t, alloc_size);
1219 if (!call->pkt.u.request.stub_and_verifier.data) {
1220 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1222 memcpy(call->pkt.u.request.stub_and_verifier.data +
1223 call->pkt.u.request.stub_and_verifier.length,
1224 call2->pkt.u.request.stub_and_verifier.data,
1225 call2->pkt.u.request.stub_and_verifier.length);
1226 call->pkt.u.request.stub_and_verifier.length +=
1227 call2->pkt.u.request.stub_and_verifier.length;
1229 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1231 talloc_free(call2);
1234 /* this may not be the last pdu in the chain - if its isn't then
1235 just put it on the incoming_fragmented_call_list and wait for the rest */
1236 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1237 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1238 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1239 return NT_STATUS_OK;
1242 /* This removes any fragments we may have had stashed away */
1243 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1245 switch (call->pkt.ptype) {
1246 case DCERPC_PKT_BIND:
1247 status = dcesrv_bind(call);
1248 break;
1249 case DCERPC_PKT_AUTH3:
1250 status = dcesrv_auth3(call);
1251 break;
1252 case DCERPC_PKT_ALTER:
1253 status = dcesrv_alter(call);
1254 break;
1255 case DCERPC_PKT_REQUEST:
1256 status = dcesrv_request(call);
1257 break;
1258 default:
1259 status = NT_STATUS_INVALID_PARAMETER;
1260 break;
1263 /* if we are going to be sending a reply then add
1264 it to the list of pending calls. We add it to the end to keep the call
1265 list in the order we will answer */
1266 if (!NT_STATUS_IS_OK(status)) {
1267 talloc_free(call);
1270 return status;
1273 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1274 struct loadparm_context *lp_ctx,
1275 const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1277 NTSTATUS status;
1278 struct dcesrv_context *dce_ctx;
1279 int i;
1281 if (!endpoint_servers) {
1282 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1283 return NT_STATUS_INTERNAL_ERROR;
1286 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1287 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1288 dce_ctx->endpoint_list = NULL;
1289 dce_ctx->lp_ctx = lp_ctx;
1290 dce_ctx->assoc_groups_idr = idr_init(dce_ctx);
1291 NT_STATUS_HAVE_NO_MEMORY(dce_ctx->assoc_groups_idr);
1293 for (i=0;endpoint_servers[i];i++) {
1294 const struct dcesrv_endpoint_server *ep_server;
1296 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1297 if (!ep_server) {
1298 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1299 return NT_STATUS_INTERNAL_ERROR;
1302 status = ep_server->init_server(dce_ctx, ep_server);
1303 if (!NT_STATUS_IS_OK(status)) {
1304 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1305 nt_errstr(status)));
1306 return status;
1310 *_dce_ctx = dce_ctx;
1311 return NT_STATUS_OK;
1314 /* the list of currently registered DCERPC endpoint servers.
1316 static struct ep_server {
1317 struct dcesrv_endpoint_server *ep_server;
1318 } *ep_servers = NULL;
1319 static int num_ep_servers;
1322 register a DCERPC endpoint server.
1324 The 'name' can be later used by other backends to find the operations
1325 structure for this backend.
1327 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1329 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1331 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1333 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1334 /* its already registered! */
1335 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1336 ep_server->name));
1337 return NT_STATUS_OBJECT_NAME_COLLISION;
1340 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1341 if (!ep_servers) {
1342 smb_panic("out of memory in dcerpc_register");
1345 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1346 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1348 num_ep_servers++;
1350 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1351 ep_server->name));
1353 return NT_STATUS_OK;
1357 return the operations structure for a named backend of the specified type
1359 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1361 int i;
1363 for (i=0;i<num_ep_servers;i++) {
1364 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1365 return ep_servers[i].ep_server;
1369 return NULL;
1372 void dcerpc_server_init(struct loadparm_context *lp_ctx)
1374 static bool initialized;
1375 extern NTSTATUS dcerpc_server_wkssvc_init(void);
1376 extern NTSTATUS dcerpc_server_drsuapi_init(void);
1377 extern NTSTATUS dcerpc_server_winreg_init(void);
1378 extern NTSTATUS dcerpc_server_spoolss_init(void);
1379 extern NTSTATUS dcerpc_server_epmapper_init(void);
1380 extern NTSTATUS dcerpc_server_srvsvc_init(void);
1381 extern NTSTATUS dcerpc_server_netlogon_init(void);
1382 extern NTSTATUS dcerpc_server_rpcecho_init(void);
1383 extern NTSTATUS dcerpc_server_unixinfo_init(void);
1384 extern NTSTATUS dcerpc_server_samr_init(void);
1385 extern NTSTATUS dcerpc_server_remote_init(void);
1386 extern NTSTATUS dcerpc_server_lsa_init(void);
1387 extern NTSTATUS dcerpc_server_browser_init(void);
1388 init_module_fn static_init[] = { STATIC_dcerpc_server_MODULES };
1389 init_module_fn *shared_init;
1391 if (initialized) {
1392 return;
1394 initialized = true;
1396 shared_init = load_samba_modules(NULL, lp_ctx, "dcerpc_server");
1398 run_init_functions(static_init);
1399 run_init_functions(shared_init);
1401 talloc_free(shared_init);
1405 return the DCERPC module version, and the size of some critical types
1406 This can be used by endpoint server modules to either detect compilation errors, or provide
1407 multiple implementations for different smbd compilation options in one module
1409 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1411 static const struct dcesrv_critical_sizes critical_sizes = {
1412 DCERPC_MODULE_VERSION,
1413 sizeof(struct dcesrv_context),
1414 sizeof(struct dcesrv_endpoint),
1415 sizeof(struct dcesrv_endpoint_server),
1416 sizeof(struct dcesrv_interface),
1417 sizeof(struct dcesrv_if_list),
1418 sizeof(struct dcesrv_connection),
1419 sizeof(struct dcesrv_call_state),
1420 sizeof(struct dcesrv_auth),
1421 sizeof(struct dcesrv_handle)
1424 return &critical_sizes;