source: trunk/server/source4/rpc_server/dcerpc_server.c

Last change on this file was 745, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.0

File size: 51.5 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 "auth/auth.h"
25#include "auth/gensec/gensec.h"
26#include "../lib/util/dlinklist.h"
27#include "rpc_server/dcerpc_server.h"
28#include "rpc_server/dcerpc_server_proto.h"
29#include "rpc_server/common/proto.h"
30#include "librpc/rpc/dcerpc_proto.h"
31#include "system/filesys.h"
32#include "libcli/security/security.h"
33#include "param/param.h"
34#include "../lib/tsocket/tsocket.h"
35#include "../libcli/named_pipe_auth/npa_tstream.h"
36#include "smbd/service_stream.h"
37#include "../lib/tsocket/tsocket.h"
38#include "lib/socket/socket.h"
39#include "smbd/process_model.h"
40#include "lib/messaging/irpc.h"
41#include "librpc/rpc/rpc_common.h"
42
43/* this is only used when the client asks for an unknown interface */
44#define DUMMY_ASSOC_GROUP 0x0FFFFFFF
45
46extern const struct dcesrv_interface dcesrv_mgmt_interface;
47
48
49/*
50 find an association group given a assoc_group_id
51 */
52static struct dcesrv_assoc_group *dcesrv_assoc_group_find(struct dcesrv_context *dce_ctx,
53 uint32_t id)
54{
55 void *id_ptr;
56
57 id_ptr = idr_find(dce_ctx->assoc_groups_idr, id);
58 if (id_ptr == NULL) {
59 return NULL;
60 }
61 return talloc_get_type_abort(id_ptr, struct dcesrv_assoc_group);
62}
63
64/*
65 take a reference to an existing association group
66 */
67static struct dcesrv_assoc_group *dcesrv_assoc_group_reference(TALLOC_CTX *mem_ctx,
68 struct dcesrv_context *dce_ctx,
69 uint32_t id)
70{
71 struct dcesrv_assoc_group *assoc_group;
72
73 assoc_group = dcesrv_assoc_group_find(dce_ctx, id);
74 if (assoc_group == NULL) {
75 DEBUG(0,(__location__ ": Failed to find assoc_group 0x%08x\n", id));
76 return NULL;
77 }
78 return talloc_reference(mem_ctx, assoc_group);
79}
80
81static int dcesrv_assoc_group_destructor(struct dcesrv_assoc_group *assoc_group)
82{
83 int ret;
84 ret = idr_remove(assoc_group->dce_ctx->assoc_groups_idr, assoc_group->id);
85 if (ret != 0) {
86 DEBUG(0,(__location__ ": Failed to remove assoc_group 0x%08x\n",
87 assoc_group->id));
88 }
89 return 0;
90}
91
92/*
93 allocate a new association group
94 */
95static struct dcesrv_assoc_group *dcesrv_assoc_group_new(TALLOC_CTX *mem_ctx,
96 struct dcesrv_context *dce_ctx)
97{
98 struct dcesrv_assoc_group *assoc_group;
99 int id;
100
101 assoc_group = talloc_zero(mem_ctx, struct dcesrv_assoc_group);
102 if (assoc_group == NULL) {
103 return NULL;
104 }
105
106 id = idr_get_new_random(dce_ctx->assoc_groups_idr, assoc_group, UINT16_MAX);
107 if (id == -1) {
108 talloc_free(assoc_group);
109 DEBUG(0,(__location__ ": Out of association groups!\n"));
110 return NULL;
111 }
112
113 assoc_group->id = id;
114 assoc_group->dce_ctx = dce_ctx;
115
116 talloc_set_destructor(assoc_group, dcesrv_assoc_group_destructor);
117
118 return assoc_group;
119}
120
121
122/*
123 see if two endpoints match
124*/
125static bool endpoints_match(const struct dcerpc_binding *ep1,
126 const struct dcerpc_binding *ep2)
127{
128 if (ep1->transport != ep2->transport) {
129 return false;
130 }
131
132 if (!ep1->endpoint || !ep2->endpoint) {
133 return ep1->endpoint == ep2->endpoint;
134 }
135
136 if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
137 return false;
138
139 return true;
140}
141
142/*
143 find an endpoint in the dcesrv_context
144*/
145static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
146 const struct dcerpc_binding *ep_description)
147{
148 struct dcesrv_endpoint *ep;
149 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
150 if (endpoints_match(ep->ep_description, ep_description)) {
151 return ep;
152 }
153 }
154 return NULL;
155}
156
157/*
158 find a registered context_id from a bind or alter_context
159*/
160static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn,
161 uint32_t context_id)
162{
163 struct dcesrv_connection_context *c;
164 for (c=conn->contexts;c;c=c->next) {
165 if (c->context_id == context_id) return c;
166 }
167 return NULL;
168}
169
170/*
171 see if a uuid and if_version match to an interface
172*/
173static bool interface_match(const struct dcesrv_interface *if1,
174 const struct dcesrv_interface *if2)
175{
176 return (if1->syntax_id.if_version == if2->syntax_id.if_version &&
177 GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
178}
179
180/*
181 find the interface operations on an endpoint
182*/
183static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
184 const struct dcesrv_interface *iface)
185{
186 struct dcesrv_if_list *ifl;
187 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
188 if (interface_match(&(ifl->iface), iface)) {
189 return &(ifl->iface);
190 }
191 }
192 return NULL;
193}
194
195/*
196 see if a uuid and if_version match to an interface
197*/
198static bool interface_match_by_uuid(const struct dcesrv_interface *iface,
199 const struct GUID *uuid, uint32_t if_version)
200{
201 return (iface->syntax_id.if_version == if_version &&
202 GUID_equal(&iface->syntax_id.uuid, uuid));
203}
204
205/*
206 find the interface operations on an endpoint by uuid
207*/
208static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
209 const struct GUID *uuid, uint32_t if_version)
210{
211 struct dcesrv_if_list *ifl;
212 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
213 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
214 return &(ifl->iface);
215 }
216 }
217 return NULL;
218}
219
220/*
221 find the earlier parts of a fragmented call awaiting reassembily
222*/
223static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
224{
225 struct dcesrv_call_state *c;
226 for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
227 if (c->pkt.call_id == call_id) {
228 return c;
229 }
230 }
231 return NULL;
232}
233
234/*
235 register an interface on an endpoint
236*/
237_PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
238 const char *ep_name,
239 const struct dcesrv_interface *iface,
240 const struct security_descriptor *sd)
241{
242 struct dcesrv_endpoint *ep;
243 struct dcesrv_if_list *ifl;
244 struct dcerpc_binding *binding;
245 bool add_ep = false;
246 NTSTATUS status;
247
248 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
249
250 if (NT_STATUS_IS_ERR(status)) {
251 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
252 return status;
253 }
254
255 /* check if this endpoint exists
256 */
257 if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
258 ep = talloc(dce_ctx, struct dcesrv_endpoint);
259 if (!ep) {
260 return NT_STATUS_NO_MEMORY;
261 }
262 ZERO_STRUCTP(ep);
263 ep->ep_description = talloc_reference(ep, binding);
264 add_ep = true;
265
266 /* add mgmt interface */
267 ifl = talloc(dce_ctx, struct dcesrv_if_list);
268 if (!ifl) {
269 return NT_STATUS_NO_MEMORY;
270 }
271
272 memcpy(&(ifl->iface), &dcesrv_mgmt_interface,
273 sizeof(struct dcesrv_interface));
274
275 DLIST_ADD(ep->interface_list, ifl);
276 }
277
278 /* see if the interface is already registered on te endpoint */
279 if (find_interface(ep, iface)!=NULL) {
280 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
281 iface->name, ep_name));
282 return NT_STATUS_OBJECT_NAME_COLLISION;
283 }
284
285 /* talloc a new interface list element */
286 ifl = talloc(dce_ctx, struct dcesrv_if_list);
287 if (!ifl) {
288 return NT_STATUS_NO_MEMORY;
289 }
290
291 /* copy the given interface struct to the one on the endpoints interface list */
292 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
293
294 /* if we have a security descriptor given,
295 * we should see if we can set it up on the endpoint
296 */
297 if (sd != NULL) {
298 /* if there's currently no security descriptor given on the endpoint
299 * we try to set it
300 */
301 if (ep->sd == NULL) {
302 ep->sd = security_descriptor_copy(dce_ctx, sd);
303 }
304
305 /* if now there's no security descriptor given on the endpoint
306 * something goes wrong, either we failed to copy the security descriptor
307 * or there was already one on the endpoint
308 */
309 if (ep->sd != NULL) {
310 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
311 " on endpoint '%s'\n",
312 iface->name, ep_name));
313 if (add_ep) free(ep);
314 free(ifl);
315 return NT_STATUS_OBJECT_NAME_COLLISION;
316 }
317 }
318
319 /* finally add the interface on the endpoint */
320 DLIST_ADD(ep->interface_list, ifl);
321
322 /* if it's a new endpoint add it to the dcesrv_context */
323 if (add_ep) {
324 DLIST_ADD(dce_ctx->endpoint_list, ep);
325 }
326
327 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
328 iface->name, ep_name));
329
330 return NT_STATUS_OK;
331}
332
333NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
334 DATA_BLOB *session_key)
335{
336 if (p->auth_state.session_info->session_key.length) {
337 *session_key = p->auth_state.session_info->session_key;
338 return NT_STATUS_OK;
339 }
340 return NT_STATUS_NO_USER_SESSION_KEY;
341}
342
343/*
344 fetch the user session key - may be default (above) or the SMB session key
345
346 The key is always truncated to 16 bytes
347*/
348_PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
349 DATA_BLOB *session_key)
350{
351 NTSTATUS status = p->auth_state.session_key(p, session_key);
352 if (!NT_STATUS_IS_OK(status)) {
353 return status;
354 }
355
356 session_key->length = MIN(session_key->length, 16);
357
358 return NT_STATUS_OK;
359}
360
361/*
362 connect to a dcerpc endpoint
363*/
364_PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
365 TALLOC_CTX *mem_ctx,
366 const struct dcesrv_endpoint *ep,
367 struct auth_session_info *session_info,
368 struct tevent_context *event_ctx,
369 struct messaging_context *msg_ctx,
370 struct server_id server_id,
371 uint32_t state_flags,
372 struct dcesrv_connection **_p)
373{
374 struct dcesrv_connection *p;
375
376 if (!session_info) {
377 return NT_STATUS_ACCESS_DENIED;
378 }
379
380 p = talloc(mem_ctx, struct dcesrv_connection);
381 NT_STATUS_HAVE_NO_MEMORY(p);
382
383 if (!talloc_reference(p, session_info)) {
384 talloc_free(p);
385 return NT_STATUS_NO_MEMORY;
386 }
387
388 p->dce_ctx = dce_ctx;
389 p->endpoint = ep;
390 p->contexts = NULL;
391 p->call_list = NULL;
392 p->packet_log_dir = lpcfg_lockdir(dce_ctx->lp_ctx);
393 p->incoming_fragmented_call_list = NULL;
394 p->pending_call_list = NULL;
395 p->cli_max_recv_frag = 0;
396 p->partial_input = data_blob(NULL, 0);
397 p->auth_state.auth_info = NULL;
398 p->auth_state.gensec_security = NULL;
399 p->auth_state.session_info = session_info;
400 p->auth_state.session_key = dcesrv_generic_session_key;
401 p->event_ctx = event_ctx;
402 p->msg_ctx = msg_ctx;
403 p->server_id = server_id;
404 p->processing = false;
405 p->state_flags = state_flags;
406 ZERO_STRUCT(p->transport);
407
408 *_p = p;
409 return NT_STATUS_OK;
410}
411
412/*
413 move a call from an existing linked list to the specified list. This
414 prevents bugs where we forget to remove the call from a previous
415 list when moving it.
416 */
417static void dcesrv_call_set_list(struct dcesrv_call_state *call,
418 enum dcesrv_call_list list)
419{
420 switch (call->list) {
421 case DCESRV_LIST_NONE:
422 break;
423 case DCESRV_LIST_CALL_LIST:
424 DLIST_REMOVE(call->conn->call_list, call);
425 break;
426 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
427 DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
428 break;
429 case DCESRV_LIST_PENDING_CALL_LIST:
430 DLIST_REMOVE(call->conn->pending_call_list, call);
431 break;
432 }
433 call->list = list;
434 switch (list) {
435 case DCESRV_LIST_NONE:
436 break;
437 case DCESRV_LIST_CALL_LIST:
438 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
439 break;
440 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
441 DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
442 break;
443 case DCESRV_LIST_PENDING_CALL_LIST:
444 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
445 break;
446 }
447}
448
449
450/*
451 return a dcerpc bind_nak
452*/
453static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
454{
455 struct ncacn_packet pkt;
456 struct data_blob_list_item *rep;
457 NTSTATUS status;
458
459 /* setup a bind_nak */
460 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
461 pkt.auth_length = 0;
462 pkt.call_id = call->pkt.call_id;
463 pkt.ptype = DCERPC_PKT_BIND_NAK;
464 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
465 pkt.u.bind_nak.reject_reason = reason;
466 if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
467 pkt.u.bind_nak.versions.v.num_versions = 0;
468 }
469
470 rep = talloc(call, struct data_blob_list_item);
471 if (!rep) {
472 return NT_STATUS_NO_MEMORY;
473 }
474
475 status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
476 if (!NT_STATUS_IS_OK(status)) {
477 return status;
478 }
479
480 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
481
482 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
483 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
484
485 if (call->conn->call_list && call->conn->call_list->replies) {
486 if (call->conn->transport.report_output_data) {
487 call->conn->transport.report_output_data(call->conn);
488 }
489 }
490
491 return NT_STATUS_OK;
492}
493
494static int dcesrv_connection_context_destructor(struct dcesrv_connection_context *c)
495{
496 DLIST_REMOVE(c->conn->contexts, c);
497
498 if (c->iface && c->iface->unbind) {
499 c->iface->unbind(c, c->iface);
500 }
501
502 return 0;
503}
504
505/*
506 handle a bind request
507*/
508static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
509{
510 uint32_t if_version, transfer_syntax_version;
511 struct GUID uuid, *transfer_syntax_uuid;
512 struct ncacn_packet pkt;
513 struct data_blob_list_item *rep;
514 NTSTATUS status;
515 uint32_t result=0, reason=0;
516 uint32_t context_id;
517 const struct dcesrv_interface *iface;
518 uint32_t extra_flags = 0;
519
520 /*
521 if provided, check the assoc_group is valid
522 */
523 if (call->pkt.u.bind.assoc_group_id != 0 &&
524 lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
525 dcesrv_assoc_group_find(call->conn->dce_ctx, call->pkt.u.bind.assoc_group_id) == NULL) {
526 return dcesrv_bind_nak(call, 0);
527 }
528
529 if (call->pkt.u.bind.num_contexts < 1 ||
530 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
531 return dcesrv_bind_nak(call, 0);
532 }
533
534 context_id = call->pkt.u.bind.ctx_list[0].context_id;
535
536 /* you can't bind twice on one context */
537 if (dcesrv_find_context(call->conn, context_id) != NULL) {
538 return dcesrv_bind_nak(call, 0);
539 }
540
541 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
542 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
543
544 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
545 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
546 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
547 ndr_transfer_syntax.if_version != transfer_syntax_version) {
548 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
549 /* we only do NDR encoded dcerpc */
550 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
551 talloc_free(uuid_str);
552 return dcesrv_bind_nak(call, 0);
553 }
554
555 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
556 if (iface == NULL) {
557 char *uuid_str = GUID_string(call, &uuid);
558 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
559 talloc_free(uuid_str);
560
561 /* we don't know about that interface */
562 result = DCERPC_BIND_PROVIDER_REJECT;
563 reason = DCERPC_BIND_REASON_ASYNTAX;
564 }
565
566 if (iface) {
567 /* add this context to the list of available context_ids */
568 struct dcesrv_connection_context *context = talloc(call->conn,
569 struct dcesrv_connection_context);
570 if (context == NULL) {
571 return dcesrv_bind_nak(call, 0);
572 }
573 context->conn = call->conn;
574 context->iface = iface;
575 context->context_id = context_id;
576 if (call->pkt.u.bind.assoc_group_id != 0) {
577 context->assoc_group = dcesrv_assoc_group_reference(context,
578 call->conn->dce_ctx,
579 call->pkt.u.bind.assoc_group_id);
580 } else {
581 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
582 }
583 if (context->assoc_group == NULL) {
584 talloc_free(context);
585 return dcesrv_bind_nak(call, 0);
586 }
587 context->private_data = NULL;
588 DLIST_ADD(call->conn->contexts, context);
589 call->context = context;
590 talloc_set_destructor(context, dcesrv_connection_context_destructor);
591
592 status = iface->bind(call, iface, if_version);
593 if (!NT_STATUS_IS_OK(status)) {
594 char *uuid_str = GUID_string(call, &uuid);
595 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
596 uuid_str, if_version, nt_errstr(status)));
597 talloc_free(uuid_str);
598 /* we don't want to trigger the iface->unbind() hook */
599 context->iface = NULL;
600 talloc_free(call->context);
601 call->context = NULL;
602 return dcesrv_bind_nak(call, 0);
603 }
604 }
605
606 if (call->conn->cli_max_recv_frag == 0) {
607 call->conn->cli_max_recv_frag = MIN(0x2000, call->pkt.u.bind.max_recv_frag);
608 }
609
610 if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) &&
611 lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","header signing", false)) {
612 call->conn->state_flags |= DCESRV_CALL_STATE_FLAG_HEADER_SIGNING;
613 extra_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
614 }
615
616 /* handle any authentication that is being requested */
617 if (!dcesrv_auth_bind(call)) {
618 talloc_free(call->context);
619 call->context = NULL;
620 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
621 }
622
623 /* setup a bind_ack */
624 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
625 pkt.auth_length = 0;
626 pkt.call_id = call->pkt.call_id;
627 pkt.ptype = DCERPC_PKT_BIND_ACK;
628 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
629 pkt.u.bind_ack.max_xmit_frag = call->conn->cli_max_recv_frag;
630 pkt.u.bind_ack.max_recv_frag = 0x2000;
631
632 /*
633 make it possible for iface->bind() to specify the assoc_group_id
634 This helps the openchange mapiproxy plugin to work correctly.
635
636 metze
637 */
638 if (call->context) {
639 pkt.u.bind_ack.assoc_group_id = call->context->assoc_group->id;
640 } else {
641 pkt.u.bind_ack.assoc_group_id = DUMMY_ASSOC_GROUP;
642 }
643
644 if (iface) {
645 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
646 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
647 } else {
648 pkt.u.bind_ack.secondary_address = "";
649 }
650 pkt.u.bind_ack.num_results = 1;
651 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
652 if (!pkt.u.bind_ack.ctx_list) {
653 talloc_free(call->context);
654 call->context = NULL;
655 return NT_STATUS_NO_MEMORY;
656 }
657 pkt.u.bind_ack.ctx_list[0].result = result;
658 pkt.u.bind_ack.ctx_list[0].reason = reason;
659 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
660 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
661
662 status = dcesrv_auth_bind_ack(call, &pkt);
663 if (!NT_STATUS_IS_OK(status)) {
664 talloc_free(call->context);
665 call->context = NULL;
666 return dcesrv_bind_nak(call, 0);
667 }
668
669 rep = talloc(call, struct data_blob_list_item);
670 if (!rep) {
671 talloc_free(call->context);
672 call->context = NULL;
673 return NT_STATUS_NO_MEMORY;
674 }
675
676 status = ncacn_push_auth(&rep->blob, call, &pkt,
677 call->conn->auth_state.auth_info);
678 if (!NT_STATUS_IS_OK(status)) {
679 talloc_free(call->context);
680 call->context = NULL;
681 return status;
682 }
683
684 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
685
686 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
687 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
688
689 if (call->conn->call_list && call->conn->call_list->replies) {
690 if (call->conn->transport.report_output_data) {
691 call->conn->transport.report_output_data(call->conn);
692 }
693 }
694
695 return NT_STATUS_OK;
696}
697
698
699/*
700 handle a auth3 request
701*/
702static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
703{
704 /* handle the auth3 in the auth code */
705 if (!dcesrv_auth_auth3(call)) {
706 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
707 }
708
709 talloc_free(call);
710
711 /* we don't send a reply to a auth3 request, except by a
712 fault */
713 return NT_STATUS_OK;
714}
715
716
717/*
718 handle a bind request
719*/
720static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
721{
722 uint32_t if_version, transfer_syntax_version;
723 struct dcesrv_connection_context *context;
724 const struct dcesrv_interface *iface;
725 struct GUID uuid, *transfer_syntax_uuid;
726 NTSTATUS status;
727
728 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
729 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
730
731 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
732 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
733 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
734 ndr_transfer_syntax.if_version != transfer_syntax_version) {
735 /* we only do NDR encoded dcerpc */
736 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
737 }
738
739 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
740 if (iface == NULL) {
741 char *uuid_str = GUID_string(call, &uuid);
742 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
743 talloc_free(uuid_str);
744 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
745 }
746
747 /* add this context to the list of available context_ids */
748 context = talloc(call->conn, struct dcesrv_connection_context);
749 if (context == NULL) {
750 return NT_STATUS_NO_MEMORY;
751 }
752 context->conn = call->conn;
753 context->iface = iface;
754 context->context_id = context_id;
755 if (call->pkt.u.alter.assoc_group_id != 0) {
756 context->assoc_group = dcesrv_assoc_group_reference(context,
757 call->conn->dce_ctx,
758 call->pkt.u.alter.assoc_group_id);
759 } else {
760 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx);
761 }
762 if (context->assoc_group == NULL) {
763 talloc_free(context);
764 call->context = NULL;
765 return NT_STATUS_NO_MEMORY;
766 }
767 context->private_data = NULL;
768 DLIST_ADD(call->conn->contexts, context);
769 call->context = context;
770 talloc_set_destructor(context, dcesrv_connection_context_destructor);
771
772 status = iface->bind(call, iface, if_version);
773 if (!NT_STATUS_IS_OK(status)) {
774 /* we don't want to trigger the iface->unbind() hook */
775 context->iface = NULL;
776 talloc_free(context);
777 call->context = NULL;
778 return status;
779 }
780
781 return NT_STATUS_OK;
782}
783
784
785/*
786 handle a alter context request
787*/
788static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
789{
790 struct ncacn_packet pkt;
791 struct data_blob_list_item *rep;
792 NTSTATUS status;
793 uint32_t result=0, reason=0;
794 uint32_t context_id;
795
796 /* handle any authentication that is being requested */
797 if (!dcesrv_auth_alter(call)) {
798 /* TODO: work out the right reject code */
799 result = DCERPC_BIND_PROVIDER_REJECT;
800 reason = DCERPC_BIND_REASON_ASYNTAX;
801 }
802
803 context_id = call->pkt.u.alter.ctx_list[0].context_id;
804
805 /* see if they are asking for a new interface */
806 if (result == 0) {
807 call->context = dcesrv_find_context(call->conn, context_id);
808 if (!call->context) {
809 status = dcesrv_alter_new_context(call, context_id);
810 if (!NT_STATUS_IS_OK(status)) {
811 result = DCERPC_BIND_PROVIDER_REJECT;
812 reason = DCERPC_BIND_REASON_ASYNTAX;
813 }
814 }
815 }
816
817 if (result == 0 &&
818 call->pkt.u.alter.assoc_group_id != 0 &&
819 lpcfg_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
820 call->pkt.u.alter.assoc_group_id != call->context->assoc_group->id) {
821 DEBUG(0,(__location__ ": Failed attempt to use new assoc_group in alter context (0x%08x 0x%08x)\n",
822 call->context->assoc_group->id, call->pkt.u.alter.assoc_group_id));
823 /* TODO: can they ask for a new association group? */
824 result = DCERPC_BIND_PROVIDER_REJECT;
825 reason = DCERPC_BIND_REASON_ASYNTAX;
826 }
827
828 /* setup a alter_resp */
829 dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
830 pkt.auth_length = 0;
831 pkt.call_id = call->pkt.call_id;
832 pkt.ptype = DCERPC_PKT_ALTER_RESP;
833 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
834 pkt.u.alter_resp.max_xmit_frag = 0x2000;
835 pkt.u.alter_resp.max_recv_frag = 0x2000;
836 if (result == 0) {
837 pkt.u.alter_resp.assoc_group_id = call->context->assoc_group->id;
838 } else {
839 pkt.u.alter_resp.assoc_group_id = 0;
840 }
841 pkt.u.alter_resp.num_results = 1;
842 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
843 if (!pkt.u.alter_resp.ctx_list) {
844 return NT_STATUS_NO_MEMORY;
845 }
846 pkt.u.alter_resp.ctx_list[0].result = result;
847 pkt.u.alter_resp.ctx_list[0].reason = reason;
848 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
849 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
850 pkt.u.alter_resp.secondary_address = "";
851
852 status = dcesrv_auth_alter_ack(call, &pkt);
853 if (!NT_STATUS_IS_OK(status)) {
854 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
855 || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
856 || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
857 || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
858 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
859 }
860 return dcesrv_fault(call, 0);
861 }
862
863 rep = talloc(call, struct data_blob_list_item);
864 if (!rep) {
865 return NT_STATUS_NO_MEMORY;
866 }
867
868 status = ncacn_push_auth(&rep->blob, call, &pkt, call->conn->auth_state.auth_info);
869 if (!NT_STATUS_IS_OK(status)) {
870 return status;
871 }
872
873 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
874
875 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
876 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
877
878 if (call->conn->call_list && call->conn->call_list->replies) {
879 if (call->conn->transport.report_output_data) {
880 call->conn->transport.report_output_data(call->conn);
881 }
882 }
883
884 return NT_STATUS_OK;
885}
886
887/*
888 possibly save the call for inspection with ndrdump
889 */
890static void dcesrv_save_call(struct dcesrv_call_state *call, const char *why)
891{
892#ifdef DEVELOPER
893 char *fname;
894 const char *dump_dir;
895 dump_dir = lpcfg_parm_string(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv", "stubs directory");
896 if (!dump_dir) {
897 return;
898 }
899 fname = talloc_asprintf(call, "%s/RPC-%s-%u-%s.dat",
900 dump_dir,
901 call->context->iface->name,
902 call->pkt.u.request.opnum,
903 why);
904 if (file_save(fname, call->pkt.u.request.stub_and_verifier.data, call->pkt.u.request.stub_and_verifier.length)) {
905 DEBUG(0,("RPC SAVED %s\n", fname));
906 }
907 talloc_free(fname);
908#endif
909}
910
911/*
912 handle a dcerpc request packet
913*/
914static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
915{
916 struct ndr_pull *pull;
917 NTSTATUS status;
918 struct dcesrv_connection_context *context;
919
920 /* if authenticated, and the mech we use can't do async replies, don't use them... */
921 if (call->conn->auth_state.gensec_security &&
922 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
923 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
924 }
925
926 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
927 if (context == NULL) {
928 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
929 }
930
931 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
932 NT_STATUS_HAVE_NO_MEMORY(pull);
933
934 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
935
936 call->context = context;
937 call->ndr_pull = pull;
938
939 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
940 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
941 }
942
943 /* unravel the NDR for the packet */
944 status = context->iface->ndr_pull(call, call, pull, &call->r);
945 if (!NT_STATUS_IS_OK(status)) {
946 if (call->fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
947 /* we got an unknown call */
948 DEBUG(3,(__location__ ": Unknown RPC call %u on %s\n",
949 call->pkt.u.request.opnum, context->iface->name));
950 dcesrv_save_call(call, "unknown");
951 } else {
952 dcesrv_save_call(call, "pullfail");
953 }
954 return dcesrv_fault(call, call->fault_code);
955 }
956
957 if (pull->offset != pull->data_size) {
958 dcesrv_save_call(call, "extrabytes");
959 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
960 pull->data_size - pull->offset));
961 }
962
963 /* call the dispatch function */
964 status = context->iface->dispatch(call, call, call->r);
965 if (!NT_STATUS_IS_OK(status)) {
966 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
967 context->iface->name,
968 call->pkt.u.request.opnum,
969 dcerpc_errstr(pull, call->fault_code)));
970 return dcesrv_fault(call, call->fault_code);
971 }
972
973 /* add the call to the pending list */
974 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
975
976 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
977 return NT_STATUS_OK;
978 }
979
980 return dcesrv_reply(call);
981}
982
983
984/*
985 remove the call from the right list when freed
986 */
987static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
988{
989 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
990 return 0;
991}
992
993_PUBLIC_ const struct tsocket_address *dcesrv_connection_get_local_address(struct dcesrv_connection *conn)
994{
995 return conn->local_address;
996}
997
998_PUBLIC_ const struct tsocket_address *dcesrv_connection_get_remote_address(struct dcesrv_connection *conn)
999{
1000 return conn->remote_address;
1001}
1002
1003/*
1004 process some input to a dcerpc endpoint server.
1005*/
1006NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
1007 struct ncacn_packet *pkt,
1008 DATA_BLOB blob)
1009{
1010 NTSTATUS status;
1011 struct dcesrv_call_state *call;
1012
1013 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1014 if (!call) {
1015 data_blob_free(&blob);
1016 talloc_free(pkt);
1017 return NT_STATUS_NO_MEMORY;
1018 }
1019 call->conn = dce_conn;
1020 call->event_ctx = dce_conn->event_ctx;
1021 call->msg_ctx = dce_conn->msg_ctx;
1022 call->state_flags = call->conn->state_flags;
1023 call->time = timeval_current();
1024 call->list = DCESRV_LIST_NONE;
1025
1026 talloc_steal(call, pkt);
1027 talloc_steal(call, blob.data);
1028 call->pkt = *pkt;
1029
1030 talloc_set_destructor(call, dcesrv_call_dequeue);
1031
1032 /* we have to check the signing here, before combining the
1033 pdus */
1034 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1035 !dcesrv_auth_request(call, &blob)) {
1036 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1037 }
1038
1039 /* see if this is a continued packet */
1040 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1041 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1042 struct dcesrv_call_state *call2 = call;
1043 uint32_t alloc_size;
1044
1045 /* we only allow fragmented requests, no other packet types */
1046 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1047 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1048 }
1049
1050 /* this is a continuation of an existing call - find the call
1051 then tack it on the end */
1052 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1053 if (!call) {
1054 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1055 }
1056
1057 if (call->pkt.ptype != call2->pkt.ptype) {
1058 /* trying to play silly buggers are we? */
1059 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1060 }
1061
1062 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1063 call2->pkt.u.request.stub_and_verifier.length;
1064 if (call->pkt.u.request.alloc_hint > alloc_size) {
1065 alloc_size = call->pkt.u.request.alloc_hint;
1066 }
1067
1068 call->pkt.u.request.stub_and_verifier.data =
1069 talloc_realloc(call,
1070 call->pkt.u.request.stub_and_verifier.data,
1071 uint8_t, alloc_size);
1072 if (!call->pkt.u.request.stub_and_verifier.data) {
1073 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1074 }
1075 memcpy(call->pkt.u.request.stub_and_verifier.data +
1076 call->pkt.u.request.stub_and_verifier.length,
1077 call2->pkt.u.request.stub_and_verifier.data,
1078 call2->pkt.u.request.stub_and_verifier.length);
1079 call->pkt.u.request.stub_and_verifier.length +=
1080 call2->pkt.u.request.stub_and_verifier.length;
1081
1082 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1083
1084 talloc_free(call2);
1085 }
1086
1087 /* this may not be the last pdu in the chain - if its isn't then
1088 just put it on the incoming_fragmented_call_list and wait for the rest */
1089 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1090 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1091 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1092 return NT_STATUS_OK;
1093 }
1094
1095 /* This removes any fragments we may have had stashed away */
1096 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1097
1098 switch (call->pkt.ptype) {
1099 case DCERPC_PKT_BIND:
1100 status = dcesrv_bind(call);
1101 break;
1102 case DCERPC_PKT_AUTH3:
1103 status = dcesrv_auth3(call);
1104 break;
1105 case DCERPC_PKT_ALTER:
1106 status = dcesrv_alter(call);
1107 break;
1108 case DCERPC_PKT_REQUEST:
1109 status = dcesrv_request(call);
1110 break;
1111 default:
1112 status = NT_STATUS_INVALID_PARAMETER;
1113 break;
1114 }
1115
1116 /* if we are going to be sending a reply then add
1117 it to the list of pending calls. We add it to the end to keep the call
1118 list in the order we will answer */
1119 if (!NT_STATUS_IS_OK(status)) {
1120 talloc_free(call);
1121 }
1122
1123 return status;
1124}
1125
1126_PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
1127 struct loadparm_context *lp_ctx,
1128 const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1129{
1130 NTSTATUS status;
1131 struct dcesrv_context *dce_ctx;
1132 int i;
1133
1134 if (!endpoint_servers) {
1135 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1136 return NT_STATUS_INTERNAL_ERROR;
1137 }
1138
1139 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1140 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1141 dce_ctx->endpoint_list = NULL;
1142 dce_ctx->lp_ctx = lp_ctx;
1143 dce_ctx->assoc_groups_idr = idr_init(dce_ctx);
1144 NT_STATUS_HAVE_NO_MEMORY(dce_ctx->assoc_groups_idr);
1145
1146 for (i=0;endpoint_servers[i];i++) {
1147 const struct dcesrv_endpoint_server *ep_server;
1148
1149 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1150 if (!ep_server) {
1151 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1152 return NT_STATUS_INTERNAL_ERROR;
1153 }
1154
1155 status = ep_server->init_server(dce_ctx, ep_server);
1156 if (!NT_STATUS_IS_OK(status)) {
1157 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1158 nt_errstr(status)));
1159 return status;
1160 }
1161 }
1162
1163 *_dce_ctx = dce_ctx;
1164 return NT_STATUS_OK;
1165}
1166
1167/* the list of currently registered DCERPC endpoint servers.
1168 */
1169static struct ep_server {
1170 struct dcesrv_endpoint_server *ep_server;
1171} *ep_servers = NULL;
1172static int num_ep_servers;
1173
1174/*
1175 register a DCERPC endpoint server.
1176
1177 The 'name' can be later used by other backends to find the operations
1178 structure for this backend.
1179
1180 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1181*/
1182_PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1183{
1184 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1185
1186 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1187 /* its already registered! */
1188 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1189 ep_server->name));
1190 return NT_STATUS_OBJECT_NAME_COLLISION;
1191 }
1192
1193 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1194 if (!ep_servers) {
1195 smb_panic("out of memory in dcerpc_register");
1196 }
1197
1198 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1199 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1200
1201 num_ep_servers++;
1202
1203 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1204 ep_server->name));
1205
1206 return NT_STATUS_OK;
1207}
1208
1209/*
1210 return the operations structure for a named backend of the specified type
1211*/
1212const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1213{
1214 int i;
1215
1216 for (i=0;i<num_ep_servers;i++) {
1217 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1218 return ep_servers[i].ep_server;
1219 }
1220 }
1221
1222 return NULL;
1223}
1224
1225void dcerpc_server_init(struct loadparm_context *lp_ctx)
1226{
1227 static bool initialized;
1228#define _MODULE_PROTO(init) extern NTSTATUS init(void);
1229 STATIC_dcerpc_server_MODULES_PROTO;
1230 init_module_fn static_init[] = { STATIC_dcerpc_server_MODULES };
1231 init_module_fn *shared_init;
1232
1233 if (initialized) {
1234 return;
1235 }
1236 initialized = true;
1237
1238 shared_init = load_samba_modules(NULL, lp_ctx, "dcerpc_server");
1239
1240 run_init_functions(static_init);
1241 run_init_functions(shared_init);
1242
1243 talloc_free(shared_init);
1244}
1245
1246/*
1247 return the DCERPC module version, and the size of some critical types
1248 This can be used by endpoint server modules to either detect compilation errors, or provide
1249 multiple implementations for different smbd compilation options in one module
1250*/
1251const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1252{
1253 static const struct dcesrv_critical_sizes critical_sizes = {
1254 DCERPC_MODULE_VERSION,
1255 sizeof(struct dcesrv_context),
1256 sizeof(struct dcesrv_endpoint),
1257 sizeof(struct dcesrv_endpoint_server),
1258 sizeof(struct dcesrv_interface),
1259 sizeof(struct dcesrv_if_list),
1260 sizeof(struct dcesrv_connection),
1261 sizeof(struct dcesrv_call_state),
1262 sizeof(struct dcesrv_auth),
1263 sizeof(struct dcesrv_handle)
1264 };
1265
1266 return &critical_sizes;
1267}
1268
1269static void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, const char *reason)
1270{
1271 struct stream_connection *srv_conn;
1272 srv_conn = talloc_get_type(dce_conn->transport.private_data,
1273 struct stream_connection);
1274
1275 stream_terminate_connection(srv_conn, reason);
1276}
1277/* We need this include to be able to compile on some plateforms
1278 * (ie. freebsd 7.2) as it seems that <sys/uio.h> is not included
1279 * correctly.
1280 * It has to be that deep because otherwise we have a conflict on
1281 * const struct dcesrv_interface declaration.
1282 * This is mostly due to socket_wrapper defining #define bind swrap_bind
1283 * which conflict with the bind used before.
1284 */
1285#include "system/network.h"
1286
1287struct dcesrv_sock_reply_state {
1288 struct dcesrv_connection *dce_conn;
1289 struct dcesrv_call_state *call;
1290 struct iovec iov;
1291};
1292
1293static void dcesrv_sock_reply_done(struct tevent_req *subreq);
1294
1295static void dcesrv_sock_report_output_data(struct dcesrv_connection *dce_conn)
1296{
1297 struct dcesrv_call_state *call;
1298
1299 call = dce_conn->call_list;
1300 if (!call || !call->replies) {
1301 return;
1302 }
1303
1304 while (call->replies) {
1305 struct data_blob_list_item *rep = call->replies;
1306 struct dcesrv_sock_reply_state *substate;
1307 struct tevent_req *subreq;
1308
1309 substate = talloc(call, struct dcesrv_sock_reply_state);
1310 if (!substate) {
1311 dcesrv_terminate_connection(dce_conn, "no memory");
1312 return;
1313 }
1314
1315 substate->dce_conn = dce_conn;
1316 substate->call = NULL;
1317
1318 DLIST_REMOVE(call->replies, rep);
1319
1320 if (call->replies == NULL) {
1321 substate->call = call;
1322 }
1323
1324 substate->iov.iov_base = (void *) rep->blob.data;
1325 substate->iov.iov_len = rep->blob.length;
1326
1327 subreq = tstream_writev_queue_send(substate,
1328 dce_conn->event_ctx,
1329 dce_conn->stream,
1330 dce_conn->send_queue,
1331 &substate->iov, 1);
1332 if (!subreq) {
1333 dcesrv_terminate_connection(dce_conn, "no memory");
1334 return;
1335 }
1336 tevent_req_set_callback(subreq, dcesrv_sock_reply_done,
1337 substate);
1338 }
1339
1340 DLIST_REMOVE(call->conn->call_list, call);
1341 call->list = DCESRV_LIST_NONE;
1342}
1343
1344static void dcesrv_sock_reply_done(struct tevent_req *subreq)
1345{
1346 struct dcesrv_sock_reply_state *substate = tevent_req_callback_data(subreq,
1347 struct dcesrv_sock_reply_state);
1348 int ret;
1349 int sys_errno;
1350 NTSTATUS status;
1351 struct dcesrv_call_state *call = substate->call;
1352
1353 ret = tstream_writev_queue_recv(subreq, &sys_errno);
1354 TALLOC_FREE(subreq);
1355 if (ret == -1) {
1356 status = map_nt_error_from_unix(sys_errno);
1357 dcesrv_terminate_connection(substate->dce_conn, nt_errstr(status));
1358 return;
1359 }
1360
1361 talloc_free(substate);
1362 if (call) {
1363 talloc_free(call);
1364 }
1365}
1366
1367
1368
1369
1370struct dcesrv_socket_context {
1371 const struct dcesrv_endpoint *endpoint;
1372 struct dcesrv_context *dcesrv_ctx;
1373};
1374
1375
1376static void dcesrv_read_fragment_done(struct tevent_req *subreq);
1377
1378static void dcesrv_sock_accept(struct stream_connection *srv_conn)
1379{
1380 NTSTATUS status;
1381 struct dcesrv_socket_context *dcesrv_sock =
1382 talloc_get_type(srv_conn->private_data, struct dcesrv_socket_context);
1383 struct dcesrv_connection *dcesrv_conn = NULL;
1384 int ret;
1385 struct tevent_req *subreq;
1386 struct loadparm_context *lp_ctx = dcesrv_sock->dcesrv_ctx->lp_ctx;
1387
1388 if (!srv_conn->session_info) {
1389 status = auth_anonymous_session_info(srv_conn,
1390 lp_ctx,
1391 &srv_conn->session_info);
1392 if (!NT_STATUS_IS_OK(status)) {
1393 DEBUG(0,("dcesrv_sock_accept: auth_anonymous_session_info failed: %s\n",
1394 nt_errstr(status)));
1395 stream_terminate_connection(srv_conn, nt_errstr(status));
1396 return;
1397 }
1398 }
1399
1400 status = dcesrv_endpoint_connect(dcesrv_sock->dcesrv_ctx,
1401 srv_conn,
1402 dcesrv_sock->endpoint,
1403 srv_conn->session_info,
1404 srv_conn->event.ctx,
1405 srv_conn->msg_ctx,
1406 srv_conn->server_id,
1407 DCESRV_CALL_STATE_FLAG_MAY_ASYNC,
1408 &dcesrv_conn);
1409 if (!NT_STATUS_IS_OK(status)) {
1410 DEBUG(0,("dcesrv_sock_accept: dcesrv_endpoint_connect failed: %s\n",
1411 nt_errstr(status)));
1412 stream_terminate_connection(srv_conn, nt_errstr(status));
1413 return;
1414 }
1415
1416 dcesrv_conn->transport.private_data = srv_conn;
1417 dcesrv_conn->transport.report_output_data = dcesrv_sock_report_output_data;
1418
1419 TALLOC_FREE(srv_conn->event.fde);
1420
1421 dcesrv_conn->send_queue = tevent_queue_create(dcesrv_conn, "dcesrv send queue");
1422 if (!dcesrv_conn->send_queue) {
1423 status = NT_STATUS_NO_MEMORY;
1424 DEBUG(0,("dcesrv_sock_accept: tevent_queue_create(%s)\n",
1425 nt_errstr(status)));
1426 stream_terminate_connection(srv_conn, nt_errstr(status));
1427 return;
1428 }
1429
1430 if (dcesrv_sock->endpoint->ep_description->transport == NCACN_NP) {
1431 dcesrv_conn->auth_state.session_key = dcesrv_inherited_session_key;
1432 dcesrv_conn->stream = talloc_move(dcesrv_conn,
1433 &srv_conn->tstream);
1434 } else {
1435 ret = tstream_bsd_existing_socket(dcesrv_conn,
1436 socket_get_fd(srv_conn->socket),
1437 &dcesrv_conn->stream);
1438 if (ret == -1) {
1439 status = map_nt_error_from_unix(errno);
1440 DEBUG(0, ("dcesrv_sock_accept: "
1441 "failed to setup tstream: %s\n",
1442 nt_errstr(status)));
1443 stream_terminate_connection(srv_conn, nt_errstr(status));
1444 return;
1445 }
1446 socket_set_flags(srv_conn->socket, SOCKET_FLAG_NOCLOSE);
1447 }
1448
1449 dcesrv_conn->local_address = srv_conn->local_address;
1450 dcesrv_conn->remote_address = srv_conn->remote_address;
1451
1452 srv_conn->private_data = dcesrv_conn;
1453
1454 irpc_add_name(srv_conn->msg_ctx, "rpc_server");
1455
1456 subreq = dcerpc_read_ncacn_packet_send(dcesrv_conn,
1457 dcesrv_conn->event_ctx,
1458 dcesrv_conn->stream);
1459 if (!subreq) {
1460 status = NT_STATUS_NO_MEMORY;
1461 DEBUG(0,("dcesrv_sock_accept: dcerpc_read_fragment_buffer_send(%s)\n",
1462 nt_errstr(status)));
1463 stream_terminate_connection(srv_conn, nt_errstr(status));
1464 return;
1465 }
1466 tevent_req_set_callback(subreq, dcesrv_read_fragment_done, dcesrv_conn);
1467
1468 return;
1469}
1470
1471static void dcesrv_read_fragment_done(struct tevent_req *subreq)
1472{
1473 struct dcesrv_connection *dce_conn = tevent_req_callback_data(subreq,
1474 struct dcesrv_connection);
1475 struct ncacn_packet *pkt;
1476 DATA_BLOB buffer;
1477 NTSTATUS status;
1478
1479 status = dcerpc_read_ncacn_packet_recv(subreq, dce_conn,
1480 &pkt, &buffer);
1481 TALLOC_FREE(subreq);
1482 if (!NT_STATUS_IS_OK(status)) {
1483 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1484 return;
1485 }
1486
1487 status = dcesrv_process_ncacn_packet(dce_conn, pkt, buffer);
1488 if (!NT_STATUS_IS_OK(status)) {
1489 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1490 return;
1491 }
1492
1493 subreq = dcerpc_read_ncacn_packet_send(dce_conn,
1494 dce_conn->event_ctx,
1495 dce_conn->stream);
1496 if (!subreq) {
1497 status = NT_STATUS_NO_MEMORY;
1498 dcesrv_terminate_connection(dce_conn, nt_errstr(status));
1499 return;
1500 }
1501 tevent_req_set_callback(subreq, dcesrv_read_fragment_done, dce_conn);
1502}
1503
1504static void dcesrv_sock_recv(struct stream_connection *conn, uint16_t flags)
1505{
1506 struct dcesrv_connection *dce_conn = talloc_get_type(conn->private_data,
1507 struct dcesrv_connection);
1508 dcesrv_terminate_connection(dce_conn, "dcesrv_sock_recv triggered");
1509}
1510
1511static void dcesrv_sock_send(struct stream_connection *conn, uint16_t flags)
1512{
1513 struct dcesrv_connection *dce_conn = talloc_get_type(conn->private_data,
1514 struct dcesrv_connection);
1515 dcesrv_terminate_connection(dce_conn, "dcesrv_sock_send triggered");
1516}
1517
1518
1519static const struct stream_server_ops dcesrv_stream_ops = {
1520 .name = "rpc",
1521 .accept_connection = dcesrv_sock_accept,
1522 .recv_handler = dcesrv_sock_recv,
1523 .send_handler = dcesrv_sock_send,
1524};
1525
1526static NTSTATUS dcesrv_add_ep_unix(struct dcesrv_context *dce_ctx,
1527 struct loadparm_context *lp_ctx,
1528 struct dcesrv_endpoint *e,
1529 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1530{
1531 struct dcesrv_socket_context *dcesrv_sock;
1532 uint16_t port = 1;
1533 NTSTATUS status;
1534
1535 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1536 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1537
1538 /* remember the endpoint of this socket */
1539 dcesrv_sock->endpoint = e;
1540 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1541
1542 status = stream_setup_socket(dcesrv_sock, event_ctx, lp_ctx,
1543 model_ops, &dcesrv_stream_ops,
1544 "unix", e->ep_description->endpoint, &port,
1545 lpcfg_socket_options(lp_ctx),
1546 dcesrv_sock);
1547 if (!NT_STATUS_IS_OK(status)) {
1548 DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n",
1549 e->ep_description->endpoint, nt_errstr(status)));
1550 }
1551
1552 return status;
1553}
1554
1555static NTSTATUS dcesrv_add_ep_ncalrpc(struct dcesrv_context *dce_ctx,
1556 struct loadparm_context *lp_ctx,
1557 struct dcesrv_endpoint *e,
1558 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1559{
1560 struct dcesrv_socket_context *dcesrv_sock;
1561 uint16_t port = 1;
1562 char *full_path;
1563 NTSTATUS status;
1564
1565 if (!e->ep_description->endpoint) {
1566 /* No identifier specified: use DEFAULT.
1567 * DO NOT hardcode this value anywhere else. Rather, specify
1568 * no endpoint and let the epmapper worry about it. */
1569 e->ep_description->endpoint = talloc_strdup(dce_ctx, "DEFAULT");
1570 }
1571
1572 full_path = talloc_asprintf(dce_ctx, "%s/%s", lpcfg_ncalrpc_dir(lp_ctx),
1573 e->ep_description->endpoint);
1574
1575 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1576 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1577
1578 /* remember the endpoint of this socket */
1579 dcesrv_sock->endpoint = e;
1580 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1581
1582 status = stream_setup_socket(dcesrv_sock, event_ctx, lp_ctx,
1583 model_ops, &dcesrv_stream_ops,
1584 "unix", full_path, &port,
1585 lpcfg_socket_options(lp_ctx),
1586 dcesrv_sock);
1587 if (!NT_STATUS_IS_OK(status)) {
1588 DEBUG(0,("service_setup_stream_socket(identifier=%s,path=%s) failed - %s\n",
1589 e->ep_description->endpoint, full_path, nt_errstr(status)));
1590 }
1591 return status;
1592}
1593
1594static NTSTATUS dcesrv_add_ep_np(struct dcesrv_context *dce_ctx,
1595 struct loadparm_context *lp_ctx,
1596 struct dcesrv_endpoint *e,
1597 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1598{
1599 struct dcesrv_socket_context *dcesrv_sock;
1600 NTSTATUS status;
1601
1602 if (e->ep_description->endpoint == NULL) {
1603 DEBUG(0, ("Endpoint mandatory for named pipes\n"));
1604 return NT_STATUS_INVALID_PARAMETER;
1605 }
1606
1607 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1608 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1609
1610 /* remember the endpoint of this socket */
1611 dcesrv_sock->endpoint = e;
1612 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1613
1614 status = tstream_setup_named_pipe(dce_ctx, event_ctx, lp_ctx,
1615 model_ops, &dcesrv_stream_ops,
1616 e->ep_description->endpoint,
1617 dcesrv_sock);
1618 if (!NT_STATUS_IS_OK(status)) {
1619 DEBUG(0,("stream_setup_named_pipe(pipe=%s) failed - %s\n",
1620 e->ep_description->endpoint, nt_errstr(status)));
1621 return status;
1622 }
1623
1624 return NT_STATUS_OK;
1625}
1626
1627/*
1628 add a socket address to the list of events, one event per dcerpc endpoint
1629*/
1630static NTSTATUS add_socket_rpc_tcp_iface(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e,
1631 struct tevent_context *event_ctx, const struct model_ops *model_ops,
1632 const char *address)
1633{
1634 struct dcesrv_socket_context *dcesrv_sock;
1635 uint16_t port = 0;
1636 NTSTATUS status;
1637
1638 if (e->ep_description->endpoint) {
1639 port = atoi(e->ep_description->endpoint);
1640 }
1641
1642 dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context);
1643 NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock);
1644
1645 /* remember the endpoint of this socket */
1646 dcesrv_sock->endpoint = e;
1647 dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx);
1648
1649 status = stream_setup_socket(dcesrv_sock, event_ctx, dce_ctx->lp_ctx,
1650 model_ops, &dcesrv_stream_ops,
1651 "ipv4", address, &port,
1652 lpcfg_socket_options(dce_ctx->lp_ctx),
1653 dcesrv_sock);
1654 if (!NT_STATUS_IS_OK(status)) {
1655 DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) failed - %s\n",
1656 address, port, nt_errstr(status)));
1657 }
1658
1659 if (e->ep_description->endpoint == NULL) {
1660 e->ep_description->endpoint = talloc_asprintf(dce_ctx, "%d", port);
1661 }
1662
1663 return status;
1664}
1665
1666#include "lib/socket/netif.h" /* Included here to work around the fact that socket_wrapper redefines bind() */
1667
1668static NTSTATUS dcesrv_add_ep_tcp(struct dcesrv_context *dce_ctx,
1669 struct loadparm_context *lp_ctx,
1670 struct dcesrv_endpoint *e,
1671 struct tevent_context *event_ctx, const struct model_ops *model_ops)
1672{
1673 NTSTATUS status;
1674
1675 /* Add TCP/IP sockets */
1676 if (lpcfg_interfaces(lp_ctx) && lpcfg_bind_interfaces_only(lp_ctx)) {
1677 int num_interfaces;
1678 int i;
1679 struct interface *ifaces;
1680
1681 load_interfaces(dce_ctx, lpcfg_interfaces(lp_ctx), &ifaces);
1682
1683 num_interfaces = iface_count(ifaces);
1684 for(i = 0; i < num_interfaces; i++) {
1685 const char *address = iface_n_ip(ifaces, i);
1686 status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, address);
1687 NT_STATUS_NOT_OK_RETURN(status);
1688 }
1689 } else {
1690 status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops,
1691 lpcfg_socket_address(lp_ctx));
1692 NT_STATUS_NOT_OK_RETURN(status);
1693 }
1694
1695 return NT_STATUS_OK;
1696}
1697
1698NTSTATUS dcesrv_add_ep(struct dcesrv_context *dce_ctx,
1699 struct loadparm_context *lp_ctx,
1700 struct dcesrv_endpoint *e,
1701 struct tevent_context *event_ctx,
1702 const struct model_ops *model_ops)
1703{
1704 switch (e->ep_description->transport) {
1705 case NCACN_UNIX_STREAM:
1706 return dcesrv_add_ep_unix(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1707
1708 case NCALRPC:
1709 return dcesrv_add_ep_ncalrpc(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1710
1711 case NCACN_IP_TCP:
1712 return dcesrv_add_ep_tcp(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1713
1714 case NCACN_NP:
1715 return dcesrv_add_ep_np(dce_ctx, lp_ctx, e, event_ctx, model_ops);
1716
1717 default:
1718 return NT_STATUS_NOT_SUPPORTED;
1719 }
1720}
1721
1722
1723/**
1724 * retrieve credentials from a dce_call
1725 */
1726_PUBLIC_ struct cli_credentials *dcesrv_call_credentials(struct dcesrv_call_state *dce_call)
1727{
1728 return dce_call->conn->auth_state.session_info->credentials;
1729}
1730
1731/**
1732 * returns true if this is an authenticated call
1733 */
1734_PUBLIC_ bool dcesrv_call_authenticated(struct dcesrv_call_state *dce_call)
1735{
1736 enum security_user_level level;
1737 level = security_session_user_level(dce_call->conn->auth_state.session_info, NULL);
1738 return level >= SECURITY_USER;
1739}
1740
1741/**
1742 * retrieve account_name for a dce_call
1743 */
1744_PUBLIC_ const char *dcesrv_call_account_name(struct dcesrv_call_state *dce_call)
1745{
1746 return dce_call->context->conn->auth_state.session_info->info->account_name;
1747}
Note: See TracBrowser for help on using the repository browser.