• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt/router/samba-3.5.8/source4/rpc_server/
1/*
2   Unix SMB/CIFS implementation.
3
4   server side dcerpc core code
5
6   Copyright (C) Andrew Tridgell 2003-2005
7   Copyright (C) Stefan (metze) Metzmacher 2004-2005
8
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.
13
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.
18
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/>.
21*/
22
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"
38
39/* this is only used when the client asks for an unknown interface */
40#define DUMMY_ASSOC_GROUP 0x0FFFFFFF
41
42extern const struct dcesrv_interface dcesrv_mgmt_interface;
43
44
45/*
46  find an association group given a assoc_group_id
47 */
48static struct dcesrv_assoc_group *dcesrv_assoc_group_find(struct dcesrv_context *dce_ctx,
49							  uint32_t id)
50{
51	void *id_ptr;
52
53	id_ptr = idr_find(dce_ctx->assoc_groups_idr, id);
54	if (id_ptr == NULL) {
55		return NULL;
56	}
57	return talloc_get_type_abort(id_ptr, struct dcesrv_assoc_group);
58}
59
60/*
61  take a reference to an existing association group
62 */
63static struct dcesrv_assoc_group *dcesrv_assoc_group_reference(TALLOC_CTX *mem_ctx,
64							       struct dcesrv_context *dce_ctx,
65							       uint32_t id)
66{
67	struct dcesrv_assoc_group *assoc_group;
68
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;
73	}
74	return talloc_reference(mem_ctx, assoc_group);
75}
76
77static int dcesrv_assoc_group_destructor(struct dcesrv_assoc_group *assoc_group)
78{
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));
84	}
85	return 0;
86}
87
88/*
89  allocate a new association group
90 */
91static struct dcesrv_assoc_group *dcesrv_assoc_group_new(TALLOC_CTX *mem_ctx,
92							 struct dcesrv_context *dce_ctx)
93{
94	struct dcesrv_assoc_group *assoc_group;
95	int id;
96
97	assoc_group = talloc_zero(mem_ctx, struct dcesrv_assoc_group);
98	if (assoc_group == NULL) {
99		return NULL;
100	}
101
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;
107	}
108
109	assoc_group->id = id;
110	assoc_group->dce_ctx = dce_ctx;
111
112	talloc_set_destructor(assoc_group, dcesrv_assoc_group_destructor);
113
114	return assoc_group;
115}
116
117
118/*
119  see if two endpoints match
120*/
121static bool endpoints_match(const struct dcerpc_binding *ep1,
122			    const struct dcerpc_binding *ep2)
123{
124	if (ep1->transport != ep2->transport) {
125		return false;
126	}
127
128	if (!ep1->endpoint || !ep2->endpoint) {
129		return ep1->endpoint == ep2->endpoint;
130	}
131
132	if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
133		return false;
134
135	return true;
136}
137
138/*
139  find an endpoint in the dcesrv_context
140*/
141static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
142					     const struct dcerpc_binding *ep_description)
143{
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;
148		}
149	}
150	return NULL;
151}
152
153/*
154  find a registered context_id from a bind or alter_context
155*/
156static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn,
157								   uint32_t context_id)
158{
159	struct dcesrv_connection_context *c;
160	for (c=conn->contexts;c;c=c->next) {
161		if (c->context_id == context_id) return c;
162	}
163	return NULL;
164}
165
166/*
167  see if a uuid and if_version match to an interface
168*/
169static bool interface_match(const struct dcesrv_interface *if1,
170							const struct dcesrv_interface *if2)
171{
172	return (if1->syntax_id.if_version == if2->syntax_id.if_version &&
173			GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
174}
175
176/*
177  find the interface operations on an endpoint
178*/
179static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
180						     const struct dcesrv_interface *iface)
181{
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);
186		}
187	}
188	return NULL;
189}
190
191/*
192  see if a uuid and if_version match to an interface
193*/
194static bool interface_match_by_uuid(const struct dcesrv_interface *iface,
195				    const struct GUID *uuid, uint32_t if_version)
196{
197	return (iface->syntax_id.if_version == if_version &&
198			GUID_equal(&iface->syntax_id.uuid, uuid));
199}
200
201/*
202  find the interface operations on an endpoint by uuid
203*/
204static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
205							     const struct GUID *uuid, uint32_t if_version)
206{
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);
211		}
212	}
213	return NULL;
214}
215
216/*
217  find the earlier parts of a fragmented call awaiting reassembily
218*/
219static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
220{
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;
225		}
226	}
227	return NULL;
228}
229
230/*
231  register an interface on an endpoint
232*/
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)
237{
238	struct dcesrv_endpoint *ep;
239	struct dcesrv_if_list *ifl;
240	struct dcerpc_binding *binding;
241	bool add_ep = false;
242	NTSTATUS status;
243
244	status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
245
246	if (NT_STATUS_IS_ERR(status)) {
247		DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
248		return status;
249	}
250
251	/* check if this endpoint exists
252	 */
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;
257		}
258		ZERO_STRUCTP(ep);
259		ep->ep_description = talloc_reference(ep, binding);
260		add_ep = true;
261
262		/* add mgmt interface */
263		ifl = talloc(dce_ctx, struct dcesrv_if_list);
264		if (!ifl) {
265			return NT_STATUS_NO_MEMORY;
266		}
267
268		memcpy(&(ifl->iface), &dcesrv_mgmt_interface,
269			   sizeof(struct dcesrv_interface));
270
271		DLIST_ADD(ep->interface_list, ifl);
272	}
273
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;
279	}
280
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;
285	}
286
287	/* copy the given interface struct to the one on the endpoints interface list */
288	memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
289
290	/* if we have a security descriptor given,
291	 * we should see if we can set it up on the endpoint
292	 */
293	if (sd != NULL) {
294		/* if there's currently no security descriptor given on the endpoint
295		 * we try to set it
296		 */
297		if (ep->sd == NULL) {
298			ep->sd = security_descriptor_copy(dce_ctx, sd);
299		}
300
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
304		 */
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;
312		}
313	}
314
315	/* finally add the interface on the endpoint */
316	DLIST_ADD(ep->interface_list, ifl);
317
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);
321	}
322
323	DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
324		iface->name, ep_name));
325
326	return NT_STATUS_OK;
327}
328
329NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
330				      DATA_BLOB *session_key)
331{
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;
335	}
336	return NT_STATUS_NO_USER_SESSION_KEY;
337}
338
339NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
340				    DATA_BLOB *session_key)
341{
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;
346}
347
348/*
349  fetch the user session key - may be default (above) or the SMB session key
350
351  The key is always truncated to 16 bytes
352*/
353_PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
354				  DATA_BLOB *session_key)
355{
356	NTSTATUS status = p->auth_state.session_key(p, session_key);
357	if (!NT_STATUS_IS_OK(status)) {
358		return status;
359	}
360
361	session_key->length = MIN(session_key->length, 16);
362
363	return NT_STATUS_OK;
364}
365
366/*
367  connect to a dcerpc endpoint
368*/
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)
378{
379	struct dcesrv_connection *p;
380
381	if (!session_info) {
382		return NT_STATUS_ACCESS_DENIED;
383	}
384
385	p = talloc(mem_ctx, struct dcesrv_connection);
386	NT_STATUS_HAVE_NO_MEMORY(p);
387
388	if (!talloc_reference(p, session_info)) {
389		talloc_free(p);
390		return NT_STATUS_NO_MEMORY;
391	}
392
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);
412
413	*_p = p;
414	return NT_STATUS_OK;
415}
416
417static void dcesrv_init_hdr(struct ncacn_packet *pkt, bool bigendian)
418{
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;
425	}
426	pkt->drep[1] = 0;
427	pkt->drep[2] = 0;
428	pkt->drep[3] = 0;
429}
430
431/*
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.
435 */
436static void dcesrv_call_set_list(struct dcesrv_call_state *call,
437				 enum dcesrv_call_list list)
438{
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;
451	}
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;
465	}
466}
467
468/*
469  return a dcerpc fault
470*/
471static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
472{
473	struct ncacn_packet pkt;
474	struct data_blob_list_item *rep;
475	uint8_t zeros[4];
476	NTSTATUS status;
477
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;
488
489	ZERO_STRUCT(zeros);
490	pkt.u.fault._pad = data_blob_const(zeros, sizeof(zeros));
491
492	rep = talloc(call, struct data_blob_list_item);
493	if (!rep) {
494		return NT_STATUS_NO_MEMORY;
495	}
496
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;
500	}
501
502	dcerpc_set_frag_length(&rep->blob, rep->blob.length);
503
504	DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
505	dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
506
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);
510		}
511	}
512
513	return NT_STATUS_OK;
514}
515
516
517/*
518  return a dcerpc bind_nak
519*/
520static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
521{
522	struct ncacn_packet pkt;
523	struct data_blob_list_item *rep;
524	NTSTATUS status;
525
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;
535	}
536
537	rep = talloc(call, struct data_blob_list_item);
538	if (!rep) {
539		return NT_STATUS_NO_MEMORY;
540	}
541
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;
545	}
546
547	dcerpc_set_frag_length(&rep->blob, rep->blob.length);
548
549	DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
550	dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
551
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);
555		}
556	}
557
558	return NT_STATUS_OK;
559}
560
561static int dcesrv_connection_context_destructor(struct dcesrv_connection_context *c)
562{
563	DLIST_REMOVE(c->conn->contexts, c);
564
565	if (c->iface) {
566		c->iface->unbind(c, c->iface);
567	}
568
569	return 0;
570}
571
572/*
573  handle a bind request
574*/
575static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
576{
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;
586
587	/*
588	  if provided, check the assoc_group is valid
589	 */
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);
594	}
595
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);
599	}
600
601	context_id = call->pkt.u.bind.ctx_list[0].context_id;
602
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);
606	}
607
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;
610
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);
620	}
621
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);
627
628		/* we don't know about that interface */
629		result = DCERPC_BIND_PROVIDER_REJECT;
630		reason = DCERPC_BIND_REASON_ASYNTAX;
631	}
632
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);
639		}
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);
649		}
650		if (context->assoc_group == NULL) {
651			talloc_free(context);
652			return dcesrv_bind_nak(call, 0);
653		}
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);
658
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);
670		}
671	}
672
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);
675	}
676
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;
681	}
682
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);
688	}
689
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;
698
699	/*
700	  make it possible for iface->bind() to specify the assoc_group_id
701	  This helps the openchange mapiproxy plugin to work correctly.
702
703	  metze
704	*/
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;
709	}
710
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 = "";
716	}
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;
723	}
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);
728
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);
734	}
735
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;
741	}
742
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;
748	}
749
750	dcerpc_set_frag_length(&rep->blob, rep->blob.length);
751
752	DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
753	dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
754
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);
758		}
759	}
760
761	return NT_STATUS_OK;
762}
763
764
765/*
766  handle a auth3 request
767*/
768static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
769{
770	/* handle the auth3 in the auth code */
771	if (!dcesrv_auth_auth3(call)) {
772		return dcesrv_fault(call, DCERPC_FAULT_OTHER);
773	}
774
775	talloc_free(call);
776
777	/* we don't send a reply to a auth3 request, except by a
778	   fault */
779	return NT_STATUS_OK;
780}
781
782
783/*
784  handle a bind request
785*/
786static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
787{
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;
793
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;
796
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;
803	}
804
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;
811	}
812
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;
817	}
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);
827	}
828	if (context->assoc_group == NULL) {
829		talloc_free(context);
830		call->context = NULL;
831		return NT_STATUS_NO_MEMORY;
832	}
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);
837
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;
845	}
846
847	return NT_STATUS_OK;
848}
849
850
851/*
852  handle a alter context request
853*/
854static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
855{
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;
861
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;
867	}
868
869	context_id = call->pkt.u.alter.ctx_list[0].context_id;
870
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;
879			}
880		}
881	}
882
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;
892	}
893
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;
906	}
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;
911	}
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 = "";
917
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);
925		}
926		return dcesrv_fault(call, 0);
927	}
928
929	rep = talloc(call, struct data_blob_list_item);
930	if (!rep) {
931		return NT_STATUS_NO_MEMORY;
932	}
933
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;
937	}
938
939	dcerpc_set_frag_length(&rep->blob, rep->blob.length);
940
941	DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
942	dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
943
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);
947		}
948	}
949
950	return NT_STATUS_OK;
951}
952
953/*
954  handle a dcerpc request packet
955*/
956static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
957{
958	struct ndr_pull *pull;
959	NTSTATUS status;
960	struct dcesrv_connection_context *context;
961
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;
966	}
967
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);
971	}
972
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);
976
977	pull->flags |= LIBNDR_FLAG_REF_ALLOC;
978
979	call->context	= context;
980	call->ndr_pull	= pull;
981
982	if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
983		pull->flags |= LIBNDR_FLAG_BIGENDIAN;
984	}
985
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);
990	}
991
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);
996	}
997
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);
1006	}
1007
1008	/* add the call to the pending list */
1009	dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
1010
1011	if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
1012		return NT_STATUS_OK;
1013	}
1014
1015	return dcesrv_reply(call);
1016}
1017
1018_PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
1019{
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;
1026
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);
1031	}
1032
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);
1036
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;
1041
1042	if (lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
1043		push->flags |= LIBNDR_FLAG_BIGENDIAN;
1044	}
1045
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);
1049	}
1050
1051	stub = ndr_push_blob(push);
1052
1053	total_length = stub.length;
1054
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;
1066		}
1067	}
1068	chunk_size -= (chunk_size % 16);
1069
1070	do {
1071		uint32_t length;
1072		struct data_blob_list_item *rep;
1073		struct ncacn_packet pkt;
1074
1075		rep = talloc(call, struct data_blob_list_item);
1076		NT_STATUS_HAVE_NO_MEMORY(rep);
1077
1078		length = MIN(chunk_size, stub.length);
1079
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;
1088		}
1089		if (length == stub.length) {
1090			pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1091		}
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;
1097
1098		if (!dcesrv_auth_response(call, &rep->blob, sig_size, &pkt)) {
1099			return dcesrv_fault(call, DCERPC_FAULT_OTHER);
1100		}
1101
1102		dcerpc_set_frag_length(&rep->blob, rep->blob.length);
1103
1104		DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
1105
1106		stub.data += length;
1107		stub.length -= length;
1108	} while (stub.length != 0);
1109
1110	/* move the call from the pending to the finished calls list */
1111	dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
1112
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);
1116		}
1117	}
1118
1119	return NT_STATUS_OK;
1120}
1121
1122_PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1123{
1124	if (!conn->transport.get_my_addr) {
1125		return NULL;
1126	}
1127
1128	return conn->transport.get_my_addr(conn, mem_ctx);
1129}
1130
1131_PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
1132{
1133	if (!conn->transport.get_peer_addr) {
1134		return NULL;
1135	}
1136
1137	return conn->transport.get_peer_addr(conn, mem_ctx);
1138}
1139
1140
1141/*
1142  remove the call from the right list when freed
1143 */
1144static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1145{
1146	dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1147	return 0;
1148}
1149
1150/*
1151  process some input to a dcerpc endpoint server.
1152*/
1153NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
1154				     struct ncacn_packet *pkt,
1155				     DATA_BLOB blob)
1156{
1157	NTSTATUS status;
1158	struct dcesrv_call_state *call;
1159
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;
1165	}
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;
1172
1173	talloc_steal(call, pkt);
1174	talloc_steal(call, blob.data);
1175	call->pkt = *pkt;
1176
1177	talloc_set_destructor(call, dcesrv_call_dequeue);
1178
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);
1184	}
1185
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;
1191
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);
1195		}
1196
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);
1202		}
1203
1204		if (call->pkt.ptype != call2->pkt.ptype) {
1205			/* trying to play silly buggers are we? */
1206			return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1207		}
1208
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;
1213		}
1214
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);
1221		}
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;
1228
1229		call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1230
1231		talloc_free(call2);
1232	}
1233
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;
1240	}
1241
1242	/* This removes any fragments we may have had stashed away */
1243	dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1244
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;
1261	}
1262
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);
1268	}
1269
1270	return status;
1271}
1272
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)
1276{
1277	NTSTATUS status;
1278	struct dcesrv_context *dce_ctx;
1279	int i;
1280
1281	if (!endpoint_servers) {
1282		DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1283		return NT_STATUS_INTERNAL_ERROR;
1284	}
1285
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);
1292
1293	for (i=0;endpoint_servers[i];i++) {
1294		const struct dcesrv_endpoint_server *ep_server;
1295
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;
1300		}
1301
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;
1307		}
1308	}
1309
1310	*_dce_ctx = dce_ctx;
1311	return NT_STATUS_OK;
1312}
1313
1314/* the list of currently registered DCERPC endpoint servers.
1315 */
1316static struct ep_server {
1317	struct dcesrv_endpoint_server *ep_server;
1318} *ep_servers = NULL;
1319static int num_ep_servers;
1320
1321/*
1322  register a DCERPC endpoint server.
1323
1324  The 'name' can be later used by other backends to find the operations
1325  structure for this backend.
1326
1327  The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1328*/
1329_PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1330{
1331	const struct dcesrv_endpoint_server *ep_server = _ep_server;
1332
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;
1338	}
1339
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");
1343	}
1344
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);
1347
1348	num_ep_servers++;
1349
1350	DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1351		 ep_server->name));
1352
1353	return NT_STATUS_OK;
1354}
1355
1356/*
1357  return the operations structure for a named backend of the specified type
1358*/
1359const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1360{
1361	int i;
1362
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;
1366		}
1367	}
1368
1369	return NULL;
1370}
1371
1372void dcerpc_server_init(struct loadparm_context *lp_ctx)
1373{
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;
1390
1391	if (initialized) {
1392		return;
1393	}
1394	initialized = true;
1395
1396	shared_init = load_samba_modules(NULL, lp_ctx, "dcerpc_server");
1397
1398	run_init_functions(static_init);
1399	run_init_functions(shared_init);
1400
1401	talloc_free(shared_init);
1402}
1403
1404/*
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
1408*/
1409const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1410{
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)
1422	};
1423
1424	return &critical_sizes;
1425}
1426
1427