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/>.
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) {
53
if (!ep1->endpoint || !ep2->endpoint) {
54
return ep1->endpoint == ep2->endpoint;
57
if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
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)) {
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,
84
struct dcesrv_connection_context *c;
85
for (c=conn->contexts;c;c=c->next) {
86
if (c->context_id == context_id) return c;
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);
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);
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) {
156
register an interface on an endpoint
158
_PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
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;
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));
176
/* check if this endpoint exists
178
if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
179
ep = talloc(dce_ctx, struct dcesrv_endpoint);
181
return NT_STATUS_NO_MEMORY;
184
ep->ep_description = talloc_reference(ep, binding);
187
/* add mgmt interface */
188
ifl = talloc(dce_ctx, struct dcesrv_if_list);
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);
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
219
/* if there's currently no security descriptor given on the endpoint
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);
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 */
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));
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;
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;
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)) {
286
session_key->length = MIN(session_key->length, 16);
292
connect to a dcerpc endpoint
294
_PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_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;
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)) {
315
return NT_STATUS_NO_MEMORY;
318
p->dce_ctx = dce_ctx;
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);
343
search and connect to a dcerpc endpoint
345
_PUBLIC_ NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
347
const struct dcerpc_binding *ep_description,
348
struct auth_session_info *session_info,
349
struct tevent_context *event_ctx,
350
struct messaging_context *msg_ctx,
351
struct server_id server_id,
352
uint32_t state_flags,
353
struct dcesrv_connection **dce_conn_p)
356
const struct dcesrv_endpoint *ep;
358
/* make sure this endpoint exists */
359
ep = find_endpoint(dce_ctx, ep_description);
361
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
364
status = dcesrv_endpoint_connect(dce_ctx, mem_ctx, ep, session_info,
365
event_ctx, msg_ctx, server_id,
366
state_flags, dce_conn_p);
367
NT_STATUS_NOT_OK_RETURN(status);
369
(*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
371
/* TODO: check security descriptor of the endpoint here
372
* if it's a smb named pipe
373
* if it's failed free dce_conn_p
380
static void dcesrv_init_hdr(struct ncacn_packet *pkt, bool bigendian)
383
pkt->rpc_vers_minor = 0;
387
pkt->drep[0] = DCERPC_DREP_LE;
395
move a call from an existing linked list to the specified list. This
396
prevents bugs where we forget to remove the call from a previous
399
static void dcesrv_call_set_list(struct dcesrv_call_state *call,
400
enum dcesrv_call_list list)
402
switch (call->list) {
403
case DCESRV_LIST_NONE:
405
case DCESRV_LIST_CALL_LIST:
406
DLIST_REMOVE(call->conn->call_list, call);
408
case DCESRV_LIST_FRAGMENTED_CALL_LIST:
409
DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
411
case DCESRV_LIST_PENDING_CALL_LIST:
412
DLIST_REMOVE(call->conn->pending_call_list, call);
417
case DCESRV_LIST_NONE:
419
case DCESRV_LIST_CALL_LIST:
420
DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
422
case DCESRV_LIST_FRAGMENTED_CALL_LIST:
423
DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
425
case DCESRV_LIST_PENDING_CALL_LIST:
426
DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
432
return a dcerpc fault
434
static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
436
struct ncacn_packet pkt;
437
struct data_blob_list_item *rep;
441
/* setup a bind_ack */
442
dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
444
pkt.call_id = call->pkt.call_id;
445
pkt.ptype = DCERPC_PKT_FAULT;
446
pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
447
pkt.u.fault.alloc_hint = 0;
448
pkt.u.fault.context_id = 0;
449
pkt.u.fault.cancel_count = 0;
450
pkt.u.fault.status = fault_code;
453
pkt.u.fault._pad = data_blob_const(zeros, sizeof(zeros));
455
rep = talloc(call, struct data_blob_list_item);
457
return NT_STATUS_NO_MEMORY;
460
status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
461
if (!NT_STATUS_IS_OK(status)) {
465
dcerpc_set_frag_length(&rep->blob, rep->blob.length);
467
DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
468
dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
475
return a dcerpc bind_nak
477
static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
479
struct ncacn_packet pkt;
480
struct data_blob_list_item *rep;
483
/* setup a bind_nak */
484
dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
486
pkt.call_id = call->pkt.call_id;
487
pkt.ptype = DCERPC_PKT_BIND_NAK;
488
pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
489
pkt.u.bind_nak.reject_reason = reason;
490
if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
491
pkt.u.bind_nak.versions.v.num_versions = 0;
494
rep = talloc(call, struct data_blob_list_item);
496
return NT_STATUS_NO_MEMORY;
499
status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
500
if (!NT_STATUS_IS_OK(status)) {
504
dcerpc_set_frag_length(&rep->blob, rep->blob.length);
506
DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
507
dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
512
static int dcesrv_connection_context_destructor(struct dcesrv_connection_context *c)
514
DLIST_REMOVE(c->conn->contexts, c);
517
c->iface->unbind(c, c->iface);
524
handle a bind request
526
static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
528
uint32_t if_version, transfer_syntax_version;
529
struct GUID uuid, *transfer_syntax_uuid;
530
struct ncacn_packet pkt;
531
struct data_blob_list_item *rep;
533
uint32_t result=0, reason=0;
535
const struct dcesrv_interface *iface;
536
uint32_t extra_flags = 0;
539
* Association groups allow policy handles to be shared across
540
* multiple client connections. We don't implement this yet.
542
* So we just allow 0 if the client wants to create a new
545
* And we allow the 0x12345678 value, we give away as
546
* assoc_group_id back to the clients
548
if (call->pkt.u.bind.assoc_group_id != 0 &&
549
lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
550
call->pkt.u.bind.assoc_group_id != SAMBA_ASSOC_GROUP) {
551
return dcesrv_bind_nak(call, 0);
554
if (call->pkt.u.bind.num_contexts < 1 ||
555
call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
556
return dcesrv_bind_nak(call, 0);
559
context_id = call->pkt.u.bind.ctx_list[0].context_id;
561
/* you can't bind twice on one context */
562
if (dcesrv_find_context(call->conn, context_id) != NULL) {
563
return dcesrv_bind_nak(call, 0);
566
if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
567
uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
569
transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
570
transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
571
if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
572
ndr_transfer_syntax.if_version != transfer_syntax_version) {
573
char *uuid_str = GUID_string(call, transfer_syntax_uuid);
574
/* we only do NDR encoded dcerpc */
575
DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
576
talloc_free(uuid_str);
577
return dcesrv_bind_nak(call, 0);
580
iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
582
char *uuid_str = GUID_string(call, &uuid);
583
DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
584
talloc_free(uuid_str);
586
/* we don't know about that interface */
587
result = DCERPC_BIND_PROVIDER_REJECT;
588
reason = DCERPC_BIND_REASON_ASYNTAX;
592
/* add this context to the list of available context_ids */
593
struct dcesrv_connection_context *context = talloc(call->conn,
594
struct dcesrv_connection_context);
595
if (context == NULL) {
596
return dcesrv_bind_nak(call, 0);
598
context->conn = call->conn;
599
context->iface = iface;
600
context->context_id = context_id;
602
* we need to send a non zero assoc_group_id here to make longhorn happy,
603
* it also matches samba3
605
context->assoc_group_id = SAMBA_ASSOC_GROUP;
606
context->private_data = NULL;
607
context->handles = NULL;
608
DLIST_ADD(call->conn->contexts, context);
609
call->context = context;
610
talloc_set_destructor(context, dcesrv_connection_context_destructor);
612
status = iface->bind(call, iface);
613
if (!NT_STATUS_IS_OK(status)) {
614
char *uuid_str = GUID_string(call, &uuid);
615
DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
616
uuid_str, if_version, nt_errstr(status)));
617
talloc_free(uuid_str);
618
/* we don't want to trigger the iface->unbind() hook */
619
context->iface = NULL;
620
talloc_free(call->context);
621
call->context = NULL;
622
return dcesrv_bind_nak(call, 0);
626
if (call->conn->cli_max_recv_frag == 0) {
627
call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
630
if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) &&
631
lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","header signing", false)) {
632
call->conn->state_flags |= DCESRV_CALL_STATE_FLAG_HEADER_SIGNING;
633
extra_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
636
/* handle any authentication that is being requested */
637
if (!dcesrv_auth_bind(call)) {
638
talloc_free(call->context);
639
call->context = NULL;
640
return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
643
/* setup a bind_ack */
644
dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
646
pkt.call_id = call->pkt.call_id;
647
pkt.ptype = DCERPC_PKT_BIND_ACK;
648
pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
649
pkt.u.bind_ack.max_xmit_frag = 0x2000;
650
pkt.u.bind_ack.max_recv_frag = 0x2000;
653
make it possible for iface->bind() to specify the assoc_group_id
654
This helps the openchange mapiproxy plugin to work correctly.
659
pkt.u.bind_ack.assoc_group_id = call->context->assoc_group_id;
661
/* we better pick something - this chosen so as to send a non zero assoc_group_id (matching windows), it also matches samba3 */
662
pkt.u.bind_ack.assoc_group_id = SAMBA_ASSOC_GROUP;
666
/* FIXME: Use pipe name as specified by endpoint instead of interface name */
667
pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
669
pkt.u.bind_ack.secondary_address = "";
671
pkt.u.bind_ack.num_results = 1;
672
pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
673
if (!pkt.u.bind_ack.ctx_list) {
674
talloc_free(call->context);
675
call->context = NULL;
676
return NT_STATUS_NO_MEMORY;
678
pkt.u.bind_ack.ctx_list[0].result = result;
679
pkt.u.bind_ack.ctx_list[0].reason = reason;
680
pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
681
pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
683
status = dcesrv_auth_bind_ack(call, &pkt);
684
if (!NT_STATUS_IS_OK(status)) {
685
talloc_free(call->context);
686
call->context = NULL;
687
return dcesrv_bind_nak(call, 0);
690
rep = talloc(call, struct data_blob_list_item);
692
talloc_free(call->context);
693
call->context = NULL;
694
return NT_STATUS_NO_MEMORY;
697
status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
698
if (!NT_STATUS_IS_OK(status)) {
699
talloc_free(call->context);
700
call->context = NULL;
704
dcerpc_set_frag_length(&rep->blob, rep->blob.length);
706
DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
707
dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
714
handle a auth3 request
716
static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
718
/* handle the auth3 in the auth code */
719
if (!dcesrv_auth_auth3(call)) {
720
return dcesrv_fault(call, DCERPC_FAULT_OTHER);
725
/* we don't send a reply to a auth3 request, except by a
732
handle a bind request
734
static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
736
uint32_t if_version, transfer_syntax_version;
737
struct dcesrv_connection_context *context;
738
const struct dcesrv_interface *iface;
739
struct GUID uuid, *transfer_syntax_uuid;
742
if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
743
uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
745
transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
746
transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
747
if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
748
ndr_transfer_syntax.if_version != transfer_syntax_version) {
749
/* we only do NDR encoded dcerpc */
750
return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
753
iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
755
char *uuid_str = GUID_string(call, &uuid);
756
DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
757
talloc_free(uuid_str);
758
return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
761
/* add this context to the list of available context_ids */
762
context = talloc(call->conn, struct dcesrv_connection_context);
763
if (context == NULL) {
764
return NT_STATUS_NO_MEMORY;
766
context->conn = call->conn;
767
context->iface = iface;
768
context->context_id = context_id;
769
context->assoc_group_id = SAMBA_ASSOC_GROUP;
770
context->private_data = NULL;
771
context->handles = NULL;
772
DLIST_ADD(call->conn->contexts, context);
773
call->context = context;
774
talloc_set_destructor(context, dcesrv_connection_context_destructor);
776
status = iface->bind(call, iface);
777
if (!NT_STATUS_IS_OK(status)) {
778
/* we don't want to trigger the iface->unbind() hook */
779
context->iface = NULL;
780
talloc_free(context);
781
call->context = NULL;
790
handle a alter context request
792
static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
794
struct ncacn_packet pkt;
795
struct data_blob_list_item *rep;
797
uint32_t result=0, reason=0;
800
/* handle any authentication that is being requested */
801
if (!dcesrv_auth_alter(call)) {
802
/* TODO: work out the right reject code */
803
result = DCERPC_BIND_PROVIDER_REJECT;
804
reason = DCERPC_BIND_REASON_ASYNTAX;
807
context_id = call->pkt.u.alter.ctx_list[0].context_id;
809
/* see if they are asking for a new interface */
811
call->context = dcesrv_find_context(call->conn, context_id);
812
if (!call->context) {
813
status = dcesrv_alter_new_context(call, context_id);
814
if (!NT_STATUS_IS_OK(status)) {
815
result = DCERPC_BIND_PROVIDER_REJECT;
816
reason = DCERPC_BIND_REASON_ASYNTAX;
822
call->pkt.u.alter.assoc_group_id != 0 &&
823
lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
824
call->pkt.u.alter.assoc_group_id != call->context->assoc_group_id) {
825
/* TODO: work out what to return here */
826
result = DCERPC_BIND_PROVIDER_REJECT;
827
reason = DCERPC_BIND_REASON_ASYNTAX;
830
/* setup a alter_resp */
831
dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
833
pkt.call_id = call->pkt.call_id;
834
pkt.ptype = DCERPC_PKT_ALTER_RESP;
835
pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
836
pkt.u.alter_resp.max_xmit_frag = 0x2000;
837
pkt.u.alter_resp.max_recv_frag = 0x2000;
839
pkt.u.alter_resp.assoc_group_id = call->context->assoc_group_id;
841
pkt.u.alter_resp.assoc_group_id = 0;
843
pkt.u.alter_resp.num_results = 1;
844
pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
845
if (!pkt.u.alter_resp.ctx_list) {
846
return NT_STATUS_NO_MEMORY;
848
pkt.u.alter_resp.ctx_list[0].result = result;
849
pkt.u.alter_resp.ctx_list[0].reason = reason;
850
pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
851
pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
852
pkt.u.alter_resp.secondary_address = "";
854
status = dcesrv_auth_alter_ack(call, &pkt);
855
if (!NT_STATUS_IS_OK(status)) {
856
if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
857
|| NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
858
|| NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
859
|| NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
860
return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
862
return dcesrv_fault(call, 0);
865
rep = talloc(call, struct data_blob_list_item);
867
return NT_STATUS_NO_MEMORY;
870
status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
871
if (!NT_STATUS_IS_OK(status)) {
875
dcerpc_set_frag_length(&rep->blob, rep->blob.length);
877
DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
878
dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
884
handle a dcerpc request packet
886
static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
888
struct ndr_pull *pull;
890
struct dcesrv_connection_context *context;
892
/* if authenticated, and the mech we use can't do async replies, don't use them... */
893
if (call->conn->auth_state.gensec_security &&
894
!gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
895
call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
898
context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
899
if (context == NULL) {
900
return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
903
pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call,
904
lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
905
NT_STATUS_HAVE_NO_MEMORY(pull);
907
pull->flags |= LIBNDR_FLAG_REF_ALLOC;
909
call->context = context;
910
call->ndr_pull = pull;
912
if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
913
pull->flags |= LIBNDR_FLAG_BIGENDIAN;
916
/* unravel the NDR for the packet */
917
status = context->iface->ndr_pull(call, call, pull, &call->r);
918
if (!NT_STATUS_IS_OK(status)) {
919
return dcesrv_fault(call, call->fault_code);
922
if (pull->offset != pull->data_size) {
923
DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
924
pull->data_size - pull->offset));
925
dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
928
/* call the dispatch function */
929
status = context->iface->dispatch(call, call, call->r);
930
if (!NT_STATUS_IS_OK(status)) {
931
DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
932
context->iface->name,
933
call->pkt.u.request.opnum,
934
dcerpc_errstr(pull, call->fault_code)));
935
return dcesrv_fault(call, call->fault_code);
938
/* add the call to the pending list */
939
dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
941
if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
945
return dcesrv_reply(call);
948
_PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
950
struct ndr_push *push;
953
uint32_t total_length, chunk_size;
954
struct dcesrv_connection_context *context = call->context;
957
/* call the reply function */
958
status = context->iface->reply(call, call, call->r);
959
if (!NT_STATUS_IS_OK(status)) {
960
return dcesrv_fault(call, call->fault_code);
963
/* form the reply NDR */
964
push = ndr_push_init_ctx(call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
965
NT_STATUS_HAVE_NO_MEMORY(push);
967
/* carry over the pointer count to the reply in case we are
968
using full pointer. See NDR specification for full
970
push->ptr_count = call->ndr_pull->ptr_count;
972
if (lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
973
push->flags |= LIBNDR_FLAG_BIGENDIAN;
976
status = context->iface->ndr_push(call, call, push, call->r);
977
if (!NT_STATUS_IS_OK(status)) {
978
return dcesrv_fault(call, call->fault_code);
981
stub = ndr_push_blob(push);
983
total_length = stub.length;
985
/* we can write a full max_recv_frag size, minus the dcerpc
986
request header size */
987
chunk_size = call->conn->cli_max_recv_frag;
988
chunk_size -= DCERPC_REQUEST_LENGTH;
989
if (call->conn->auth_state.auth_info &&
990
call->conn->auth_state.gensec_security) {
991
sig_size = gensec_sig_size(call->conn->auth_state.gensec_security,
992
call->conn->cli_max_recv_frag);
994
chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
995
chunk_size -= sig_size;
998
chunk_size -= (chunk_size % 16);
1002
struct data_blob_list_item *rep;
1003
struct ncacn_packet pkt;
1005
rep = talloc(call, struct data_blob_list_item);
1006
NT_STATUS_HAVE_NO_MEMORY(rep);
1008
length = MIN(chunk_size, stub.length);
1010
/* form the dcerpc response packet */
1011
dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
1012
pkt.auth_length = 0;
1013
pkt.call_id = call->pkt.call_id;
1014
pkt.ptype = DCERPC_PKT_RESPONSE;
1016
if (stub.length == total_length) {
1017
pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1019
if (length == stub.length) {
1020
pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1022
pkt.u.response.alloc_hint = stub.length;
1023
pkt.u.response.context_id = call->pkt.u.request.context_id;
1024
pkt.u.response.cancel_count = 0;
1025
pkt.u.response.stub_and_verifier.data = stub.data;
1026
pkt.u.response.stub_and_verifier.length = length;
1028
if (!dcesrv_auth_response(call, &rep->blob, sig_size, &pkt)) {
1029
return dcesrv_fault(call, DCERPC_FAULT_OTHER);
1032
dcerpc_set_frag_length(&rep->blob, rep->blob.length);
1034
DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
1036
stub.data += length;
1037
stub.length -= length;
1038
} while (stub.length != 0);
1040
/* move the call from the pending to the finished calls list */
1041
dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
1043
if (call->conn->call_list && call->conn->call_list->replies) {
1044
if (call->conn->transport.report_output_data) {
1045
call->conn->transport.report_output_data(call->conn);
1049
return NT_STATUS_OK;
1052
_PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1054
if (!conn->transport.get_my_addr) {
1058
return conn->transport.get_my_addr(conn, mem_ctx);
1061
_PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1063
if (!conn->transport.get_peer_addr) {
1067
return conn->transport.get_peer_addr(conn, mem_ctx);
1071
work out if we have a full packet yet
1073
static bool dce_full_packet(const DATA_BLOB *data)
1075
if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
1078
if (dcerpc_get_frag_length(data) > data->length) {
1085
we might have consumed only part of our input - advance past that part
1087
static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
1091
if (dce_conn->partial_input.length == offset) {
1092
data_blob_free(&dce_conn->partial_input);
1096
blob = dce_conn->partial_input;
1097
dce_conn->partial_input = data_blob(blob.data + offset,
1098
blob.length - offset);
1099
data_blob_free(&blob);
1103
remove the call from the right list when freed
1105
static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1107
dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1112
process some input to a dcerpc endpoint server.
1114
NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
1116
struct ndr_pull *ndr;
1117
enum ndr_err_code ndr_err;
1119
struct dcesrv_call_state *call;
1122
call = talloc_zero(dce_conn, struct dcesrv_call_state);
1124
talloc_free(dce_conn->partial_input.data);
1125
return NT_STATUS_NO_MEMORY;
1127
call->conn = dce_conn;
1128
call->event_ctx = dce_conn->event_ctx;
1129
call->msg_ctx = dce_conn->msg_ctx;
1130
call->state_flags = call->conn->state_flags;
1131
call->time = timeval_current();
1132
call->list = DCESRV_LIST_NONE;
1134
talloc_set_destructor(call, dcesrv_call_dequeue);
1136
blob = dce_conn->partial_input;
1137
blob.length = dcerpc_get_frag_length(&blob);
1139
ndr = ndr_pull_init_blob(&blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
1141
talloc_free(dce_conn->partial_input.data);
1143
return NT_STATUS_NO_MEMORY;
1146
if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
1147
ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
1150
if (CVAL(blob.data, DCERPC_PFC_OFFSET) & DCERPC_PFC_FLAG_OBJECT_UUID) {
1151
ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
1154
ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
1155
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1156
talloc_free(dce_conn->partial_input.data);
1158
return ndr_map_error2ntstatus(ndr_err);
1161
/* we have to check the signing here, before combining the
1163
if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1164
!dcesrv_auth_request(call, &blob)) {
1165
dce_partial_advance(dce_conn, blob.length);
1166
return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1169
dce_partial_advance(dce_conn, blob.length);
1171
/* see if this is a continued packet */
1172
if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1173
!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1174
struct dcesrv_call_state *call2 = call;
1175
uint32_t alloc_size;
1177
/* we only allow fragmented requests, no other packet types */
1178
if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1179
return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1182
/* this is a continuation of an existing call - find the call then
1183
tack it on the end */
1184
call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1186
return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1189
if (call->pkt.ptype != call2->pkt.ptype) {
1190
/* trying to play silly buggers are we? */
1191
return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1194
alloc_size = call->pkt.u.request.stub_and_verifier.length +
1195
call2->pkt.u.request.stub_and_verifier.length;
1196
if (call->pkt.u.request.alloc_hint > alloc_size) {
1197
alloc_size = call->pkt.u.request.alloc_hint;
1200
call->pkt.u.request.stub_and_verifier.data =
1201
talloc_realloc(call,
1202
call->pkt.u.request.stub_and_verifier.data,
1203
uint8_t, alloc_size);
1204
if (!call->pkt.u.request.stub_and_verifier.data) {
1205
return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1207
memcpy(call->pkt.u.request.stub_and_verifier.data +
1208
call->pkt.u.request.stub_and_verifier.length,
1209
call2->pkt.u.request.stub_and_verifier.data,
1210
call2->pkt.u.request.stub_and_verifier.length);
1211
call->pkt.u.request.stub_and_verifier.length +=
1212
call2->pkt.u.request.stub_and_verifier.length;
1214
call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1219
/* this may not be the last pdu in the chain - if its isn't then
1220
just put it on the incoming_fragmented_call_list and wait for the rest */
1221
if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1222
!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1223
dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1224
return NT_STATUS_OK;
1227
/* This removes any fragments we may have had stashed away */
1228
dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1230
switch (call->pkt.ptype) {
1231
case DCERPC_PKT_BIND:
1232
status = dcesrv_bind(call);
1234
case DCERPC_PKT_AUTH3:
1235
status = dcesrv_auth3(call);
1237
case DCERPC_PKT_ALTER:
1238
status = dcesrv_alter(call);
1240
case DCERPC_PKT_REQUEST:
1241
status = dcesrv_request(call);
1244
status = NT_STATUS_INVALID_PARAMETER;
1248
/* if we are going to be sending a reply then add
1249
it to the list of pending calls. We add it to the end to keep the call
1250
list in the order we will answer */
1251
if (!NT_STATUS_IS_OK(status)) {
1260
provide some input to a dcerpc endpoint server. This passes data
1261
from a dcerpc client into the server
1263
_PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1267
dce_conn->partial_input.data = talloc_realloc(dce_conn,
1268
dce_conn->partial_input.data,
1270
dce_conn->partial_input.length + data->length);
1271
if (!dce_conn->partial_input.data) {
1272
return NT_STATUS_NO_MEMORY;
1274
memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1275
data->data, data->length);
1276
dce_conn->partial_input.length += data->length;
1278
while (dce_full_packet(&dce_conn->partial_input)) {
1279
status = dcesrv_input_process(dce_conn);
1280
if (!NT_STATUS_IS_OK(status)) {
1285
return NT_STATUS_OK;
1289
retrieve some output from a dcerpc server
1290
The caller supplies a function that will be called to do the
1293
The first argument to write_fn() will be 'private', the second will
1294
be a pointer to a buffer containing the data to be sent and the 3rd
1295
will be a pointer to a size_t variable that will be set to the
1296
number of bytes that are consumed from the output.
1298
from the current fragment
1300
_PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
1302
NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1305
struct dcesrv_call_state *call;
1306
struct data_blob_list_item *rep;
1309
call = dce_conn->call_list;
1310
if (!call || !call->replies) {
1311
if (dce_conn->pending_call_list) {
1312
/* TODO: we need to say act async here
1313
* as we know we have pending requests
1314
* which will be finished at a time
1316
return NT_STATUS_FOOBAR;
1318
return NT_STATUS_FOOBAR;
1320
rep = call->replies;
1322
status = write_fn(private_data, &rep->blob, &nwritten);
1323
NT_STATUS_IS_ERR_RETURN(status);
1325
rep->blob.length -= nwritten;
1326
rep->blob.data += nwritten;
1328
if (rep->blob.length == 0) {
1329
/* we're done with this section of the call */
1330
DLIST_REMOVE(call->replies, rep);
1333
if (call->replies == NULL) {
1334
/* we're done with the whole call */
1335
dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1342
_PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1343
struct loadparm_context *lp_ctx,
1344
const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1347
struct dcesrv_context *dce_ctx;
1350
if (!endpoint_servers) {
1351
DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1352
return NT_STATUS_INTERNAL_ERROR;
1355
dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1356
NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1357
dce_ctx->endpoint_list = NULL;
1358
dce_ctx->lp_ctx = lp_ctx;
1360
for (i=0;endpoint_servers[i];i++) {
1361
const struct dcesrv_endpoint_server *ep_server;
1363
ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1365
DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1366
return NT_STATUS_INTERNAL_ERROR;
1369
status = ep_server->init_server(dce_ctx, ep_server);
1370
if (!NT_STATUS_IS_OK(status)) {
1371
DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1372
nt_errstr(status)));
1377
*_dce_ctx = dce_ctx;
1378
return NT_STATUS_OK;
1381
/* the list of currently registered DCERPC endpoint servers.
1383
static struct ep_server {
1384
struct dcesrv_endpoint_server *ep_server;
1385
} *ep_servers = NULL;
1386
static int num_ep_servers;
1389
register a DCERPC endpoint server.
1391
The 'name' can be later used by other backends to find the operations
1392
structure for this backend.
1394
The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1396
_PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1398
const struct dcesrv_endpoint_server *ep_server = _ep_server;
1400
if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1401
/* its already registered! */
1402
DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1404
return NT_STATUS_OBJECT_NAME_COLLISION;
1407
ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1409
smb_panic("out of memory in dcerpc_register");
1412
ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1413
ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1417
DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1420
return NT_STATUS_OK;
1424
return the operations structure for a named backend of the specified type
1426
const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1430
for (i=0;i<num_ep_servers;i++) {
1431
if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1432
return ep_servers[i].ep_server;
1439
void dcerpc_server_init(struct loadparm_context *lp_ctx)
1441
static bool initialized;
1442
extern NTSTATUS dcerpc_server_wkssvc_init(void);
1443
extern NTSTATUS dcerpc_server_drsuapi_init(void);
1444
extern NTSTATUS dcerpc_server_winreg_init(void);
1445
extern NTSTATUS dcerpc_server_spoolss_init(void);
1446
extern NTSTATUS dcerpc_server_epmapper_init(void);
1447
extern NTSTATUS dcerpc_server_srvsvc_init(void);
1448
extern NTSTATUS dcerpc_server_netlogon_init(void);
1449
extern NTSTATUS dcerpc_server_rpcecho_init(void);
1450
extern NTSTATUS dcerpc_server_unixinfo_init(void);
1451
extern NTSTATUS dcerpc_server_samr_init(void);
1452
extern NTSTATUS dcerpc_server_remote_init(void);
1453
extern NTSTATUS dcerpc_server_lsa_init(void);
1454
extern NTSTATUS dcerpc_server_browser_init(void);
1455
init_module_fn static_init[] = { STATIC_dcerpc_server_MODULES };
1456
init_module_fn *shared_init;
1463
shared_init = load_samba_modules(NULL, lp_ctx, "dcerpc_server");
1465
run_init_functions(static_init);
1466
run_init_functions(shared_init);
1468
talloc_free(shared_init);
1472
return the DCERPC module version, and the size of some critical types
1473
This can be used by endpoint server modules to either detect compilation errors, or provide
1474
multiple implementations for different smbd compilation options in one module
1476
const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1478
static const struct dcesrv_critical_sizes critical_sizes = {
1479
DCERPC_MODULE_VERSION,
1480
sizeof(struct dcesrv_context),
1481
sizeof(struct dcesrv_endpoint),
1482
sizeof(struct dcesrv_endpoint_server),
1483
sizeof(struct dcesrv_interface),
1484
sizeof(struct dcesrv_if_list),
1485
sizeof(struct dcesrv_connection),
1486
sizeof(struct dcesrv_call_state),
1487
sizeof(struct dcesrv_auth),
1488
sizeof(struct dcesrv_handle)
1491
return &critical_sizes;
1495
initialise the dcerpc server context for ncacn_np based services
1497
_PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
1498
struct dcesrv_context **_dce_ctx)
1501
struct dcesrv_context *dce_ctx;
1503
dcerpc_server_init(lp_ctx);
1505
status = dcesrv_init_context(mem_ctx, lp_ctx, lp_dcerpc_endpoint_servers(lp_ctx), &dce_ctx);
1506
NT_STATUS_NOT_OK_RETURN(status);
1508
*_dce_ctx = dce_ctx;
1509
return NT_STATUS_OK;