r4640: first stage in the server side support for multiple context_ids on one pipe
[Samba/gebeck_regimport.git] / source4 / rpc_server / dcerpc_server.c
blob808cad94d9c35da905e00c47b497e6e45ac2b5d8
1 /*
2 Unix SMB/CIFS implementation.
4 server side dcerpc core code
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Stefan (metze) Metzmacher 2004
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_epmapper.h"
26 #include "librpc/gen_ndr/ndr_oxidresolver.h"
27 #include "auth/auth.h"
28 #include "dlinklist.h"
29 #include "rpc_server/dcerpc_server.h"
32 see if two endpoints match
34 static BOOL endpoints_match(const struct dcerpc_binding *ep1,
35 const struct dcerpc_binding *ep2)
37 if (ep1->transport != ep2->transport) {
38 return False;
41 if (!ep1->endpoint || !ep2->endpoint) {
42 return ep1->endpoint == ep2->endpoint;
45 if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
46 return False;
48 return True;
52 find an endpoint in the dcesrv_context
54 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
55 const struct dcerpc_binding *ep_description)
57 struct dcesrv_endpoint *ep;
58 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
59 if (endpoints_match(&ep->ep_description, ep_description)) {
60 return ep;
63 return NULL;
67 find a registered context_id from a bind or alter_context
69 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn,
70 uint32_t context_id)
72 struct dcesrv_connection_context *c;
73 for (c=conn->contexts;c;c=c->next) {
74 if (c->context_id == context_id) return c;
76 return NULL;
80 see if a uuid and if_version match to an interface
82 static BOOL interface_match(const struct dcesrv_interface *if1,
83 const struct dcesrv_interface *if2)
85 if (if1->if_version != if2->if_version) {
86 return False;
89 if (strcmp(if1->uuid, if2->uuid)==0) {
90 return True;
93 return False;
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 char *uuid, uint32_t if_version)
117 if (iface->if_version != if_version) {
118 return False;
121 if (strcmp(iface->uuid, uuid)==0) {
122 return True;
125 return False;
129 find the interface operations on an endpoint by uuid
131 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
132 const char *uuid, uint32_t if_version)
134 struct dcesrv_if_list *ifl;
135 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
136 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
137 return &(ifl->iface);
140 return NULL;
144 find a call that is pending in our call list
146 static struct dcesrv_call_state *dcesrv_find_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
148 struct dcesrv_call_state *c;
149 for (c=dce_conn->call_list;c;c=c->next) {
150 if (c->pkt.call_id == call_id) {
151 return c;
154 return NULL;
158 register an interface on an endpoint
160 NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
161 const char *ep_name,
162 const struct dcesrv_interface *iface,
163 const struct security_descriptor *sd)
165 struct dcesrv_endpoint *ep;
166 struct dcesrv_if_list *ifl;
167 struct dcerpc_binding binding;
168 BOOL add_ep = False;
169 NTSTATUS status;
171 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
173 if (NT_STATUS_IS_ERR(status)) {
174 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
175 return status;
178 /* check if this endpoint exists
180 if ((ep=find_endpoint(dce_ctx, &binding))==NULL) {
181 ep = talloc_p(dce_ctx, struct dcesrv_endpoint);
182 if (!ep) {
183 return NT_STATUS_NO_MEMORY;
185 ZERO_STRUCTP(ep);
186 ep->ep_description = binding;
187 add_ep = True;
190 /* see if the interface is already registered on te endpoint */
191 if (find_interface(ep, iface)!=NULL) {
192 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
193 iface->name, ep_name));
194 return NT_STATUS_OBJECT_NAME_COLLISION;
197 /* talloc a new interface list element */
198 ifl = talloc_p(dce_ctx, struct dcesrv_if_list);
199 if (!ifl) {
200 return NT_STATUS_NO_MEMORY;
203 /* copy the given interface struct to the one on the endpoints interface list */
204 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
206 /* if we have a security descriptor given,
207 * we should see if we can set it up on the endpoint
209 if (sd != NULL) {
210 /* if there's currently no security descriptor given on the endpoint
211 * we try to set it
213 if (ep->sd == NULL) {
214 ep->sd = security_descriptor_copy(dce_ctx, sd);
217 /* if now there's no security descriptor given on the endpoint
218 * something goes wrong, either we failed to copy the security descriptor
219 * or there was already one on the endpoint
221 if (ep->sd != NULL) {
222 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
223 " on endpoint '%s'\n",
224 iface->name, ep_name));
225 if (add_ep) free(ep);
226 free(ifl);
227 return NT_STATUS_OBJECT_NAME_COLLISION;
231 /* finally add the interface on the endpoint */
232 DLIST_ADD(ep->interface_list, ifl);
234 /* if it's a new endpoint add it to the dcesrv_context */
235 if (add_ep) {
236 DLIST_ADD(dce_ctx->endpoint_list, ep);
239 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
240 iface->name, ep_name));
242 return NT_STATUS_OK;
245 static NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
246 DATA_BLOB *session_key)
248 if (p->auth_state.session_info->session_key.length) {
249 *session_key = p->auth_state.session_info->session_key;
250 return NT_STATUS_OK;
252 return NT_STATUS_NO_USER_SESSION_KEY;
255 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
256 DATA_BLOB *session_key)
258 /* this took quite a few CPU cycles to find ... */
259 session_key->data = discard_const_p(uint8_t, "SystemLibraryDTC");
260 session_key->length = 16;
261 return NT_STATUS_OK;
265 fetch the user session key - may be default (above) or the SMB session key
267 NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
268 DATA_BLOB *session_key)
270 return p->auth_state.session_key(p, session_key);
275 destroy a link to an endpoint
277 static int dcesrv_endpoint_destructor(void *ptr)
279 struct dcesrv_connection *p = ptr;
281 while (p->contexts) {
282 struct dcesrv_connection_context *c = p->contexts;
284 DLIST_REMOVE(p->contexts, c);
286 if (c->iface) {
287 c->iface->unbind(c, c->iface);
289 talloc_free(c);
293 return 0;
298 connect to a dcerpc endpoint
300 NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
301 const struct dcesrv_endpoint *ep,
302 struct dcesrv_connection **p)
304 *p = talloc_p(dce_ctx, struct dcesrv_connection);
305 if (! *p) {
306 return NT_STATUS_NO_MEMORY;
309 (*p)->dce_ctx = dce_ctx;
310 (*p)->endpoint = ep;
311 (*p)->contexts = NULL;
312 (*p)->call_list = NULL;
313 (*p)->cli_max_recv_frag = 0;
314 (*p)->partial_input = data_blob(NULL, 0);
315 (*p)->auth_state.auth_info = NULL;
316 (*p)->auth_state.gensec_security = NULL;
317 (*p)->auth_state.session_info = NULL;
318 (*p)->auth_state.session_key = dcesrv_generic_session_key;
319 (*p)->srv_conn = NULL;
321 talloc_set_destructor(*p, dcesrv_endpoint_destructor);
323 return NT_STATUS_OK;
327 search and connect to a dcerpc endpoint
329 NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
330 const struct dcerpc_binding *ep_description,
331 struct auth_session_info *session_info,
332 struct dcesrv_connection **dce_conn_p)
334 NTSTATUS status;
335 const struct dcesrv_endpoint *ep;
337 /* make sure this endpoint exists */
338 ep = find_endpoint(dce_ctx, ep_description);
339 if (!ep) {
340 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
343 status = dcesrv_endpoint_connect(dce_ctx, ep, dce_conn_p);
344 if (!NT_STATUS_IS_OK(status)) {
345 return status;
348 (*dce_conn_p)->auth_state.session_info = talloc_reference((*dce_conn_p), session_info);
349 (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
351 /* TODO: check security descriptor of the endpoint here
352 * if it's a smb named pipe
353 * if it's failed free dce_conn_p
356 return NT_STATUS_OK;
360 static void dcesrv_init_hdr(struct dcerpc_packet *pkt)
362 pkt->rpc_vers = 5;
363 pkt->rpc_vers_minor = 0;
364 if (lp_rpc_big_endian()) {
365 pkt->drep[0] = 0;
366 } else {
367 pkt->drep[0] = DCERPC_DREP_LE;
369 pkt->drep[1] = 0;
370 pkt->drep[2] = 0;
371 pkt->drep[3] = 0;
375 return a dcerpc fault
377 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
379 struct dcerpc_packet pkt;
380 struct dcesrv_call_reply *rep;
381 NTSTATUS status;
383 /* setup a bind_ack */
384 dcesrv_init_hdr(&pkt);
385 pkt.auth_length = 0;
386 pkt.call_id = call->pkt.call_id;
387 pkt.ptype = DCERPC_PKT_FAULT;
388 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
389 pkt.u.fault.alloc_hint = 0;
390 pkt.u.fault.context_id = 0;
391 pkt.u.fault.cancel_count = 0;
392 pkt.u.fault.status = fault_code;
394 rep = talloc_p(call, struct dcesrv_call_reply);
395 if (!rep) {
396 return NT_STATUS_NO_MEMORY;
399 status = dcerpc_push_auth(&rep->data, call, &pkt, NULL);
400 if (!NT_STATUS_IS_OK(status)) {
401 return status;
404 dcerpc_set_frag_length(&rep->data, rep->data.length);
406 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
407 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
409 return NT_STATUS_OK;
414 return a dcerpc bind_nak
416 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
418 struct dcerpc_packet pkt;
419 struct dcesrv_call_reply *rep;
420 NTSTATUS status;
422 /* setup a bind_nak */
423 dcesrv_init_hdr(&pkt);
424 pkt.auth_length = 0;
425 pkt.call_id = call->pkt.call_id;
426 pkt.ptype = DCERPC_PKT_BIND_NAK;
427 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
428 pkt.u.bind_nak.reject_reason = reason;
429 pkt.u.bind_nak.num_versions = 0;
431 rep = talloc_p(call, struct dcesrv_call_reply);
432 if (!rep) {
433 return NT_STATUS_NO_MEMORY;
436 status = dcerpc_push_auth(&rep->data, call, &pkt, NULL);
437 if (!NT_STATUS_IS_OK(status)) {
438 return status;
441 dcerpc_set_frag_length(&rep->data, rep->data.length);
443 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
444 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
446 return NT_STATUS_OK;
451 handle a bind request
453 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
455 const char *uuid, *transfer_syntax;
456 uint32_t if_version, transfer_syntax_version;
457 struct dcerpc_packet pkt;
458 struct dcesrv_call_reply *rep;
459 NTSTATUS status;
460 uint32_t result=0, reason=0;
461 uint32_t context_id;
462 const struct dcesrv_interface *iface;
464 if (call->pkt.u.bind.num_contexts != 1 ||
465 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
466 return dcesrv_bind_nak(call, 0);
469 context_id = call->pkt.u.bind.ctx_list[0].context_id;
471 /* you can't bind twice on one context */
472 if (dcesrv_find_context(call->conn, context_id) != NULL) {
473 return dcesrv_bind_nak(call, 0);
476 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
477 uuid = GUID_string(call, &call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid);
478 if (!uuid) {
479 return dcesrv_bind_nak(call, 0);
482 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
483 transfer_syntax = GUID_string(call,
484 &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid);
485 if (!transfer_syntax ||
486 strcasecmp(NDR_GUID, transfer_syntax) != 0 ||
487 NDR_GUID_VERSION != transfer_syntax_version) {
488 /* we only do NDR encoded dcerpc */
489 return dcesrv_bind_nak(call, 0);
492 iface = find_interface_by_uuid(call->conn->endpoint, uuid, if_version);
493 if (iface == NULL) {
494 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
495 /* we don't know about that interface */
496 result = DCERPC_BIND_PROVIDER_REJECT;
497 reason = DCERPC_BIND_REASON_ASYNTAX;
500 if (iface) {
501 /* add this context to the list of available context_ids */
502 struct dcesrv_connection_context *context = talloc(call->conn,
503 struct dcesrv_connection_context);
504 if (context == NULL) {
505 return dcesrv_bind_nak(call, 0);
507 context->conn = call->conn;
508 context->iface = iface;
509 context->context_id = context_id;
510 context->private = NULL;
511 context->handles = NULL;
512 DLIST_ADD(call->conn->contexts, context);
513 call->context = context;
516 if (call->conn->cli_max_recv_frag == 0) {
517 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
520 /* handle any authentication that is being requested */
521 if (!dcesrv_auth_bind(call)) {
522 /* TODO: work out the right reject code */
523 return dcesrv_bind_nak(call, 0);
526 /* setup a bind_ack */
527 dcesrv_init_hdr(&pkt);
528 pkt.auth_length = 0;
529 pkt.call_id = call->pkt.call_id;
530 pkt.ptype = DCERPC_PKT_BIND_ACK;
531 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
532 pkt.u.bind_ack.max_xmit_frag = 0x2000;
533 pkt.u.bind_ack.max_recv_frag = 0x2000;
534 pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
535 if (iface) {
536 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
537 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
538 } else {
539 pkt.u.bind_ack.secondary_address = "";
541 pkt.u.bind_ack.num_results = 1;
542 pkt.u.bind_ack.ctx_list = talloc_p(call, struct dcerpc_ack_ctx);
543 if (!pkt.u.bind_ack.ctx_list) {
544 return NT_STATUS_NO_MEMORY;
546 pkt.u.bind_ack.ctx_list[0].result = result;
547 pkt.u.bind_ack.ctx_list[0].reason = reason;
548 GUID_from_string(NDR_GUID, &pkt.u.bind_ack.ctx_list[0].syntax.uuid);
549 pkt.u.bind_ack.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
550 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
552 if (!dcesrv_auth_bind_ack(call, &pkt)) {
553 return dcesrv_bind_nak(call, 0);
556 if (iface) {
557 status = iface->bind(call, iface);
558 if (!NT_STATUS_IS_OK(status)) {
559 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
560 uuid, if_version, nt_errstr(status)));
561 return dcesrv_bind_nak(call, 0);
565 rep = talloc(call, struct dcesrv_call_reply);
566 if (!rep) {
567 return NT_STATUS_NO_MEMORY;
570 status = dcerpc_push_auth(&rep->data, call, &pkt,
571 call->conn->auth_state.auth_info);
572 if (!NT_STATUS_IS_OK(status)) {
573 return status;
576 dcerpc_set_frag_length(&rep->data, rep->data.length);
578 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
579 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
581 return NT_STATUS_OK;
586 handle a auth3 request
588 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
590 /* handle the auth3 in the auth code */
591 if (!dcesrv_auth_auth3(call)) {
592 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
595 talloc_free(call);
597 /* we don't send a reply to a auth3 request, except by a
598 fault */
599 return NT_STATUS_OK;
603 handle a bind request
605 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
607 struct dcerpc_packet pkt;
608 struct dcesrv_call_reply *rep;
609 NTSTATUS status;
610 uint32_t result=0, reason=0;
612 /* handle any authentication that is being requested */
613 if (!dcesrv_auth_alter(call)) {
614 /* TODO: work out the right reject code */
615 return dcesrv_bind_nak(call, 0);
618 /* setup a alter_ack */
619 dcesrv_init_hdr(&pkt);
620 pkt.auth_length = 0;
621 pkt.call_id = call->pkt.call_id;
622 pkt.ptype = DCERPC_PKT_ALTER_RESP;
623 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
624 pkt.u.alter_resp.max_xmit_frag = 0x2000;
625 pkt.u.alter_resp.max_recv_frag = 0x2000;
626 pkt.u.alter_resp.assoc_group_id = call->pkt.u.bind.assoc_group_id;
627 pkt.u.alter_resp.secondary_address = NULL;
628 pkt.u.alter_resp.num_results = 1;
629 pkt.u.alter_resp.ctx_list = talloc_p(call, struct dcerpc_ack_ctx);
630 if (!pkt.u.alter_resp.ctx_list) {
631 return NT_STATUS_NO_MEMORY;
633 pkt.u.alter_resp.ctx_list[0].result = result;
634 pkt.u.alter_resp.ctx_list[0].reason = reason;
635 GUID_from_string(NDR_GUID, &pkt.u.alter_resp.ctx_list[0].syntax.uuid);
636 pkt.u.alter_resp.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
637 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
639 if (!dcesrv_auth_alter_ack(call, &pkt)) {
640 return dcesrv_bind_nak(call, 0);
643 rep = talloc_p(call, struct dcesrv_call_reply);
644 if (!rep) {
645 return NT_STATUS_NO_MEMORY;
648 status = dcerpc_push_auth(&rep->data, call, &pkt,
649 call->conn->auth_state.auth_info);
650 if (!NT_STATUS_IS_OK(status)) {
651 return status;
654 dcerpc_set_frag_length(&rep->data, rep->data.length);
656 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
657 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
659 return NT_STATUS_OK;
663 handle a dcerpc request packet
665 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
667 struct ndr_pull *pull;
668 struct ndr_push *push;
669 void *r;
670 NTSTATUS status;
671 DATA_BLOB stub;
672 uint32_t total_length;
673 struct dcesrv_connection_context *context;
675 call->fault_code = 0;
677 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
678 if (context == NULL) {
679 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
682 call->context = context;
684 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
685 if (!pull) {
686 return NT_STATUS_NO_MEMORY;
689 if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_ORPC) {
690 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
693 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
694 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
697 /* unravel the NDR for the packet */
698 status = context->iface->ndr_pull(call, call, pull, &r);
699 if (!NT_STATUS_IS_OK(status)) {
700 return dcesrv_fault(call, call->fault_code);
703 if (pull->offset != pull->data_size) {
704 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
705 pull->data_size - pull->offset));
706 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
709 /* call the dispatch function */
710 status = context->iface->dispatch(call, call, r);
711 if (!NT_STATUS_IS_OK(status)) {
712 return dcesrv_fault(call, call->fault_code);
715 /* form the reply NDR */
716 push = ndr_push_init_ctx(call);
717 if (!push) {
718 return NT_STATUS_NO_MEMORY;
721 /* carry over the pointer count to the reply in case we are
722 using full pointer. See NDR specification for full
723 pointers */
724 push->ptr_count = pull->ptr_count;
726 if (lp_rpc_big_endian()) {
727 push->flags |= LIBNDR_FLAG_BIGENDIAN;
730 status = context->iface->ndr_push(call, call, push, r);
731 if (!NT_STATUS_IS_OK(status)) {
732 return dcesrv_fault(call, call->fault_code);
735 stub = ndr_push_blob(push);
737 total_length = stub.length;
739 do {
740 uint32_t length;
741 struct dcesrv_call_reply *rep;
742 struct dcerpc_packet pkt;
744 rep = talloc(call, struct dcesrv_call_reply);
745 if (!rep) {
746 return NT_STATUS_NO_MEMORY;
749 length = stub.length;
750 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
751 /* the 32 is to cope with signing data */
752 length = call->conn->cli_max_recv_frag -
753 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
756 /* form the dcerpc response packet */
757 dcesrv_init_hdr(&pkt);
758 pkt.auth_length = 0;
759 pkt.call_id = call->pkt.call_id;
760 pkt.ptype = DCERPC_PKT_RESPONSE;
761 pkt.pfc_flags = 0;
762 if (stub.length == total_length) {
763 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
765 if (length == stub.length) {
766 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
768 pkt.u.response.alloc_hint = stub.length;
769 pkt.u.response.context_id = call->pkt.u.request.context_id;
770 pkt.u.response.cancel_count = 0;
771 pkt.u.response.stub_and_verifier.data = stub.data;
772 pkt.u.response.stub_and_verifier.length = length;
774 if (!dcesrv_auth_response(call, &rep->data, &pkt)) {
775 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
778 dcerpc_set_frag_length(&rep->data, rep->data.length);
780 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
782 stub.data += length;
783 stub.length -= length;
784 } while (stub.length != 0);
786 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
788 return NT_STATUS_OK;
793 work out if we have a full packet yet
795 static BOOL dce_full_packet(const DATA_BLOB *data)
797 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
798 return False;
800 if (dcerpc_get_frag_length(data) > data->length) {
801 return False;
803 return True;
807 we might have consumed only part of our input - advance past that part
809 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
811 DATA_BLOB blob;
813 if (dce_conn->partial_input.length == offset) {
814 data_blob_free(&dce_conn->partial_input);
815 return;
818 blob = dce_conn->partial_input;
819 dce_conn->partial_input = data_blob(blob.data + offset,
820 blob.length - offset);
821 data_blob_free(&blob);
825 process some input to a dcerpc endpoint server.
827 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
829 struct ndr_pull *ndr;
830 NTSTATUS status;
831 struct dcesrv_call_state *call;
832 DATA_BLOB blob;
834 call = talloc(dce_conn, struct dcesrv_call_state);
835 if (!call) {
836 talloc_free(dce_conn->partial_input.data);
837 return NT_STATUS_NO_MEMORY;
839 call->conn = dce_conn;
840 call->replies = NULL;
841 call->context = NULL;
843 blob = dce_conn->partial_input;
844 blob.length = dcerpc_get_frag_length(&blob);
846 ndr = ndr_pull_init_blob(&blob, call);
847 if (!ndr) {
848 talloc_free(dce_conn->partial_input.data);
849 talloc_free(call);
850 return NT_STATUS_NO_MEMORY;
853 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
854 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
857 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
858 if (!NT_STATUS_IS_OK(status)) {
859 talloc_free(dce_conn->partial_input.data);
860 talloc_free(call);
861 return status;
864 /* we have to check the signing here, before combining the
865 pdus */
866 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
867 !dcesrv_auth_request(call, &blob)) {
868 dce_partial_advance(dce_conn, blob.length);
869 return dcesrv_fault(call, DCERPC_FAULT_LOGON_FAILURE);
872 dce_partial_advance(dce_conn, blob.length);
874 /* see if this is a continued packet */
875 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
876 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
877 struct dcesrv_call_state *call2 = call;
878 uint32_t alloc_size;
880 /* we only allow fragmented requests, no other packet types */
881 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
882 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
885 /* this is a continuation of an existing call - find the call then
886 tack it on the end */
887 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
888 if (!call) {
889 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
892 if (call->pkt.ptype != call2->pkt.ptype) {
893 /* trying to play silly buggers are we? */
894 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
897 alloc_size = call->pkt.u.request.stub_and_verifier.length +
898 call2->pkt.u.request.stub_and_verifier.length;
899 if (call->pkt.u.request.alloc_hint > alloc_size) {
900 alloc_size = call->pkt.u.request.alloc_hint;
903 call->pkt.u.request.stub_and_verifier.data =
904 talloc_realloc(call,
905 call->pkt.u.request.stub_and_verifier.data,
906 uint8_t, alloc_size);
907 if (!call->pkt.u.request.stub_and_verifier.data) {
908 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
910 memcpy(call->pkt.u.request.stub_and_verifier.data +
911 call->pkt.u.request.stub_and_verifier.length,
912 call2->pkt.u.request.stub_and_verifier.data,
913 call2->pkt.u.request.stub_and_verifier.length);
914 call->pkt.u.request.stub_and_verifier.length +=
915 call2->pkt.u.request.stub_and_verifier.length;
917 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
919 talloc_free(call2);
922 /* this may not be the last pdu in the chain - if its isn't then
923 just put it on the call_list and wait for the rest */
924 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
925 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
926 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
927 return NT_STATUS_OK;
930 switch (call->pkt.ptype) {
931 case DCERPC_PKT_BIND:
932 status = dcesrv_bind(call);
933 break;
934 case DCERPC_PKT_AUTH3:
935 status = dcesrv_auth3(call);
936 break;
937 case DCERPC_PKT_ALTER:
938 status = dcesrv_alter(call);
939 break;
940 case DCERPC_PKT_REQUEST:
941 status = dcesrv_request(call);
942 break;
943 default:
944 status = NT_STATUS_INVALID_PARAMETER;
945 break;
948 /* if we are going to be sending a reply then add
949 it to the list of pending calls. We add it to the end to keep the call
950 list in the order we will answer */
951 if (!NT_STATUS_IS_OK(status)) {
952 talloc_free(call);
955 return status;
960 provide some input to a dcerpc endpoint server. This passes data
961 from a dcerpc client into the server
963 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
965 NTSTATUS status;
967 dce_conn->partial_input.data = talloc_realloc(dce_conn,
968 dce_conn->partial_input.data,
969 uint8_t,
970 dce_conn->partial_input.length + data->length);
971 if (!dce_conn->partial_input.data) {
972 return NT_STATUS_NO_MEMORY;
974 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
975 data->data, data->length);
976 dce_conn->partial_input.length += data->length;
978 while (dce_full_packet(&dce_conn->partial_input)) {
979 status = dcesrv_input_process(dce_conn);
980 if (!NT_STATUS_IS_OK(status)) {
981 return status;
985 return NT_STATUS_OK;
989 retrieve some output from a dcerpc server
990 The caller supplies a function that will be called to do the
991 actual output.
993 The first argument to write_fn() will be 'private', the second will
994 be a pointer to a buffer containing the data to be sent and the 3rd
995 will be the number of bytes to be sent.
997 write_fn() should return the number of bytes successfully written.
999 this will return STATUS_BUFFER_OVERFLOW if there is more to be read
1000 from the current fragment
1002 NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
1003 void *private,
1004 ssize_t (*write_fn)(void *, DATA_BLOB *))
1006 struct dcesrv_call_state *call;
1007 struct dcesrv_call_reply *rep;
1008 ssize_t nwritten;
1010 call = dce_conn->call_list;
1011 if (!call || !call->replies) {
1012 return NT_STATUS_FOOBAR;
1014 rep = call->replies;
1016 nwritten = write_fn(private, &rep->data);
1017 if (nwritten == -1) {
1018 /* TODO: hmm, how do we cope with this? destroy the
1019 connection perhaps? */
1020 return NT_STATUS_UNSUCCESSFUL;
1023 rep->data.length -= nwritten;
1024 rep->data.data += nwritten;
1026 if (rep->data.length == 0) {
1027 /* we're done with this section of the call */
1028 DLIST_REMOVE(call->replies, rep);
1029 } else {
1030 return STATUS_BUFFER_OVERFLOW;
1033 if (call->replies == NULL) {
1034 /* we're done with the whole call */
1035 DLIST_REMOVE(dce_conn->call_list, call);
1036 talloc_free(call);
1039 return NT_STATUS_OK;
1044 write_fn() for dcesrv_output_blob()
1046 static ssize_t dcesrv_output_blob_write_fn(void *private, DATA_BLOB *out)
1048 DATA_BLOB *blob = private;
1049 if (out->length < blob->length) {
1050 blob->length = out->length;
1052 memcpy(blob->data, out->data, blob->length);
1053 return blob->length;
1057 a simple wrapper for dcesrv_output() for when we want to output
1058 into a data blob
1060 NTSTATUS dcesrv_output_blob(struct dcesrv_connection *dce_conn,
1061 DATA_BLOB *blob)
1063 return dcesrv_output(dce_conn, blob, dcesrv_output_blob_write_fn);
1067 initialise the dcerpc server context
1069 NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **dce_ctx)
1071 int i;
1072 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
1074 (*dce_ctx) = talloc_p(mem_ctx, struct dcesrv_context);
1075 if (! *dce_ctx) {
1076 return NT_STATUS_NO_MEMORY;
1079 (*dce_ctx)->endpoint_list = NULL;
1081 if (!endpoint_servers) {
1082 DEBUG(3,("dcesrv_init_context: no endpoint servers configured\n"));
1083 return NT_STATUS_OK;
1086 for (i=0;endpoint_servers[i];i++) {
1087 NTSTATUS ret;
1088 const struct dcesrv_endpoint_server *ep_server;
1090 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1091 if (!ep_server) {
1092 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1093 return NT_STATUS_UNSUCCESSFUL;
1096 ret = ep_server->init_server(*dce_ctx, ep_server);
1097 if (!NT_STATUS_IS_OK(ret)) {
1098 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1099 return ret;
1103 return NT_STATUS_OK;
1106 static void dcesrv_init(struct server_service *service, const struct model_ops *model_ops)
1108 struct dcesrv_context *dce_ctx;
1109 int i;
1110 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
1112 DEBUG(1,("dcesrv_init\n"));
1114 if (!endpoint_servers) {
1115 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1116 return;
1119 dce_ctx = talloc_p(service, struct dcesrv_context);
1120 if (!dce_ctx) {
1121 DEBUG(0,("talloc_p(mem_ctx, struct dcesrv_context) failed\n"));
1122 return;
1125 ZERO_STRUCTP(dce_ctx);
1126 dce_ctx->endpoint_list = NULL;
1128 for (i=0;endpoint_servers[i];i++) {
1129 NTSTATUS ret;
1130 const struct dcesrv_endpoint_server *ep_server;
1132 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1133 if (!ep_server) {
1134 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1135 return;
1138 ret = ep_server->init_server(dce_ctx, ep_server);
1139 if (!NT_STATUS_IS_OK(ret)) {
1140 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1141 return;
1145 dcesrv_sock_init(service, model_ops, dce_ctx);
1147 return;
1150 static void dcesrv_accept(struct server_connection *srv_conn)
1152 dcesrv_sock_accept(srv_conn);
1155 static void dcesrv_recv(struct server_connection *srv_conn,
1156 struct timeval t, uint16_t flags)
1158 dcesrv_sock_recv(srv_conn, t, flags);
1161 static void dcesrv_send(struct server_connection *srv_conn,
1162 struct timeval t, uint16_t flags)
1164 dcesrv_sock_send(srv_conn, t, flags);
1167 static void dcesrv_close(struct server_connection *srv_conn, const char *reason)
1169 dcesrv_sock_close(srv_conn, reason);
1170 return;
1173 static void dcesrv_exit(struct server_service *service, const char *reason)
1175 dcesrv_sock_exit(service, reason);
1176 return;
1179 /* the list of currently registered DCERPC endpoint servers.
1181 static struct ep_server {
1182 struct dcesrv_endpoint_server *ep_server;
1183 } *ep_servers = NULL;
1184 static int num_ep_servers;
1187 register a DCERPC endpoint server.
1189 The 'name' can be later used by other backends to find the operations
1190 structure for this backend.
1192 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1194 NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1196 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1198 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1199 /* its already registered! */
1200 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1201 ep_server->name));
1202 return NT_STATUS_OBJECT_NAME_COLLISION;
1205 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1206 if (!ep_servers) {
1207 smb_panic("out of memory in dcerpc_register");
1210 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1211 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1213 num_ep_servers++;
1215 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1216 ep_server->name));
1218 return NT_STATUS_OK;
1222 return the operations structure for a named backend of the specified type
1224 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1226 int i;
1228 for (i=0;i<num_ep_servers;i++) {
1229 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1230 return ep_servers[i].ep_server;
1234 return NULL;
1238 return the DCERPC module version, and the size of some critical types
1239 This can be used by endpoint server modules to either detect compilation errors, or provide
1240 multiple implementations for different smbd compilation options in one module
1242 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1244 static const struct dcesrv_critical_sizes critical_sizes = {
1245 DCERPC_MODULE_VERSION,
1246 sizeof(struct dcesrv_context),
1247 sizeof(struct dcesrv_endpoint),
1248 sizeof(struct dcesrv_endpoint_server),
1249 sizeof(struct dcesrv_interface),
1250 sizeof(struct dcesrv_if_list),
1251 sizeof(struct dcesrv_connection),
1252 sizeof(struct dcesrv_call_state),
1253 sizeof(struct dcesrv_auth),
1254 sizeof(struct dcesrv_handle)
1257 return &critical_sizes;
1260 static const struct server_service_ops dcesrv_ops = {
1261 .name = "rpc",
1262 .service_init = dcesrv_init,
1263 .accept_connection = dcesrv_accept,
1264 .recv_handler = dcesrv_recv,
1265 .send_handler = dcesrv_send,
1266 .idle_handler = NULL,
1267 .close_connection = dcesrv_close,
1268 .service_exit = dcesrv_exit,
1271 const struct server_service_ops *dcesrv_get_ops(void)
1273 return &dcesrv_ops;
1276 NTSTATUS server_service_rpc_init(void)
1278 return NT_STATUS_OK;