r19598: Ahead of a merge to current lorikeet-heimdal:
[Samba.git] / source / rpc_server / dcerpc_server.c
blob08b68b2318f2effddff64dcfe403c94db05fbb88
1 /*
2 Unix SMB/CIFS implementation.
4 server side dcerpc core code
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) Stefan (metze) Metzmacher 2004-2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "includes.h"
25 #include "librpc/gen_ndr/ndr_dcerpc.h"
26 #include "auth/auth.h"
27 #include "auth/gensec/gensec.h"
28 #include "lib/util/dlinklist.h"
29 #include "rpc_server/dcerpc_server.h"
30 #include "lib/events/events.h"
31 #include "smbd/service_task.h"
32 #include "smbd/service_stream.h"
33 #include "smbd/service.h"
34 #include "system/filesys.h"
35 #include "libcli/security/security.h"
36 #include "build.h"
39 see if two endpoints match
41 static BOOL endpoints_match(const struct dcerpc_binding *ep1,
42 const struct dcerpc_binding *ep2)
44 if (ep1->transport != ep2->transport) {
45 return False;
48 if (!ep1->endpoint || !ep2->endpoint) {
49 return ep1->endpoint == ep2->endpoint;
52 if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
53 return False;
55 return True;
59 find an endpoint in the dcesrv_context
61 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
62 const struct dcerpc_binding *ep_description)
64 struct dcesrv_endpoint *ep;
65 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
66 if (endpoints_match(ep->ep_description, ep_description)) {
67 return ep;
70 return NULL;
74 find a registered context_id from a bind or alter_context
76 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn,
77 uint32_t context_id)
79 struct dcesrv_connection_context *c;
80 for (c=conn->contexts;c;c=c->next) {
81 if (c->context_id == context_id) return c;
83 return NULL;
87 see if a uuid and if_version match to an interface
89 static BOOL interface_match(const struct dcesrv_interface *if1,
90 const struct dcesrv_interface *if2)
92 return (if1->syntax_id.if_version == if2->syntax_id.if_version &&
93 GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
97 find the interface operations on an endpoint
99 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
100 const struct dcesrv_interface *iface)
102 struct dcesrv_if_list *ifl;
103 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
104 if (interface_match(&(ifl->iface), iface)) {
105 return &(ifl->iface);
108 return NULL;
112 see if a uuid and if_version match to an interface
114 static BOOL interface_match_by_uuid(const struct dcesrv_interface *iface,
115 const struct GUID *uuid, uint32_t if_version)
117 return (iface->syntax_id.if_version == if_version &&
118 GUID_equal(&iface->syntax_id.uuid, uuid));
122 find the interface operations on an endpoint by uuid
124 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
125 const struct GUID *uuid, uint32_t if_version)
127 struct dcesrv_if_list *ifl;
128 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
129 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
130 return &(ifl->iface);
133 return NULL;
137 find the earlier parts of a fragmented call awaiting reassembily
139 static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
141 struct dcesrv_call_state *c;
142 for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
143 if (c->pkt.call_id == call_id) {
144 return c;
147 return NULL;
151 register an interface on an endpoint
153 _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
154 const char *ep_name,
155 const struct dcesrv_interface *iface,
156 const struct security_descriptor *sd)
158 struct dcesrv_endpoint *ep;
159 struct dcesrv_if_list *ifl;
160 struct dcerpc_binding *binding;
161 BOOL add_ep = False;
162 NTSTATUS status;
164 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
166 if (NT_STATUS_IS_ERR(status)) {
167 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
168 return status;
171 /* check if this endpoint exists
173 if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
174 ep = talloc(dce_ctx, struct dcesrv_endpoint);
175 if (!ep) {
176 return NT_STATUS_NO_MEMORY;
178 ZERO_STRUCTP(ep);
179 ep->ep_description = talloc_reference(ep, binding);
180 add_ep = True;
183 /* see if the interface is already registered on te endpoint */
184 if (find_interface(ep, iface)!=NULL) {
185 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
186 iface->name, ep_name));
187 return NT_STATUS_OBJECT_NAME_COLLISION;
190 /* talloc a new interface list element */
191 ifl = talloc(dce_ctx, struct dcesrv_if_list);
192 if (!ifl) {
193 return NT_STATUS_NO_MEMORY;
196 /* copy the given interface struct to the one on the endpoints interface list */
197 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
199 /* if we have a security descriptor given,
200 * we should see if we can set it up on the endpoint
202 if (sd != NULL) {
203 /* if there's currently no security descriptor given on the endpoint
204 * we try to set it
206 if (ep->sd == NULL) {
207 ep->sd = security_descriptor_copy(dce_ctx, sd);
210 /* if now there's no security descriptor given on the endpoint
211 * something goes wrong, either we failed to copy the security descriptor
212 * or there was already one on the endpoint
214 if (ep->sd != NULL) {
215 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
216 " on endpoint '%s'\n",
217 iface->name, ep_name));
218 if (add_ep) free(ep);
219 free(ifl);
220 return NT_STATUS_OBJECT_NAME_COLLISION;
224 /* finally add the interface on the endpoint */
225 DLIST_ADD(ep->interface_list, ifl);
227 /* if it's a new endpoint add it to the dcesrv_context */
228 if (add_ep) {
229 DLIST_ADD(dce_ctx->endpoint_list, ep);
232 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
233 iface->name, ep_name));
235 return NT_STATUS_OK;
238 static NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
239 DATA_BLOB *session_key)
241 if (p->auth_state.session_info->session_key.length) {
242 *session_key = p->auth_state.session_info->session_key;
243 return NT_STATUS_OK;
245 return NT_STATUS_NO_USER_SESSION_KEY;
248 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
249 DATA_BLOB *session_key)
251 /* this took quite a few CPU cycles to find ... */
252 session_key->data = discard_const_p(uint8_t, "SystemLibraryDTC");
253 session_key->length = 16;
254 return NT_STATUS_OK;
258 fetch the user session key - may be default (above) or the SMB session key
260 _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
261 DATA_BLOB *session_key)
263 return p->auth_state.session_key(p, session_key);
268 destroy a link to an endpoint
270 static int dcesrv_endpoint_destructor(struct dcesrv_connection *p)
272 while (p->contexts) {
273 struct dcesrv_connection_context *c = p->contexts;
275 DLIST_REMOVE(p->contexts, c);
277 if (c->iface) {
278 c->iface->unbind(c, c->iface);
282 return 0;
287 connect to a dcerpc endpoint
289 NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
290 TALLOC_CTX *mem_ctx,
291 const struct dcesrv_endpoint *ep,
292 struct auth_session_info *session_info,
293 struct event_context *event_ctx,
294 struct messaging_context *msg_ctx,
295 uint32_t server_id,
296 uint32_t state_flags,
297 struct dcesrv_connection **_p)
299 struct dcesrv_connection *p;
301 if (!session_info) {
302 return NT_STATUS_ACCESS_DENIED;
305 p = talloc(mem_ctx, struct dcesrv_connection);
306 NT_STATUS_HAVE_NO_MEMORY(p);
308 if (!talloc_reference(p, session_info)) {
309 talloc_free(p);
310 return NT_STATUS_NO_MEMORY;
313 p->dce_ctx = dce_ctx;
314 p->endpoint = ep;
315 p->contexts = NULL;
316 p->call_list = NULL;
317 p->incoming_fragmented_call_list = NULL;
318 p->pending_call_list = NULL;
319 p->cli_max_recv_frag = 0;
320 p->partial_input = data_blob(NULL, 0);
321 p->auth_state.auth_info = NULL;
322 p->auth_state.gensec_security = NULL;
323 p->auth_state.session_info = session_info;
324 p->auth_state.session_key = dcesrv_generic_session_key;
325 p->event_ctx = event_ctx;
326 p->msg_ctx = msg_ctx;
327 p->server_id = server_id;
328 p->processing = False;
329 p->state_flags = state_flags;
330 ZERO_STRUCT(p->transport);
332 talloc_set_destructor(p, dcesrv_endpoint_destructor);
334 *_p = p;
335 return NT_STATUS_OK;
339 search and connect to a dcerpc endpoint
341 _PUBLIC_ NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
342 TALLOC_CTX *mem_ctx,
343 const struct dcerpc_binding *ep_description,
344 struct auth_session_info *session_info,
345 struct event_context *event_ctx,
346 struct messaging_context *msg_ctx,
347 uint32_t server_id,
348 uint32_t state_flags,
349 struct dcesrv_connection **dce_conn_p)
351 NTSTATUS status;
352 const struct dcesrv_endpoint *ep;
354 /* make sure this endpoint exists */
355 ep = find_endpoint(dce_ctx, ep_description);
356 if (!ep) {
357 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
360 status = dcesrv_endpoint_connect(dce_ctx, mem_ctx, ep, session_info,
361 event_ctx, msg_ctx, server_id,
362 state_flags, dce_conn_p);
363 NT_STATUS_NOT_OK_RETURN(status);
365 (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
367 /* TODO: check security descriptor of the endpoint here
368 * if it's a smb named pipe
369 * if it's failed free dce_conn_p
372 return NT_STATUS_OK;
376 static void dcesrv_init_hdr(struct ncacn_packet *pkt)
378 pkt->rpc_vers = 5;
379 pkt->rpc_vers_minor = 0;
380 if (lp_rpc_big_endian()) {
381 pkt->drep[0] = 0;
382 } else {
383 pkt->drep[0] = DCERPC_DREP_LE;
385 pkt->drep[1] = 0;
386 pkt->drep[2] = 0;
387 pkt->drep[3] = 0;
391 return a dcerpc fault
393 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
395 struct ncacn_packet pkt;
396 struct data_blob_list_item *rep;
397 NTSTATUS status;
399 /* setup a bind_ack */
400 dcesrv_init_hdr(&pkt);
401 pkt.auth_length = 0;
402 pkt.call_id = call->pkt.call_id;
403 pkt.ptype = DCERPC_PKT_FAULT;
404 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
405 pkt.u.fault.alloc_hint = 0;
406 pkt.u.fault.context_id = 0;
407 pkt.u.fault.cancel_count = 0;
408 pkt.u.fault.status = fault_code;
410 rep = talloc(call, struct data_blob_list_item);
411 if (!rep) {
412 return NT_STATUS_NO_MEMORY;
415 status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
416 if (!NT_STATUS_IS_OK(status)) {
417 return status;
420 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
422 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
423 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
425 return NT_STATUS_OK;
430 return a dcerpc bind_nak
432 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
434 struct ncacn_packet pkt;
435 struct data_blob_list_item *rep;
436 NTSTATUS status;
438 /* setup a bind_nak */
439 dcesrv_init_hdr(&pkt);
440 pkt.auth_length = 0;
441 pkt.call_id = call->pkt.call_id;
442 pkt.ptype = DCERPC_PKT_BIND_NAK;
443 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
444 pkt.u.bind_nak.reject_reason = reason;
445 if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
446 pkt.u.bind_nak.versions.v.num_versions = 0;
449 rep = talloc(call, struct data_blob_list_item);
450 if (!rep) {
451 return NT_STATUS_NO_MEMORY;
454 status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
455 if (!NT_STATUS_IS_OK(status)) {
456 return status;
459 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
461 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
462 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
464 return NT_STATUS_OK;
469 handle a bind request
471 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
473 uint32_t if_version, transfer_syntax_version;
474 struct GUID uuid, *transfer_syntax_uuid;
475 struct ncacn_packet pkt;
476 struct data_blob_list_item *rep;
477 NTSTATUS status;
478 uint32_t result=0, reason=0;
479 uint32_t context_id;
480 const struct dcesrv_interface *iface;
482 if (call->pkt.u.bind.num_contexts < 1 ||
483 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
484 return dcesrv_bind_nak(call, 0);
487 context_id = call->pkt.u.bind.ctx_list[0].context_id;
489 /* you can't bind twice on one context */
490 if (dcesrv_find_context(call->conn, context_id) != NULL) {
491 return dcesrv_bind_nak(call, 0);
494 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
495 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
497 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
498 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
499 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
500 ndr_transfer_syntax.if_version != transfer_syntax_version) {
501 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
502 /* we only do NDR encoded dcerpc */
503 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
504 talloc_free(uuid_str);
505 return dcesrv_bind_nak(call, 0);
508 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
509 if (iface == NULL) {
510 char *uuid_str = GUID_string(call, &uuid);
511 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
512 talloc_free(uuid_str);
514 /* we don't know about that interface */
515 result = DCERPC_BIND_PROVIDER_REJECT;
516 reason = DCERPC_BIND_REASON_ASYNTAX;
519 if (iface) {
520 /* add this context to the list of available context_ids */
521 struct dcesrv_connection_context *context = talloc(call->conn,
522 struct dcesrv_connection_context);
523 if (context == NULL) {
524 return dcesrv_bind_nak(call, 0);
526 context->conn = call->conn;
527 context->iface = iface;
528 context->context_id = context_id;
529 context->private = NULL;
530 context->handles = NULL;
531 DLIST_ADD(call->conn->contexts, context);
532 call->context = context;
535 if (call->conn->cli_max_recv_frag == 0) {
536 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
539 /* handle any authentication that is being requested */
540 if (!dcesrv_auth_bind(call)) {
541 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
544 /* setup a bind_ack */
545 dcesrv_init_hdr(&pkt);
546 pkt.auth_length = 0;
547 pkt.call_id = call->pkt.call_id;
548 pkt.ptype = DCERPC_PKT_BIND_ACK;
549 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
550 pkt.u.bind_ack.max_xmit_frag = 0x2000;
551 pkt.u.bind_ack.max_recv_frag = 0x2000;
552 pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
553 if (iface) {
554 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
555 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
556 } else {
557 pkt.u.bind_ack.secondary_address = "";
559 pkt.u.bind_ack.num_results = 1;
560 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
561 if (!pkt.u.bind_ack.ctx_list) {
562 return NT_STATUS_NO_MEMORY;
564 pkt.u.bind_ack.ctx_list[0].result = result;
565 pkt.u.bind_ack.ctx_list[0].reason = reason;
566 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
567 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
569 if (!dcesrv_auth_bind_ack(call, &pkt)) {
570 return dcesrv_bind_nak(call, 0);
573 if (iface) {
574 status = iface->bind(call, iface);
575 if (!NT_STATUS_IS_OK(status)) {
576 char *uuid_str = GUID_string(call, &uuid);
577 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
578 uuid_str, if_version, nt_errstr(status)));
579 talloc_free(uuid_str);
580 return dcesrv_bind_nak(call, 0);
584 rep = talloc(call, struct data_blob_list_item);
585 if (!rep) {
586 return NT_STATUS_NO_MEMORY;
589 status = ncacn_push_auth(&rep->blob, call, &pkt,
590 call->conn->auth_state.auth_info);
591 if (!NT_STATUS_IS_OK(status)) {
592 return status;
595 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
597 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
598 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
600 return NT_STATUS_OK;
605 handle a auth3 request
607 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
609 /* handle the auth3 in the auth code */
610 if (!dcesrv_auth_auth3(call)) {
611 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
614 talloc_free(call);
616 /* we don't send a reply to a auth3 request, except by a
617 fault */
618 return NT_STATUS_OK;
623 handle a bind request
625 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
627 uint32_t if_version, transfer_syntax_version;
628 struct dcesrv_connection_context *context;
629 const struct dcesrv_interface *iface;
630 struct GUID uuid, *transfer_syntax_uuid;
632 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
633 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
635 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
636 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
637 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
638 ndr_transfer_syntax.if_version != transfer_syntax_version) {
639 /* we only do NDR encoded dcerpc */
640 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
643 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
644 if (iface == NULL) {
645 char *uuid_str = GUID_string(call, &uuid);
646 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
647 talloc_free(uuid_str);
648 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
651 /* add this context to the list of available context_ids */
652 context = talloc(call->conn, struct dcesrv_connection_context);
653 if (context == NULL) {
654 return NT_STATUS_NO_MEMORY;
656 context->conn = call->conn;
657 context->iface = iface;
658 context->context_id = context_id;
659 context->private = NULL;
660 context->handles = NULL;
661 DLIST_ADD(call->conn->contexts, context);
662 call->context = context;
664 return NT_STATUS_OK;
669 handle a alter context request
671 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
673 struct ncacn_packet pkt;
674 struct data_blob_list_item *rep;
675 NTSTATUS status;
676 uint32_t result=0, reason=0;
677 uint32_t context_id;
679 /* handle any authentication that is being requested */
680 if (!dcesrv_auth_alter(call)) {
681 /* TODO: work out the right reject code */
682 result = DCERPC_BIND_PROVIDER_REJECT;
683 reason = DCERPC_BIND_REASON_ASYNTAX;
686 context_id = call->pkt.u.alter.ctx_list[0].context_id;
688 /* see if they are asking for a new interface */
689 if (result == 0 &&
690 dcesrv_find_context(call->conn, context_id) == NULL) {
691 status = dcesrv_alter_new_context(call, context_id);
692 if (!NT_STATUS_IS_OK(status)) {
693 result = DCERPC_BIND_PROVIDER_REJECT;
694 reason = DCERPC_BIND_REASON_ASYNTAX;
698 /* setup a alter_resp */
699 dcesrv_init_hdr(&pkt);
700 pkt.auth_length = 0;
701 pkt.call_id = call->pkt.call_id;
702 pkt.ptype = DCERPC_PKT_ALTER_RESP;
703 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
704 pkt.u.alter_resp.max_xmit_frag = 0x2000;
705 pkt.u.alter_resp.max_recv_frag = 0x2000;
706 pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
707 pkt.u.alter_resp.num_results = 1;
708 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
709 if (!pkt.u.alter_resp.ctx_list) {
710 return NT_STATUS_NO_MEMORY;
712 pkt.u.alter_resp.ctx_list[0].result = result;
713 pkt.u.alter_resp.ctx_list[0].reason = reason;
714 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
715 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
716 pkt.u.alter_resp.secondary_address = "";
718 if (!dcesrv_auth_alter_ack(call, &pkt)) {
719 return dcesrv_bind_nak(call, 0);
722 rep = talloc(call, struct data_blob_list_item);
723 if (!rep) {
724 return NT_STATUS_NO_MEMORY;
727 status = ncacn_push_auth(&rep->blob, call, &pkt,
728 call->conn->auth_state.auth_info);
729 if (!NT_STATUS_IS_OK(status)) {
730 return status;
733 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
735 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
736 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
738 return NT_STATUS_OK;
742 handle a dcerpc request packet
744 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
746 struct ndr_pull *pull;
747 NTSTATUS status;
748 struct dcesrv_connection_context *context;
750 /* if authenticated, and the mech we use can't do async replies, don't use them... */
751 if (call->conn->auth_state.gensec_security &&
752 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
753 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
756 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
757 if (context == NULL) {
758 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
761 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
762 NT_STATUS_HAVE_NO_MEMORY(pull);
764 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
766 call->context = context;
767 call->ndr_pull = pull;
769 if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_ORPC) {
770 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
773 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
774 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
777 /* unravel the NDR for the packet */
778 status = context->iface->ndr_pull(call, call, pull, &call->r);
779 if (!NT_STATUS_IS_OK(status)) {
780 return dcesrv_fault(call, call->fault_code);
783 if (pull->offset != pull->data_size) {
784 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
785 pull->data_size - pull->offset));
786 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
789 /* call the dispatch function */
790 status = context->iface->dispatch(call, call, call->r);
791 if (!NT_STATUS_IS_OK(status)) {
792 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
793 context->iface->name,
794 call->pkt.u.request.opnum,
795 dcerpc_errstr(pull, call->fault_code)));
796 return dcesrv_fault(call, call->fault_code);
799 /* add the call to the pending list */
800 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
802 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
803 return NT_STATUS_OK;
806 return dcesrv_reply(call);
809 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
811 struct ndr_push *push;
812 NTSTATUS status;
813 DATA_BLOB stub;
814 uint32_t total_length;
815 struct dcesrv_connection_context *context = call->context;
817 /* call the reply function */
818 status = context->iface->reply(call, call, call->r);
819 if (!NT_STATUS_IS_OK(status)) {
820 return dcesrv_fault(call, call->fault_code);
823 /* form the reply NDR */
824 push = ndr_push_init_ctx(call);
825 NT_STATUS_HAVE_NO_MEMORY(push);
827 /* carry over the pointer count to the reply in case we are
828 using full pointer. See NDR specification for full
829 pointers */
830 push->ptr_count = call->ndr_pull->ptr_count;
832 if (lp_rpc_big_endian()) {
833 push->flags |= LIBNDR_FLAG_BIGENDIAN;
836 status = context->iface->ndr_push(call, call, push, call->r);
837 if (!NT_STATUS_IS_OK(status)) {
838 return dcesrv_fault(call, call->fault_code);
841 stub = ndr_push_blob(push);
843 total_length = stub.length;
845 do {
846 uint32_t length;
847 struct data_blob_list_item *rep;
848 struct ncacn_packet pkt;
850 rep = talloc(call, struct data_blob_list_item);
851 NT_STATUS_HAVE_NO_MEMORY(rep);
853 length = stub.length;
854 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
855 /* the 32 is to cope with signing data */
856 length = call->conn->cli_max_recv_frag -
857 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
860 /* form the dcerpc response packet */
861 dcesrv_init_hdr(&pkt);
862 pkt.auth_length = 0;
863 pkt.call_id = call->pkt.call_id;
864 pkt.ptype = DCERPC_PKT_RESPONSE;
865 pkt.pfc_flags = 0;
866 if (stub.length == total_length) {
867 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
869 if (length == stub.length) {
870 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
872 pkt.u.response.alloc_hint = stub.length;
873 pkt.u.response.context_id = call->pkt.u.request.context_id;
874 pkt.u.response.cancel_count = 0;
875 pkt.u.response.stub_and_verifier.data = stub.data;
876 pkt.u.response.stub_and_verifier.length = length;
878 if (!dcesrv_auth_response(call, &rep->blob, &pkt)) {
879 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
882 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
884 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
886 stub.data += length;
887 stub.length -= length;
888 } while (stub.length != 0);
890 /* move the call from the pending to the finished calls list */
891 DLIST_REMOVE(call->conn->pending_call_list, call);
892 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
894 if (call->conn->call_list && call->conn->call_list->replies) {
895 if (call->conn->transport.report_output_data) {
896 call->conn->transport.report_output_data(call->conn);
900 return NT_STATUS_OK;
903 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
905 if (!conn->transport.get_my_addr) {
906 return NULL;
909 return conn->transport.get_my_addr(conn, mem_ctx);
912 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
914 if (!conn->transport.get_peer_addr) {
915 return NULL;
918 return conn->transport.get_peer_addr(conn, mem_ctx);
922 work out if we have a full packet yet
924 static BOOL dce_full_packet(const DATA_BLOB *data)
926 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
927 return False;
929 if (dcerpc_get_frag_length(data) > data->length) {
930 return False;
932 return True;
936 we might have consumed only part of our input - advance past that part
938 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
940 DATA_BLOB blob;
942 if (dce_conn->partial_input.length == offset) {
943 data_blob_free(&dce_conn->partial_input);
944 return;
947 blob = dce_conn->partial_input;
948 dce_conn->partial_input = data_blob(blob.data + offset,
949 blob.length - offset);
950 data_blob_free(&blob);
954 process some input to a dcerpc endpoint server.
956 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
958 struct ndr_pull *ndr;
959 NTSTATUS status;
960 struct dcesrv_call_state *call;
961 DATA_BLOB blob;
963 call = talloc_zero(dce_conn, struct dcesrv_call_state);
964 if (!call) {
965 talloc_free(dce_conn->partial_input.data);
966 return NT_STATUS_NO_MEMORY;
968 call->conn = dce_conn;
969 call->event_ctx = dce_conn->event_ctx;
970 call->msg_ctx = dce_conn->msg_ctx;
971 call->state_flags = call->conn->state_flags;
972 call->time = timeval_current();
974 blob = dce_conn->partial_input;
975 blob.length = dcerpc_get_frag_length(&blob);
977 ndr = ndr_pull_init_blob(&blob, call);
978 if (!ndr) {
979 talloc_free(dce_conn->partial_input.data);
980 talloc_free(call);
981 return NT_STATUS_NO_MEMORY;
984 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
985 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
988 status = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
989 if (!NT_STATUS_IS_OK(status)) {
990 talloc_free(dce_conn->partial_input.data);
991 talloc_free(call);
992 return status;
995 /* we have to check the signing here, before combining the
996 pdus */
997 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
998 !dcesrv_auth_request(call, &blob)) {
999 dce_partial_advance(dce_conn, blob.length);
1000 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1003 dce_partial_advance(dce_conn, blob.length);
1005 /* see if this is a continued packet */
1006 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1007 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1008 struct dcesrv_call_state *call2 = call;
1009 uint32_t alloc_size;
1011 /* we only allow fragmented requests, no other packet types */
1012 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1013 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1016 /* this is a continuation of an existing call - find the call then
1017 tack it on the end */
1018 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1019 if (!call) {
1020 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1023 if (call->pkt.ptype != call2->pkt.ptype) {
1024 /* trying to play silly buggers are we? */
1025 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1028 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1029 call2->pkt.u.request.stub_and_verifier.length;
1030 if (call->pkt.u.request.alloc_hint > alloc_size) {
1031 alloc_size = call->pkt.u.request.alloc_hint;
1034 call->pkt.u.request.stub_and_verifier.data =
1035 talloc_realloc(call,
1036 call->pkt.u.request.stub_and_verifier.data,
1037 uint8_t, alloc_size);
1038 if (!call->pkt.u.request.stub_and_verifier.data) {
1039 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1041 memcpy(call->pkt.u.request.stub_and_verifier.data +
1042 call->pkt.u.request.stub_and_verifier.length,
1043 call2->pkt.u.request.stub_and_verifier.data,
1044 call2->pkt.u.request.stub_and_verifier.length);
1045 call->pkt.u.request.stub_and_verifier.length +=
1046 call2->pkt.u.request.stub_and_verifier.length;
1048 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1050 talloc_free(call2);
1053 /* this may not be the last pdu in the chain - if its isn't then
1054 just put it on the incoming_fragmented_call_list and wait for the rest */
1055 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1056 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1057 DLIST_ADD_END(dce_conn->incoming_fragmented_call_list, call,
1058 struct dcesrv_call_state *);
1059 return NT_STATUS_OK;
1062 /* This removes any fragments we may have had stashed away */
1063 DLIST_REMOVE(dce_conn->incoming_fragmented_call_list, call);
1065 switch (call->pkt.ptype) {
1066 case DCERPC_PKT_BIND:
1067 status = dcesrv_bind(call);
1068 break;
1069 case DCERPC_PKT_AUTH3:
1070 status = dcesrv_auth3(call);
1071 break;
1072 case DCERPC_PKT_ALTER:
1073 status = dcesrv_alter(call);
1074 break;
1075 case DCERPC_PKT_REQUEST:
1076 status = dcesrv_request(call);
1077 break;
1078 default:
1079 status = NT_STATUS_INVALID_PARAMETER;
1080 break;
1083 /* if we are going to be sending a reply then add
1084 it to the list of pending calls. We add it to the end to keep the call
1085 list in the order we will answer */
1086 if (!NT_STATUS_IS_OK(status)) {
1087 talloc_free(call);
1090 return status;
1095 provide some input to a dcerpc endpoint server. This passes data
1096 from a dcerpc client into the server
1098 _PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1100 NTSTATUS status;
1102 dce_conn->partial_input.data = talloc_realloc(dce_conn,
1103 dce_conn->partial_input.data,
1104 uint8_t,
1105 dce_conn->partial_input.length + data->length);
1106 if (!dce_conn->partial_input.data) {
1107 return NT_STATUS_NO_MEMORY;
1109 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1110 data->data, data->length);
1111 dce_conn->partial_input.length += data->length;
1113 while (dce_full_packet(&dce_conn->partial_input)) {
1114 status = dcesrv_input_process(dce_conn);
1115 if (!NT_STATUS_IS_OK(status)) {
1116 return status;
1120 return NT_STATUS_OK;
1124 retrieve some output from a dcerpc server
1125 The caller supplies a function that will be called to do the
1126 actual output.
1128 The first argument to write_fn() will be 'private', the second will
1129 be a pointer to a buffer containing the data to be sent and the 3rd
1130 will be a pointer to a size_t variable that will be set to the
1131 number of bytes that are consumed from the output.
1133 from the current fragment
1135 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
1136 void *private_data,
1137 NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1139 NTSTATUS status;
1140 struct dcesrv_call_state *call;
1141 struct data_blob_list_item *rep;
1142 size_t nwritten;
1144 call = dce_conn->call_list;
1145 if (!call || !call->replies) {
1146 if (dce_conn->pending_call_list) {
1147 /* TODO: we need to say act async here
1148 * as we know we have pending requests
1149 * which will be finished at a time
1151 return NT_STATUS_FOOBAR;
1153 return NT_STATUS_FOOBAR;
1155 rep = call->replies;
1157 status = write_fn(private_data, &rep->blob, &nwritten);
1158 NT_STATUS_IS_ERR_RETURN(status);
1160 rep->blob.length -= nwritten;
1161 rep->blob.data += nwritten;
1163 if (rep->blob.length == 0) {
1164 /* we're done with this section of the call */
1165 DLIST_REMOVE(call->replies, rep);
1168 if (call->replies == NULL) {
1169 /* we're done with the whole call */
1170 DLIST_REMOVE(dce_conn->call_list, call);
1171 talloc_free(call);
1174 return status;
1177 static NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1179 NTSTATUS status;
1180 struct dcesrv_context *dce_ctx;
1181 int i;
1183 if (!endpoint_servers) {
1184 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1185 return NT_STATUS_INTERNAL_ERROR;
1188 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1189 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1190 dce_ctx->endpoint_list = NULL;
1192 for (i=0;endpoint_servers[i];i++) {
1193 const struct dcesrv_endpoint_server *ep_server;
1195 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1196 if (!ep_server) {
1197 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1198 return NT_STATUS_INTERNAL_ERROR;
1201 status = ep_server->init_server(dce_ctx, ep_server);
1202 if (!NT_STATUS_IS_OK(status)) {
1203 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1204 nt_errstr(status)));
1205 return status;
1209 *_dce_ctx = dce_ctx;
1210 return NT_STATUS_OK;
1214 initialise the dcerpc server context for ncacn_np based services
1216 _PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **_dce_ctx)
1218 NTSTATUS status;
1219 struct dcesrv_context *dce_ctx;
1221 status = dcesrv_init_context(mem_ctx, lp_dcerpc_endpoint_servers(), &dce_ctx);
1222 NT_STATUS_NOT_OK_RETURN(status);
1224 *_dce_ctx = dce_ctx;
1225 return NT_STATUS_OK;
1228 /* the list of currently registered DCERPC endpoint servers.
1230 static struct ep_server {
1231 struct dcesrv_endpoint_server *ep_server;
1232 } *ep_servers = NULL;
1233 static int num_ep_servers;
1236 register a DCERPC endpoint server.
1238 The 'name' can be later used by other backends to find the operations
1239 structure for this backend.
1241 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1243 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1245 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1247 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1248 /* its already registered! */
1249 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1250 ep_server->name));
1251 return NT_STATUS_OBJECT_NAME_COLLISION;
1254 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1255 if (!ep_servers) {
1256 smb_panic("out of memory in dcerpc_register");
1259 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1260 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1262 num_ep_servers++;
1264 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1265 ep_server->name));
1267 return NT_STATUS_OK;
1271 return the operations structure for a named backend of the specified type
1273 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1275 int i;
1277 for (i=0;i<num_ep_servers;i++) {
1278 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1279 return ep_servers[i].ep_server;
1283 return NULL;
1287 return the DCERPC module version, and the size of some critical types
1288 This can be used by endpoint server modules to either detect compilation errors, or provide
1289 multiple implementations for different smbd compilation options in one module
1291 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1293 static const struct dcesrv_critical_sizes critical_sizes = {
1294 DCERPC_MODULE_VERSION,
1295 sizeof(struct dcesrv_context),
1296 sizeof(struct dcesrv_endpoint),
1297 sizeof(struct dcesrv_endpoint_server),
1298 sizeof(struct dcesrv_interface),
1299 sizeof(struct dcesrv_if_list),
1300 sizeof(struct dcesrv_connection),
1301 sizeof(struct dcesrv_call_state),
1302 sizeof(struct dcesrv_auth),
1303 sizeof(struct dcesrv_handle)
1306 return &critical_sizes;
1310 open the dcerpc server sockets
1312 static void dcesrv_task_init(struct task_server *task)
1314 NTSTATUS status;
1315 struct dcesrv_context *dce_ctx;
1316 struct dcesrv_endpoint *e;
1318 task_server_set_title(task, "task[dcesrv]");
1320 status = dcesrv_init_context(task->event_ctx,
1321 lp_dcerpc_endpoint_servers(),
1322 &dce_ctx);
1323 if (!NT_STATUS_IS_OK(status)) goto failed;
1325 /* Make sure the directory for NCALRPC exists */
1326 if (!directory_exist(lp_ncalrpc_dir())) {
1327 mkdir(lp_ncalrpc_dir(), 0755);
1330 for (e=dce_ctx->endpoint_list;e;e=e->next) {
1331 switch (e->ep_description->transport) {
1332 case NCACN_UNIX_STREAM:
1333 status = dcesrv_add_ep_unix(dce_ctx, e, task->event_ctx, task->model_ops);
1334 if (!NT_STATUS_IS_OK(status)) goto failed;
1335 break;
1337 case NCALRPC:
1338 status = dcesrv_add_ep_ncalrpc(dce_ctx, e, task->event_ctx, task->model_ops);
1339 if (!NT_STATUS_IS_OK(status)) goto failed;
1340 break;
1342 case NCACN_IP_TCP:
1343 status = dcesrv_add_ep_tcp(dce_ctx, e, task->event_ctx, task->model_ops);
1344 if (!NT_STATUS_IS_OK(status)) goto failed;
1345 break;
1347 case NCACN_NP:
1348 /* FIXME: status = dcesrv_add_ep_np(dce_ctx, e, task->event_ctx, task->model_ops);
1349 if (!NT_STATUS_IS_OK(status)) goto failed;
1350 */ break;
1352 default:
1353 status = NT_STATUS_NOT_SUPPORTED;
1354 if (!NT_STATUS_IS_OK(status)) goto failed;
1358 return;
1359 failed:
1360 task_server_terminate(task, "Failed to startup dcerpc server task");
1364 called on startup of the smb server service It's job is to start
1365 listening on all configured sockets
1367 static NTSTATUS dcesrv_init(struct event_context *event_context,
1368 const struct model_ops *model_ops)
1370 return task_server_startup(event_context, model_ops, dcesrv_task_init);
1373 NTSTATUS server_service_rpc_init(void)
1375 init_module_fn static_init[] = STATIC_dcerpc_server_MODULES;
1376 init_module_fn *shared_init = load_samba_modules(NULL, "dcerpc_server");
1378 run_init_functions(static_init);
1379 run_init_functions(shared_init);
1381 talloc_free(shared_init);
1383 return register_server_service("rpc", dcesrv_init);