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.
25 #include "librpc/gen_ndr/ndr_epmapper.h"
26 #include "librpc/gen_ndr/ndr_oxidresolver.h"
27 #include "librpc/gen_ndr/tables.h"
28 #include "auth/auth.h"
29 #include "dlinklist.h"
30 #include "rpc_server/dcerpc_server.h"
33 see if two endpoints match
35 static BOOL endpoints_match(const struct dcerpc_binding *ep1,
36 const struct dcerpc_binding *ep2)
38 if (ep1->transport != ep2->transport) {
42 if (!ep1->endpoint || !ep2->endpoint) {
43 return ep1->endpoint == ep2->endpoint;
46 if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
53 find an endpoint in the dcesrv_context
55 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
56 const struct dcerpc_binding *ep_description)
58 struct dcesrv_endpoint *ep;
59 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
60 if (endpoints_match(&ep->ep_description, ep_description)) {
68 see if a uuid and if_version match to an interface
70 static BOOL interface_match(const struct dcesrv_interface *if1,
71 const struct dcesrv_interface *if2)
73 if (if1->ndr->if_version != if2->ndr->if_version) {
77 if (strcmp(if1->ndr->uuid, if2->ndr->uuid)==0) {
85 find the interface operations on an endpoint
87 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
88 const struct dcesrv_interface *iface)
90 struct dcesrv_if_list *ifl;
91 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
92 if (interface_match(&(ifl->iface), iface)) {
100 see if a uuid and if_version match to an interface
102 static BOOL interface_match_by_uuid(const struct dcesrv_interface *iface,
103 const char *uuid, uint32_t if_version)
105 if (iface->ndr->if_version != if_version) {
109 if (strcmp(iface->ndr->uuid, uuid)==0) {
117 find the interface operations on an endpoint by uuid
119 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
120 const char *uuid, uint32_t if_version)
122 struct dcesrv_if_list *ifl;
123 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
124 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
125 return &(ifl->iface);
132 find a call that is pending in our call list
134 static struct dcesrv_call_state *dcesrv_find_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
136 struct dcesrv_call_state *c;
137 for (c=dce_conn->call_list;c;c=c->next) {
138 if (c->pkt.call_id == call_id) {
146 register an interface on an endpoint
148 NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
150 const struct dcesrv_interface *iface,
151 const struct security_descriptor *sd)
153 struct dcesrv_endpoint *ep;
154 struct dcesrv_if_list *ifl;
155 struct dcerpc_binding binding;
159 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
161 if (NT_STATUS_IS_ERR(status)) {
162 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
166 /* check if this endpoint exists
168 if ((ep=find_endpoint(dce_ctx, &binding))==NULL) {
169 ep = talloc_p(dce_ctx, struct dcesrv_endpoint);
171 return NT_STATUS_NO_MEMORY;
174 ep->ep_description = binding;
178 /* see if the interface is already registered on te endpoint */
179 if (find_interface(ep, iface)!=NULL) {
180 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
181 iface->ndr->name, ep_name));
182 return NT_STATUS_OBJECT_NAME_COLLISION;
185 /* talloc a new interface list element */
186 ifl = talloc_p(dce_ctx, struct dcesrv_if_list);
188 return NT_STATUS_NO_MEMORY;
191 /* copy the given interface struct to the one on the endpoints interface list */
192 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
194 /* if we have a security descriptor given,
195 * we should see if we can set it up on the endpoint
198 /* if there's currently no security descriptor given on the endpoint
201 if (ep->sd == NULL) {
202 ep->sd = copy_security_descriptor(dce_ctx, sd);
205 /* if now there's no security descriptor given on the endpoint
206 * something goes wrong, either we failed to copy the security descriptor
207 * or there was already one on the endpoint
209 if (ep->sd != NULL) {
210 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
211 " on endpoint '%s'\n",
212 iface->ndr->name, ep_name));
213 if (add_ep) free(ep);
215 return NT_STATUS_OBJECT_NAME_COLLISION;
219 /* finally add the interface on the endpoint */
220 DLIST_ADD(ep->interface_list, ifl);
222 /* if it's a new endpoint add it to the dcesrv_context */
224 DLIST_ADD(dce_ctx->endpoint_list, ep);
227 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
228 iface->ndr->name, ep_name));
233 static NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
234 DATA_BLOB *session_key)
236 if (p->auth_state.session_info->session_key.length) {
237 *session_key = p->auth_state.session_info->session_key;
240 return NT_STATUS_NO_USER_SESSION_KEY;
243 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
244 DATA_BLOB *session_key)
246 /* this took quite a few CPU cycles to find ... */
247 session_key->data = discard_const_p(char, "SystemLibraryDTC");
248 session_key->length = 16;
253 fetch the user session key - may be default (above) or the SMB session key
255 NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
256 DATA_BLOB *session_key)
258 return p->auth_state.session_key(p, session_key);
263 destroy a link to an endpoint
265 static int dcesrv_endpoint_destructor(void *ptr)
267 struct dcesrv_connection *p = ptr;
269 p->iface->unbind(p, p->iface);
272 /* destroy any handles */
274 dcesrv_handle_destroy(p, p->handles);
277 if (p->auth_state.gensec_security) {
278 gensec_end(&p->auth_state.gensec_security);
286 connect to a dcerpc endpoint
288 NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
289 const struct dcesrv_endpoint *ep,
290 struct dcesrv_connection **p)
292 *p = talloc_p(dce_ctx, struct dcesrv_connection);
294 return NT_STATUS_NO_MEMORY;
297 (*p)->dce_ctx = dce_ctx;
300 (*p)->private = NULL;
301 (*p)->call_list = NULL;
302 (*p)->cli_max_recv_frag = 0;
303 (*p)->handles = NULL;
304 (*p)->partial_input = data_blob(NULL, 0);
305 (*p)->auth_state.auth_info = NULL;
306 (*p)->auth_state.gensec_security = NULL;
307 (*p)->auth_state.session_info = NULL;
308 (*p)->auth_state.session_key = dcesrv_generic_session_key;
309 (*p)->srv_conn = NULL;
311 talloc_set_destructor(*p, dcesrv_endpoint_destructor);
317 search and connect to a dcerpc endpoint
319 NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
320 const struct dcerpc_binding *ep_description,
321 struct auth_session_info *session_info,
322 struct dcesrv_connection **dce_conn_p)
325 const struct dcesrv_endpoint *ep;
327 /* make sure this endpoint exists */
328 ep = find_endpoint(dce_ctx, ep_description);
330 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
333 status = dcesrv_endpoint_connect(dce_ctx, ep, dce_conn_p);
334 if (!NT_STATUS_IS_OK(status)) {
338 session_info->refcount++;
339 (*dce_conn_p)->auth_state.session_info = session_info;
340 (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
342 /* TODO: check security descriptor of the endpoint here
343 * if it's a smb named pipe
344 * if it's failed free dce_conn_p
351 static void dcesrv_init_hdr(struct dcerpc_packet *pkt)
354 pkt->rpc_vers_minor = 0;
355 if (lp_rpc_big_endian()) {
358 pkt->drep[0] = DCERPC_DREP_LE;
366 return a dcerpc fault
368 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
370 struct dcerpc_packet pkt;
371 struct dcesrv_call_reply *rep;
374 /* setup a bind_ack */
375 dcesrv_init_hdr(&pkt);
377 pkt.call_id = call->pkt.call_id;
378 pkt.ptype = DCERPC_PKT_FAULT;
379 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
380 pkt.u.fault.alloc_hint = 0;
381 pkt.u.fault.context_id = 0;
382 pkt.u.fault.cancel_count = 0;
383 pkt.u.fault.status = fault_code;
385 rep = talloc_p(call, struct dcesrv_call_reply);
387 return NT_STATUS_NO_MEMORY;
390 status = dcerpc_push_auth(&rep->data, call, &pkt, NULL);
391 if (!NT_STATUS_IS_OK(status)) {
395 dcerpc_set_frag_length(&rep->data, rep->data.length);
397 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
398 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
405 return a dcerpc bind_nak
407 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
409 struct dcerpc_packet pkt;
410 struct dcesrv_call_reply *rep;
413 /* setup a bind_nak */
414 dcesrv_init_hdr(&pkt);
416 pkt.call_id = call->pkt.call_id;
417 pkt.ptype = DCERPC_PKT_BIND_NAK;
418 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
419 pkt.u.bind_nak.reject_reason = reason;
420 pkt.u.bind_nak.num_versions = 0;
422 rep = talloc_p(call, struct dcesrv_call_reply);
424 return NT_STATUS_NO_MEMORY;
427 status = dcerpc_push_auth(&rep->data, call, &pkt, NULL);
428 if (!NT_STATUS_IS_OK(status)) {
432 dcerpc_set_frag_length(&rep->data, rep->data.length);
434 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
435 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
442 handle a bind request
444 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
446 const char *uuid, *transfer_syntax;
447 uint32_t if_version, transfer_syntax_version;
448 struct dcerpc_packet pkt;
449 struct dcesrv_call_reply *rep;
451 uint32_t result=0, reason=0;
453 if (call->pkt.u.bind.num_contexts != 1 ||
454 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
455 return dcesrv_bind_nak(call, 0);
458 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
459 uuid = GUID_string(call, &call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid);
461 return dcesrv_bind_nak(call, 0);
464 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
465 transfer_syntax = GUID_string(call,
466 &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid);
467 if (!transfer_syntax ||
468 strcasecmp(NDR_GUID, transfer_syntax) != 0 ||
469 NDR_GUID_VERSION != transfer_syntax_version) {
470 /* we only do NDR encoded dcerpc */
471 return dcesrv_bind_nak(call, 0);
474 call->conn->iface = find_interface_by_uuid(call->conn->endpoint, uuid, if_version);
475 if (!call->conn->iface) {
476 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
477 /* we don't know about that interface */
478 result = DCERPC_BIND_PROVIDER_REJECT;
479 reason = DCERPC_BIND_REASON_ASYNTAX;
482 if (call->conn->cli_max_recv_frag == 0) {
483 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
486 /* handle any authentication that is being requested */
487 if (!dcesrv_auth_bind(call)) {
488 /* TODO: work out the right reject code */
489 return dcesrv_bind_nak(call, 0);
492 /* setup a bind_ack */
493 dcesrv_init_hdr(&pkt);
495 pkt.call_id = call->pkt.call_id;
496 pkt.ptype = DCERPC_PKT_BIND_ACK;
497 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
498 pkt.u.bind_ack.max_xmit_frag = 0x2000;
499 pkt.u.bind_ack.max_recv_frag = 0x2000;
500 pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
501 if (call->conn->iface && call->conn->iface->ndr) {
502 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
503 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s",
504 call->conn->iface->ndr->name);
506 pkt.u.bind_ack.secondary_address = "";
508 pkt.u.bind_ack.num_results = 1;
509 pkt.u.bind_ack.ctx_list = talloc_p(call, struct dcerpc_ack_ctx);
510 if (!pkt.u.bind_ack.ctx_list) {
511 return NT_STATUS_NO_MEMORY;
513 pkt.u.bind_ack.ctx_list[0].result = result;
514 pkt.u.bind_ack.ctx_list[0].reason = reason;
515 GUID_from_string(NDR_GUID, &pkt.u.bind_ack.ctx_list[0].syntax.uuid);
516 pkt.u.bind_ack.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
517 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
519 if (!dcesrv_auth_bind_ack(call, &pkt)) {
520 return dcesrv_bind_nak(call, 0);
523 if (call->conn->iface) {
524 status = call->conn->iface->bind(call, call->conn->iface);
525 if (!NT_STATUS_IS_OK(status)) {
526 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n", uuid, if_version, nt_errstr(status)));
527 return dcesrv_bind_nak(call, 0);
531 rep = talloc_p(call, struct dcesrv_call_reply);
533 return NT_STATUS_NO_MEMORY;
536 status = dcerpc_push_auth(&rep->data, call, &pkt,
537 call->conn->auth_state.auth_info);
538 if (!NT_STATUS_IS_OK(status)) {
542 dcerpc_set_frag_length(&rep->data, rep->data.length);
544 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
545 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
552 handle a auth3 request
554 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
556 /* handle the auth3 in the auth code */
557 if (!dcesrv_auth_auth3(call)) {
558 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
563 /* we don't send a reply to a auth3 request, except by a
570 handle a dcerpc request packet
572 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
574 struct ndr_pull *pull;
575 struct ndr_push *push;
580 uint32_t total_length;
583 if (!call->conn->iface) {
584 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
587 opnum = call->pkt.u.request.opnum;
589 if (opnum >= call->conn->iface->ndr->num_calls) {
590 return dcesrv_fault(call, DCERPC_FAULT_OP_RNG_ERROR);
593 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
595 return NT_STATUS_NO_MEMORY;
598 r = talloc(call, call->conn->iface->ndr->calls[opnum].struct_size);
600 return NT_STATUS_NO_MEMORY;
603 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
604 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
607 /* unravel the NDR for the packet */
608 status = call->conn->iface->ndr->calls[opnum].ndr_pull(pull, NDR_IN, r);
609 if (!NT_STATUS_IS_OK(status)) {
610 dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN,
611 &call->pkt.u.request.stub_and_verifier);
612 return dcesrv_fault(call, DCERPC_FAULT_NDR);
615 if (pull->offset != pull->data_size) {
616 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
617 pull->data_size - pull->offset));
618 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
621 call->fault_code = 0;
623 /* call the dispatch function */
624 status = call->conn->iface->dispatch(call, call, r);
625 if (!NT_STATUS_IS_OK(status)) {
626 dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN,
627 &call->pkt.u.request.stub_and_verifier);
628 return dcesrv_fault(call, call->fault_code);
631 /* form the reply NDR */
632 push = ndr_push_init_ctx(call);
634 return NT_STATUS_NO_MEMORY;
637 /* carry over the pointer count to the reply in case we are
638 using full pointer. See NDR specification for full
640 push->ptr_count = pull->ptr_count;
642 if (lp_rpc_big_endian()) {
643 push->flags |= LIBNDR_FLAG_BIGENDIAN;
646 status = call->conn->iface->ndr->calls[opnum].ndr_push(push, NDR_OUT, r);
647 if (!NT_STATUS_IS_OK(status)) {
648 return dcesrv_fault(call, DCERPC_FAULT_NDR);
651 stub = ndr_push_blob(push);
653 total_length = stub.length;
657 struct dcesrv_call_reply *rep;
658 struct dcerpc_packet pkt;
660 rep = talloc_p(call, struct dcesrv_call_reply);
662 return NT_STATUS_NO_MEMORY;
665 length = stub.length;
666 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
667 /* the 32 is to cope with signing data */
668 length = call->conn->cli_max_recv_frag -
669 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
672 /* form the dcerpc response packet */
673 dcesrv_init_hdr(&pkt);
675 pkt.call_id = call->pkt.call_id;
676 pkt.ptype = DCERPC_PKT_RESPONSE;
678 if (stub.length == total_length) {
679 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
681 if (length == stub.length) {
682 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
684 pkt.u.response.alloc_hint = stub.length;
685 pkt.u.response.context_id = call->pkt.u.request.context_id;
686 pkt.u.response.cancel_count = 0;
687 pkt.u.response.stub_and_verifier.data = stub.data;
688 pkt.u.response.stub_and_verifier.length = length;
690 if (!dcesrv_auth_response(call, &rep->data, &pkt)) {
691 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
694 dcerpc_set_frag_length(&rep->data, rep->data.length);
696 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
699 stub.length -= length;
700 } while (stub.length != 0);
702 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
709 work out if we have a full packet yet
711 static BOOL dce_full_packet(const DATA_BLOB *data)
713 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
716 if (dcerpc_get_frag_length(data) > data->length) {
723 we might have consumed only part of our input - advance past that part
725 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
729 if (dce_conn->partial_input.length == offset) {
730 data_blob_free(&dce_conn->partial_input);
734 blob = dce_conn->partial_input;
735 dce_conn->partial_input = data_blob(blob.data + offset,
736 blob.length - offset);
737 data_blob_free(&blob);
741 process some input to a dcerpc endpoint server.
743 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
745 struct ndr_pull *ndr;
747 struct dcesrv_call_state *call;
750 call = talloc_p(dce_conn, struct dcesrv_call_state);
752 talloc_free(dce_conn->partial_input.data);
753 return NT_STATUS_NO_MEMORY;
755 call->conn = dce_conn;
756 call->replies = NULL;
758 blob = dce_conn->partial_input;
759 blob.length = dcerpc_get_frag_length(&blob);
761 ndr = ndr_pull_init_blob(&blob, call);
763 talloc_free(dce_conn->partial_input.data);
765 return NT_STATUS_NO_MEMORY;
768 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
769 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
772 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
773 if (!NT_STATUS_IS_OK(status)) {
774 talloc_free(dce_conn->partial_input.data);
779 /* we have to check the signing here, before combining the
781 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
782 !dcesrv_auth_request(call, &blob)) {
783 dce_partial_advance(dce_conn, blob.length);
784 return dcesrv_fault(call, DCERPC_FAULT_LOGON_FAILURE);
787 dce_partial_advance(dce_conn, blob.length);
789 /* see if this is a continued packet */
790 if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
791 struct dcesrv_call_state *call2 = call;
794 /* we only allow fragmented requests, no other packet types */
795 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
796 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
799 /* this is a continuation of an existing call - find the call then
800 tack it on the end */
801 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
803 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
806 if (call->pkt.ptype != call2->pkt.ptype) {
807 /* trying to play silly buggers are we? */
808 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
811 alloc_size = call->pkt.u.request.stub_and_verifier.length +
812 call2->pkt.u.request.stub_and_verifier.length;
813 if (call->pkt.u.request.alloc_hint > alloc_size) {
814 alloc_size = call->pkt.u.request.alloc_hint;
817 call->pkt.u.request.stub_and_verifier.data =
818 talloc_realloc(call, call->pkt.u.request.stub_and_verifier.data, alloc_size);
819 if (!call->pkt.u.request.stub_and_verifier.data) {
820 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
822 memcpy(call->pkt.u.request.stub_and_verifier.data +
823 call->pkt.u.request.stub_and_verifier.length,
824 call2->pkt.u.request.stub_and_verifier.data,
825 call2->pkt.u.request.stub_and_verifier.length);
826 call->pkt.u.request.stub_and_verifier.length +=
827 call2->pkt.u.request.stub_and_verifier.length;
829 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
834 /* this may not be the last pdu in the chain - if its isn't then
835 just put it on the call_list and wait for the rest */
836 if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
837 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
841 switch (call->pkt.ptype) {
842 case DCERPC_PKT_BIND:
843 status = dcesrv_bind(call);
845 case DCERPC_PKT_AUTH3:
846 status = dcesrv_auth3(call);
848 case DCERPC_PKT_REQUEST:
849 status = dcesrv_request(call);
852 status = NT_STATUS_INVALID_PARAMETER;
856 /* if we are going to be sending a reply then add
857 it to the list of pending calls. We add it to the end to keep the call
858 list in the order we will answer */
859 if (!NT_STATUS_IS_OK(status)) {
868 provide some input to a dcerpc endpoint server. This passes data
869 from a dcerpc client into the server
871 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
875 dce_conn->partial_input.data = talloc_realloc(dce_conn,
876 dce_conn->partial_input.data,
877 dce_conn->partial_input.length + data->length);
878 if (!dce_conn->partial_input.data) {
879 return NT_STATUS_NO_MEMORY;
881 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
882 data->data, data->length);
883 dce_conn->partial_input.length += data->length;
885 while (dce_full_packet(&dce_conn->partial_input)) {
886 status = dcesrv_input_process(dce_conn);
887 if (!NT_STATUS_IS_OK(status)) {
896 retrieve some output from a dcerpc server
897 The caller supplies a function that will be called to do the
900 The first argument to write_fn() will be 'private', the second will
901 be a pointer to a buffer containing the data to be sent and the 3rd
902 will be the number of bytes to be sent.
904 write_fn() should return the number of bytes successfully written.
906 this will return STATUS_BUFFER_OVERFLOW if there is more to be read
907 from the current fragment
909 NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
911 ssize_t (*write_fn)(void *, DATA_BLOB *))
913 struct dcesrv_call_state *call;
914 struct dcesrv_call_reply *rep;
917 call = dce_conn->call_list;
918 if (!call || !call->replies) {
919 return NT_STATUS_FOOBAR;
923 nwritten = write_fn(private, &rep->data);
924 if (nwritten == -1) {
925 /* TODO: hmm, how do we cope with this? destroy the
926 connection perhaps? */
927 return NT_STATUS_UNSUCCESSFUL;
930 rep->data.length -= nwritten;
931 rep->data.data += nwritten;
933 if (rep->data.length == 0) {
934 /* we're done with this section of the call */
935 DLIST_REMOVE(call->replies, rep);
938 if (call->replies == NULL) {
939 /* we're done with the whole call */
940 DLIST_REMOVE(dce_conn->call_list, call);
949 write_fn() for dcesrv_output_blob()
951 static ssize_t dcesrv_output_blob_write_fn(void *private, DATA_BLOB *out)
953 DATA_BLOB *blob = private;
954 if (out->length < blob->length) {
955 blob->length = out->length;
957 memcpy(blob->data, out->data, blob->length);
962 a simple wrapper for dcesrv_output() for when we want to output
965 NTSTATUS dcesrv_output_blob(struct dcesrv_connection *dce_conn,
968 return dcesrv_output(dce_conn, blob, dcesrv_output_blob_write_fn);
972 initialise the dcerpc server context
974 NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **dce_ctx)
977 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
979 (*dce_ctx) = talloc_p(mem_ctx, struct dcesrv_context);
981 return NT_STATUS_NO_MEMORY;
984 (*dce_ctx)->endpoint_list = NULL;
986 if (!endpoint_servers) {
987 DEBUG(3,("dcesrv_init_context: no endpoint servers configured\n"));
991 for (i=0;endpoint_servers[i];i++) {
993 const struct dcesrv_endpoint_server *ep_server;
995 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
997 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
998 return NT_STATUS_UNSUCCESSFUL;
1001 ret = ep_server->init_server(*dce_ctx, ep_server);
1002 if (!NT_STATUS_IS_OK(ret)) {
1003 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1008 return NT_STATUS_OK;
1011 static void dcesrv_init(struct server_service *service, const struct model_ops *model_ops)
1013 struct dcesrv_context *dce_ctx;
1015 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
1017 DEBUG(1,("dcesrv_init\n"));
1019 if (!endpoint_servers) {
1020 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1024 dce_ctx = talloc_p(service, struct dcesrv_context);
1026 DEBUG(0,("talloc_p(mem_ctx, struct dcesrv_context) failed\n"));
1030 ZERO_STRUCTP(dce_ctx);
1031 dce_ctx->endpoint_list = NULL;
1033 for (i=0;endpoint_servers[i];i++) {
1035 const struct dcesrv_endpoint_server *ep_server;
1037 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1039 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1043 ret = ep_server->init_server(dce_ctx, ep_server);
1044 if (!NT_STATUS_IS_OK(ret)) {
1045 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1050 dcesrv_sock_init(service, model_ops, dce_ctx);
1055 static void dcesrv_accept(struct server_connection *srv_conn)
1057 dcesrv_sock_accept(srv_conn);
1060 static void dcesrv_recv(struct server_connection *srv_conn,
1061 struct timeval t, uint16_t flags)
1063 dcesrv_sock_recv(srv_conn, t, flags);
1066 static void dcesrv_send(struct server_connection *srv_conn,
1067 struct timeval t, uint16_t flags)
1069 dcesrv_sock_send(srv_conn, t, flags);
1072 static void dcesrv_close(struct server_connection *srv_conn, const char *reason)
1074 dcesrv_sock_close(srv_conn, reason);
1078 static void dcesrv_exit(struct server_service *service, const char *reason)
1080 dcesrv_sock_exit(service, reason);
1084 /* the list of currently registered DCERPC endpoint servers.
1087 struct dcesrv_endpoint_server *ep_server;
1088 } *ep_servers = NULL;
1089 static int num_ep_servers;
1092 register a DCERPC endpoint server.
1094 The 'name' can be later used by other backends to find the operations
1095 structure for this backend.
1097 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1099 static NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1101 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1103 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1104 /* its already registered! */
1105 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1107 return NT_STATUS_OBJECT_NAME_COLLISION;
1110 ep_servers = Realloc(ep_servers, sizeof(ep_servers[0]) * (num_ep_servers+1));
1112 smb_panic("out of memory in dcerpc_register");
1115 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1116 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1120 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1123 return NT_STATUS_OK;
1127 return the operations structure for a named backend of the specified type
1129 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1133 for (i=0;i<num_ep_servers;i++) {
1134 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1135 return ep_servers[i].ep_server;
1143 return the DCERPC module version, and the size of some critical types
1144 This can be used by endpoint server modules to either detect compilation errors, or provide
1145 multiple implementations for different smbd compilation options in one module
1147 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1149 static const struct dcesrv_critical_sizes critical_sizes = {
1150 DCERPC_MODULE_VERSION,
1151 sizeof(struct dcesrv_context),
1152 sizeof(struct dcesrv_endpoint),
1153 sizeof(struct dcesrv_endpoint_server),
1154 sizeof(struct dcesrv_interface),
1155 sizeof(struct dcesrv_if_list),
1156 sizeof(struct dcesrv_connection),
1157 sizeof(struct dcesrv_call_state),
1158 sizeof(struct dcesrv_auth),
1159 sizeof(struct dcesrv_handle)
1162 return &critical_sizes;
1166 initialise the DCERPC subsystem
1168 BOOL subsystem_dcerpc_init(void)
1172 status = register_subsystem("dcerpc", dcerpc_register_ep_server);
1173 if (!NT_STATUS_IS_OK(status)) {
1177 /* FIXME: Perhaps panic if a basic endpoint server, such as EPMAPPER, fails to initialise? */
1180 DEBUG(3,("DCERPC subsystem version %d initialised\n", DCERPC_MODULE_VERSION));
1184 static const struct server_service_ops dcesrv_ops = {
1186 .service_init = dcesrv_init,
1187 .accept_connection = dcesrv_accept,
1188 .recv_handler = dcesrv_recv,
1189 .send_handler = dcesrv_send,
1190 .idle_handler = NULL,
1191 .close_connection = dcesrv_close,
1192 .service_exit = dcesrv_exit,
1195 const struct server_service_ops *dcesrv_get_ops(void)
1200 NTSTATUS server_service_rpc_init(void)
1202 return NT_STATUS_OK;