source: branches/samba-3.5.x/source4/rpc_server/dcerpc_server.c

Last change on this file was 414, checked in by Herwig Bauernfeind, 15 years ago

Samba 3.5.0: Initial import

File size: 40.4 KB
Line 
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
Note: See TracBrowser for help on using the repository browser.