Fix typo.
[Samba.git] / source4 / rpc_server / dcerpc_server.c
blobe5f59d0cf946c65dcdb6638fda6a122115034931
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_ACCOC_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 static 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;
293 destroy a link to an endpoint
295 static int dcesrv_endpoint_destructor(struct dcesrv_connection *p)
297 while (p->contexts) {
298 struct dcesrv_connection_context *c = p->contexts;
300 DLIST_REMOVE(p->contexts, c);
302 if (c->iface) {
303 c->iface->unbind(c, c->iface);
307 return 0;
312 connect to a dcerpc endpoint
314 _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
315 TALLOC_CTX *mem_ctx,
316 const struct dcesrv_endpoint *ep,
317 struct auth_session_info *session_info,
318 struct event_context *event_ctx,
319 struct messaging_context *msg_ctx,
320 struct server_id server_id,
321 uint32_t state_flags,
322 struct dcesrv_connection **_p)
324 struct dcesrv_connection *p;
326 if (!session_info) {
327 return NT_STATUS_ACCESS_DENIED;
330 p = talloc(mem_ctx, struct dcesrv_connection);
331 NT_STATUS_HAVE_NO_MEMORY(p);
333 if (!talloc_reference(p, session_info)) {
334 talloc_free(p);
335 return NT_STATUS_NO_MEMORY;
338 p->dce_ctx = dce_ctx;
339 p->endpoint = ep;
340 p->contexts = NULL;
341 p->call_list = NULL;
342 p->incoming_fragmented_call_list = NULL;
343 p->pending_call_list = NULL;
344 p->cli_max_recv_frag = 0;
345 p->partial_input = data_blob(NULL, 0);
346 p->auth_state.auth_info = NULL;
347 p->auth_state.gensec_security = NULL;
348 p->auth_state.session_info = session_info;
349 p->auth_state.session_key = dcesrv_generic_session_key;
350 p->event_ctx = event_ctx;
351 p->msg_ctx = msg_ctx;
352 p->server_id = server_id;
353 p->processing = false;
354 p->state_flags = state_flags;
355 ZERO_STRUCT(p->transport);
357 talloc_set_destructor(p, dcesrv_endpoint_destructor);
359 *_p = p;
360 return NT_STATUS_OK;
364 search and connect to a dcerpc endpoint
366 _PUBLIC_ NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
367 TALLOC_CTX *mem_ctx,
368 const struct dcerpc_binding *ep_description,
369 struct auth_session_info *session_info,
370 struct event_context *event_ctx,
371 struct messaging_context *msg_ctx,
372 struct server_id server_id,
373 uint32_t state_flags,
374 struct dcesrv_connection **dce_conn_p)
376 NTSTATUS status;
377 const struct dcesrv_endpoint *ep;
379 /* make sure this endpoint exists */
380 ep = find_endpoint(dce_ctx, ep_description);
381 if (!ep) {
382 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
385 status = dcesrv_endpoint_connect(dce_ctx, mem_ctx, ep, session_info,
386 event_ctx, msg_ctx, server_id,
387 state_flags, dce_conn_p);
388 NT_STATUS_NOT_OK_RETURN(status);
390 (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
392 /* TODO: check security descriptor of the endpoint here
393 * if it's a smb named pipe
394 * if it's failed free dce_conn_p
397 return NT_STATUS_OK;
401 static void dcesrv_init_hdr(struct ncacn_packet *pkt, bool bigendian)
403 pkt->rpc_vers = 5;
404 pkt->rpc_vers_minor = 0;
405 if (bigendian) {
406 pkt->drep[0] = 0;
407 } else {
408 pkt->drep[0] = DCERPC_DREP_LE;
410 pkt->drep[1] = 0;
411 pkt->drep[2] = 0;
412 pkt->drep[3] = 0;
416 move a call from an existing linked list to the specified list. This
417 prevents bugs where we forget to remove the call from a previous
418 list when moving it.
420 static void dcesrv_call_set_list(struct dcesrv_call_state *call,
421 enum dcesrv_call_list list)
423 switch (call->list) {
424 case DCESRV_LIST_NONE:
425 break;
426 case DCESRV_LIST_CALL_LIST:
427 DLIST_REMOVE(call->conn->call_list, call);
428 break;
429 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
430 DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
431 break;
432 case DCESRV_LIST_PENDING_CALL_LIST:
433 DLIST_REMOVE(call->conn->pending_call_list, call);
434 break;
436 call->list = list;
437 switch (list) {
438 case DCESRV_LIST_NONE:
439 break;
440 case DCESRV_LIST_CALL_LIST:
441 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
442 break;
443 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
444 DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
445 break;
446 case DCESRV_LIST_PENDING_CALL_LIST:
447 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
448 break;
453 return a dcerpc fault
455 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
457 struct ncacn_packet pkt;
458 struct data_blob_list_item *rep;
459 uint8_t zeros[4];
460 NTSTATUS status;
462 /* setup a bind_ack */
463 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
464 pkt.auth_length = 0;
465 pkt.call_id = call->pkt.call_id;
466 pkt.ptype = DCERPC_PKT_FAULT;
467 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
468 pkt.u.fault.alloc_hint = 0;
469 pkt.u.fault.context_id = 0;
470 pkt.u.fault.cancel_count = 0;
471 pkt.u.fault.status = fault_code;
473 ZERO_STRUCT(zeros);
474 pkt.u.fault._pad = data_blob_const(zeros, sizeof(zeros));
476 rep = talloc(call, struct data_blob_list_item);
477 if (!rep) {
478 return NT_STATUS_NO_MEMORY;
481 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
482 if (!NT_STATUS_IS_OK(status)) {
483 return status;
486 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
488 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
489 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
491 return NT_STATUS_OK;
496 return a dcerpc bind_nak
498 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
500 struct ncacn_packet pkt;
501 struct data_blob_list_item *rep;
502 NTSTATUS status;
504 /* setup a bind_nak */
505 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
506 pkt.auth_length = 0;
507 pkt.call_id = call->pkt.call_id;
508 pkt.ptype = DCERPC_PKT_BIND_NAK;
509 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
510 pkt.u.bind_nak.reject_reason = reason;
511 if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
512 pkt.u.bind_nak.versions.v.num_versions = 0;
515 rep = talloc(call, struct data_blob_list_item);
516 if (!rep) {
517 return NT_STATUS_NO_MEMORY;
520 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
521 if (!NT_STATUS_IS_OK(status)) {
522 return status;
525 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
527 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
528 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
530 return NT_STATUS_OK;
535 handle a bind request
537 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
539 uint32_t if_version, transfer_syntax_version;
540 struct GUID uuid, *transfer_syntax_uuid;
541 struct ncacn_packet pkt;
542 struct data_blob_list_item *rep;
543 NTSTATUS status;
544 uint32_t result=0, reason=0;
545 uint32_t context_id;
546 const struct dcesrv_interface *iface;
547 uint32_t extra_flags = 0;
550 * Association groups allow policy handles to be shared across
551 * multiple client connections. We don't implement this yet.
553 * So we just allow 0 if the client wants to create a new
554 * association group.
556 * And we allow the 0x12345678 value, we give away as
557 * assoc_group_id back to the clients
559 if (call->pkt.u.bind.assoc_group_id != 0 &&
560 call->pkt.u.bind.assoc_group_id != SAMBA_ACCOC_GROUP) {
561 return dcesrv_bind_nak(call, 0);
564 if (call->pkt.u.bind.num_contexts < 1 ||
565 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
566 return dcesrv_bind_nak(call, 0);
569 context_id = call->pkt.u.bind.ctx_list[0].context_id;
571 /* you can't bind twice on one context */
572 if (dcesrv_find_context(call->conn, context_id) != NULL) {
573 return dcesrv_bind_nak(call, 0);
576 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
577 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
579 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
580 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
581 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
582 ndr_transfer_syntax.if_version != transfer_syntax_version) {
583 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
584 /* we only do NDR encoded dcerpc */
585 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
586 talloc_free(uuid_str);
587 return dcesrv_bind_nak(call, 0);
590 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
591 if (iface == NULL) {
592 char *uuid_str = GUID_string(call, &uuid);
593 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
594 talloc_free(uuid_str);
596 /* we don't know about that interface */
597 result = DCERPC_BIND_PROVIDER_REJECT;
598 reason = DCERPC_BIND_REASON_ASYNTAX;
601 if (iface) {
602 /* add this context to the list of available context_ids */
603 struct dcesrv_connection_context *context = talloc(call->conn,
604 struct dcesrv_connection_context);
605 if (context == NULL) {
606 return dcesrv_bind_nak(call, 0);
608 context->conn = call->conn;
609 context->iface = iface;
610 context->context_id = context_id;
611 context->private = NULL;
612 context->handles = NULL;
613 DLIST_ADD(call->conn->contexts, context);
614 call->context = context;
617 if (call->conn->cli_max_recv_frag == 0) {
618 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
621 if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) &&
622 lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","header signing", false)) {
623 call->conn->state_flags |= DCESRV_CALL_STATE_FLAG_HEADER_SIGNING;
624 extra_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
627 /* handle any authentication that is being requested */
628 if (!dcesrv_auth_bind(call)) {
629 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
632 /* setup a bind_ack */
633 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
634 pkt.auth_length = 0;
635 pkt.call_id = call->pkt.call_id;
636 pkt.ptype = DCERPC_PKT_BIND_ACK;
637 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
638 pkt.u.bind_ack.max_xmit_frag = 0x2000;
639 pkt.u.bind_ack.max_recv_frag = 0x2000;
640 /* we need to send a non zero assoc_group_id here to make longhorn happy, it also matches samba3 */
641 pkt.u.bind_ack.assoc_group_id = SAMBA_ACCOC_GROUP;
642 if (iface) {
643 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
644 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
645 } else {
646 pkt.u.bind_ack.secondary_address = "";
648 pkt.u.bind_ack.num_results = 1;
649 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
650 if (!pkt.u.bind_ack.ctx_list) {
651 return NT_STATUS_NO_MEMORY;
653 pkt.u.bind_ack.ctx_list[0].result = result;
654 pkt.u.bind_ack.ctx_list[0].reason = reason;
655 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
656 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
658 status = dcesrv_auth_bind_ack(call, &pkt);
659 if (!NT_STATUS_IS_OK(status)) {
660 return dcesrv_bind_nak(call, 0);
663 if (iface) {
664 status = iface->bind(call, iface);
665 if (!NT_STATUS_IS_OK(status)) {
666 char *uuid_str = GUID_string(call, &uuid);
667 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
668 uuid_str, if_version, nt_errstr(status)));
669 talloc_free(uuid_str);
670 return dcesrv_bind_nak(call, 0);
674 rep = talloc(call, struct data_blob_list_item);
675 if (!rep) {
676 return NT_STATUS_NO_MEMORY;
679 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
680 if (!NT_STATUS_IS_OK(status)) {
681 return status;
684 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
686 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
687 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
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->private = NULL;
750 context->handles = NULL;
751 DLIST_ADD(call->conn->contexts, context);
752 call->context = context;
754 if (iface) {
755 status = iface->bind(call, iface);
756 if (!NT_STATUS_IS_OK(status)) {
757 return status;
761 return NT_STATUS_OK;
766 handle a alter context request
768 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
770 struct ncacn_packet pkt;
771 struct data_blob_list_item *rep;
772 NTSTATUS status;
773 uint32_t result=0, reason=0;
774 uint32_t context_id;
776 /* handle any authentication that is being requested */
777 if (!dcesrv_auth_alter(call)) {
778 /* TODO: work out the right reject code */
779 result = DCERPC_BIND_PROVIDER_REJECT;
780 reason = DCERPC_BIND_REASON_ASYNTAX;
783 context_id = call->pkt.u.alter.ctx_list[0].context_id;
785 /* see if they are asking for a new interface */
786 if (result == 0 &&
787 dcesrv_find_context(call->conn, context_id) == NULL) {
788 status = dcesrv_alter_new_context(call, context_id);
789 if (!NT_STATUS_IS_OK(status)) {
790 result = DCERPC_BIND_PROVIDER_REJECT;
791 reason = DCERPC_BIND_REASON_ASYNTAX;
795 /* setup a alter_resp */
796 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
797 pkt.auth_length = 0;
798 pkt.call_id = call->pkt.call_id;
799 pkt.ptype = DCERPC_PKT_ALTER_RESP;
800 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
801 pkt.u.alter_resp.max_xmit_frag = 0x2000;
802 pkt.u.alter_resp.max_recv_frag = 0x2000;
803 pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
804 pkt.u.alter_resp.num_results = 1;
805 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
806 if (!pkt.u.alter_resp.ctx_list) {
807 return NT_STATUS_NO_MEMORY;
809 pkt.u.alter_resp.ctx_list[0].result = result;
810 pkt.u.alter_resp.ctx_list[0].reason = reason;
811 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
812 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
813 pkt.u.alter_resp.secondary_address = "";
815 status = dcesrv_auth_alter_ack(call, &pkt);
816 if (!NT_STATUS_IS_OK(status)) {
817 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
818 || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
819 || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
820 || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
821 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
823 return dcesrv_fault(call, 0);
826 rep = talloc(call, struct data_blob_list_item);
827 if (!rep) {
828 return NT_STATUS_NO_MEMORY;
831 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
832 if (!NT_STATUS_IS_OK(status)) {
833 return status;
836 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
838 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
839 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
841 return NT_STATUS_OK;
845 handle a dcerpc request packet
847 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
849 struct ndr_pull *pull;
850 NTSTATUS status;
851 struct dcesrv_connection_context *context;
853 /* if authenticated, and the mech we use can't do async replies, don't use them... */
854 if (call->conn->auth_state.gensec_security &&
855 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
856 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
859 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
860 if (context == NULL) {
861 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
864 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call,
865 lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
866 NT_STATUS_HAVE_NO_MEMORY(pull);
868 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
870 call->context = context;
871 call->ndr_pull = pull;
873 if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
874 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
877 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
878 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
881 /* unravel the NDR for the packet */
882 status = context->iface->ndr_pull(call, call, pull, &call->r);
883 if (!NT_STATUS_IS_OK(status)) {
884 return dcesrv_fault(call, call->fault_code);
887 if (pull->offset != pull->data_size) {
888 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
889 pull->data_size - pull->offset));
890 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
893 /* call the dispatch function */
894 status = context->iface->dispatch(call, call, call->r);
895 if (!NT_STATUS_IS_OK(status)) {
896 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
897 context->iface->name,
898 call->pkt.u.request.opnum,
899 dcerpc_errstr(pull, call->fault_code)));
900 return dcesrv_fault(call, call->fault_code);
903 /* add the call to the pending list */
904 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
906 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
907 return NT_STATUS_OK;
910 return dcesrv_reply(call);
913 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
915 struct ndr_push *push;
916 NTSTATUS status;
917 DATA_BLOB stub;
918 uint32_t total_length, chunk_size;
919 struct dcesrv_connection_context *context = call->context;
920 size_t sig_size = 0;
922 /* call the reply function */
923 status = context->iface->reply(call, call, call->r);
924 if (!NT_STATUS_IS_OK(status)) {
925 return dcesrv_fault(call, call->fault_code);
928 /* form the reply NDR */
929 push = ndr_push_init_ctx(call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
930 NT_STATUS_HAVE_NO_MEMORY(push);
932 /* carry over the pointer count to the reply in case we are
933 using full pointer. See NDR specification for full
934 pointers */
935 push->ptr_count = call->ndr_pull->ptr_count;
937 if (lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
938 push->flags |= LIBNDR_FLAG_BIGENDIAN;
941 status = context->iface->ndr_push(call, call, push, call->r);
942 if (!NT_STATUS_IS_OK(status)) {
943 return dcesrv_fault(call, call->fault_code);
946 stub = ndr_push_blob(push);
948 total_length = stub.length;
950 /* we can write a full max_recv_frag size, minus the dcerpc
951 request header size */
952 chunk_size = call->conn->cli_max_recv_frag;
953 chunk_size -= DCERPC_REQUEST_LENGTH;
954 if (call->conn->auth_state.auth_info &&
955 call->conn->auth_state.gensec_security) {
956 sig_size = gensec_sig_size(call->conn->auth_state.gensec_security,
957 call->conn->cli_max_recv_frag);
958 if (sig_size) {
959 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
960 chunk_size -= sig_size;
963 chunk_size -= (chunk_size % 16);
965 do {
966 uint32_t length;
967 struct data_blob_list_item *rep;
968 struct ncacn_packet pkt;
970 rep = talloc(call, struct data_blob_list_item);
971 NT_STATUS_HAVE_NO_MEMORY(rep);
973 length = MIN(chunk_size, stub.length);
975 /* form the dcerpc response packet */
976 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
977 pkt.auth_length = 0;
978 pkt.call_id = call->pkt.call_id;
979 pkt.ptype = DCERPC_PKT_RESPONSE;
980 pkt.pfc_flags = 0;
981 if (stub.length == total_length) {
982 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
984 if (length == stub.length) {
985 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
987 pkt.u.response.alloc_hint = stub.length;
988 pkt.u.response.context_id = call->pkt.u.request.context_id;
989 pkt.u.response.cancel_count = 0;
990 pkt.u.response.stub_and_verifier.data = stub.data;
991 pkt.u.response.stub_and_verifier.length = length;
993 if (!dcesrv_auth_response(call, &rep->blob, sig_size, &pkt)) {
994 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
997 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
999 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
1001 stub.data += length;
1002 stub.length -= length;
1003 } while (stub.length != 0);
1005 /* move the call from the pending to the finished calls list */
1006 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
1008 if (call->conn->call_list && call->conn->call_list->replies) {
1009 if (call->conn->transport.report_output_data) {
1010 call->conn->transport.report_output_data(call->conn);
1014 return NT_STATUS_OK;
1017 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1019 if (!conn->transport.get_my_addr) {
1020 return NULL;
1023 return conn->transport.get_my_addr(conn, mem_ctx);
1026 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1028 if (!conn->transport.get_peer_addr) {
1029 return NULL;
1032 return conn->transport.get_peer_addr(conn, mem_ctx);
1036 work out if we have a full packet yet
1038 static bool dce_full_packet(const DATA_BLOB *data)
1040 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
1041 return false;
1043 if (dcerpc_get_frag_length(data) > data->length) {
1044 return false;
1046 return true;
1050 we might have consumed only part of our input - advance past that part
1052 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
1054 DATA_BLOB blob;
1056 if (dce_conn->partial_input.length == offset) {
1057 data_blob_free(&dce_conn->partial_input);
1058 return;
1061 blob = dce_conn->partial_input;
1062 dce_conn->partial_input = data_blob(blob.data + offset,
1063 blob.length - offset);
1064 data_blob_free(&blob);
1068 remove the call from the right list when freed
1070 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1072 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1073 return 0;
1077 process some input to a dcerpc endpoint server.
1079 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
1081 struct ndr_pull *ndr;
1082 enum ndr_err_code ndr_err;
1083 NTSTATUS status;
1084 struct dcesrv_call_state *call;
1085 DATA_BLOB blob;
1087 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1088 if (!call) {
1089 talloc_free(dce_conn->partial_input.data);
1090 return NT_STATUS_NO_MEMORY;
1092 call->conn = dce_conn;
1093 call->event_ctx = dce_conn->event_ctx;
1094 call->msg_ctx = dce_conn->msg_ctx;
1095 call->state_flags = call->conn->state_flags;
1096 call->time = timeval_current();
1097 call->list = DCESRV_LIST_NONE;
1099 talloc_set_destructor(call, dcesrv_call_dequeue);
1101 blob = dce_conn->partial_input;
1102 blob.length = dcerpc_get_frag_length(&blob);
1104 ndr = ndr_pull_init_blob(&blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
1105 if (!ndr) {
1106 talloc_free(dce_conn->partial_input.data);
1107 talloc_free(call);
1108 return NT_STATUS_NO_MEMORY;
1111 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
1112 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
1115 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
1116 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1117 talloc_free(dce_conn->partial_input.data);
1118 talloc_free(call);
1119 return ndr_map_error2ntstatus(ndr_err);
1122 /* we have to check the signing here, before combining the
1123 pdus */
1124 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1125 !dcesrv_auth_request(call, &blob)) {
1126 dce_partial_advance(dce_conn, blob.length);
1127 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1130 dce_partial_advance(dce_conn, blob.length);
1132 /* see if this is a continued packet */
1133 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1134 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1135 struct dcesrv_call_state *call2 = call;
1136 uint32_t alloc_size;
1138 /* we only allow fragmented requests, no other packet types */
1139 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1140 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1143 /* this is a continuation of an existing call - find the call then
1144 tack it on the end */
1145 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1146 if (!call) {
1147 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1150 if (call->pkt.ptype != call2->pkt.ptype) {
1151 /* trying to play silly buggers are we? */
1152 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1155 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1156 call2->pkt.u.request.stub_and_verifier.length;
1157 if (call->pkt.u.request.alloc_hint > alloc_size) {
1158 alloc_size = call->pkt.u.request.alloc_hint;
1161 call->pkt.u.request.stub_and_verifier.data =
1162 talloc_realloc(call,
1163 call->pkt.u.request.stub_and_verifier.data,
1164 uint8_t, alloc_size);
1165 if (!call->pkt.u.request.stub_and_verifier.data) {
1166 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1168 memcpy(call->pkt.u.request.stub_and_verifier.data +
1169 call->pkt.u.request.stub_and_verifier.length,
1170 call2->pkt.u.request.stub_and_verifier.data,
1171 call2->pkt.u.request.stub_and_verifier.length);
1172 call->pkt.u.request.stub_and_verifier.length +=
1173 call2->pkt.u.request.stub_and_verifier.length;
1175 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1177 talloc_free(call2);
1180 /* this may not be the last pdu in the chain - if its isn't then
1181 just put it on the incoming_fragmented_call_list and wait for the rest */
1182 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1183 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1184 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1185 return NT_STATUS_OK;
1188 /* This removes any fragments we may have had stashed away */
1189 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1191 switch (call->pkt.ptype) {
1192 case DCERPC_PKT_BIND:
1193 status = dcesrv_bind(call);
1194 break;
1195 case DCERPC_PKT_AUTH3:
1196 status = dcesrv_auth3(call);
1197 break;
1198 case DCERPC_PKT_ALTER:
1199 status = dcesrv_alter(call);
1200 break;
1201 case DCERPC_PKT_REQUEST:
1202 status = dcesrv_request(call);
1203 break;
1204 default:
1205 status = NT_STATUS_INVALID_PARAMETER;
1206 break;
1209 /* if we are going to be sending a reply then add
1210 it to the list of pending calls. We add it to the end to keep the call
1211 list in the order we will answer */
1212 if (!NT_STATUS_IS_OK(status)) {
1213 talloc_free(call);
1216 return status;
1221 provide some input to a dcerpc endpoint server. This passes data
1222 from a dcerpc client into the server
1224 _PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1226 NTSTATUS status;
1228 dce_conn->partial_input.data = talloc_realloc(dce_conn,
1229 dce_conn->partial_input.data,
1230 uint8_t,
1231 dce_conn->partial_input.length + data->length);
1232 if (!dce_conn->partial_input.data) {
1233 return NT_STATUS_NO_MEMORY;
1235 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1236 data->data, data->length);
1237 dce_conn->partial_input.length += data->length;
1239 while (dce_full_packet(&dce_conn->partial_input)) {
1240 status = dcesrv_input_process(dce_conn);
1241 if (!NT_STATUS_IS_OK(status)) {
1242 return status;
1246 return NT_STATUS_OK;
1250 retrieve some output from a dcerpc server
1251 The caller supplies a function that will be called to do the
1252 actual output.
1254 The first argument to write_fn() will be 'private', the second will
1255 be a pointer to a buffer containing the data to be sent and the 3rd
1256 will be a pointer to a size_t variable that will be set to the
1257 number of bytes that are consumed from the output.
1259 from the current fragment
1261 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
1262 void *private_data,
1263 NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1265 NTSTATUS status;
1266 struct dcesrv_call_state *call;
1267 struct data_blob_list_item *rep;
1268 size_t nwritten;
1270 call = dce_conn->call_list;
1271 if (!call || !call->replies) {
1272 if (dce_conn->pending_call_list) {
1273 /* TODO: we need to say act async here
1274 * as we know we have pending requests
1275 * which will be finished at a time
1277 return NT_STATUS_FOOBAR;
1279 return NT_STATUS_FOOBAR;
1281 rep = call->replies;
1283 status = write_fn(private_data, &rep->blob, &nwritten);
1284 NT_STATUS_IS_ERR_RETURN(status);
1286 rep->blob.length -= nwritten;
1287 rep->blob.data += nwritten;
1289 if (rep->blob.length == 0) {
1290 /* we're done with this section of the call */
1291 DLIST_REMOVE(call->replies, rep);
1294 if (call->replies == NULL) {
1295 /* we're done with the whole call */
1296 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1297 talloc_free(call);
1300 return status;
1303 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1304 struct loadparm_context *lp_ctx,
1305 const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1307 NTSTATUS status;
1308 struct dcesrv_context *dce_ctx;
1309 int i;
1311 if (!endpoint_servers) {
1312 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1313 return NT_STATUS_INTERNAL_ERROR;
1316 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1317 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1318 dce_ctx->endpoint_list = NULL;
1319 dce_ctx->lp_ctx = lp_ctx;
1321 for (i=0;endpoint_servers[i];i++) {
1322 const struct dcesrv_endpoint_server *ep_server;
1324 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1325 if (!ep_server) {
1326 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1327 return NT_STATUS_INTERNAL_ERROR;
1330 status = ep_server->init_server(dce_ctx, ep_server);
1331 if (!NT_STATUS_IS_OK(status)) {
1332 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1333 nt_errstr(status)));
1334 return status;
1338 *_dce_ctx = dce_ctx;
1339 return NT_STATUS_OK;
1342 /* the list of currently registered DCERPC endpoint servers.
1344 static struct ep_server {
1345 struct dcesrv_endpoint_server *ep_server;
1346 } *ep_servers = NULL;
1347 static int num_ep_servers;
1350 register a DCERPC endpoint server.
1352 The 'name' can be later used by other backends to find the operations
1353 structure for this backend.
1355 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1357 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1359 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1361 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1362 /* its already registered! */
1363 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1364 ep_server->name));
1365 return NT_STATUS_OBJECT_NAME_COLLISION;
1368 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1369 if (!ep_servers) {
1370 smb_panic("out of memory in dcerpc_register");
1373 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1374 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1376 num_ep_servers++;
1378 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1379 ep_server->name));
1381 return NT_STATUS_OK;
1385 return the operations structure for a named backend of the specified type
1387 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1389 int i;
1391 for (i=0;i<num_ep_servers;i++) {
1392 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1393 return ep_servers[i].ep_server;
1397 return NULL;
1401 return the DCERPC module version, and the size of some critical types
1402 This can be used by endpoint server modules to either detect compilation errors, or provide
1403 multiple implementations for different smbd compilation options in one module
1405 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1407 static const struct dcesrv_critical_sizes critical_sizes = {
1408 DCERPC_MODULE_VERSION,
1409 sizeof(struct dcesrv_context),
1410 sizeof(struct dcesrv_endpoint),
1411 sizeof(struct dcesrv_endpoint_server),
1412 sizeof(struct dcesrv_interface),
1413 sizeof(struct dcesrv_if_list),
1414 sizeof(struct dcesrv_connection),
1415 sizeof(struct dcesrv_call_state),
1416 sizeof(struct dcesrv_auth),
1417 sizeof(struct dcesrv_handle)
1420 return &critical_sizes;
1424 initialise the dcerpc server context for ncacn_np based services
1426 _PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
1427 struct dcesrv_context **_dce_ctx)
1429 NTSTATUS status;
1430 struct dcesrv_context *dce_ctx;
1432 status = dcesrv_init_context(mem_ctx, lp_ctx, lp_dcerpc_endpoint_servers(lp_ctx), &dce_ctx);
1433 NT_STATUS_NOT_OK_RETURN(status);
1435 *_dce_ctx = dce_ctx;
1436 return NT_STATUS_OK;