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.
27 see if two endpoints match
29 static BOOL endpoints_match(const struct dcesrv_ep_description *ep1,
30 const struct dcesrv_ep_description *ep2)
32 if (ep1->type != ep2->type) {
38 if (strcmp(ep1->info.smb_pipe,ep2->info.smb_pipe)==0) {
43 if (ep1->info.tcp_port == ep2->info.tcp_port) {
53 find an endpoint in the dcesrv_context
55 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
56 const struct dcesrv_ep_description *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 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 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 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_ep_description ep_description;
154 struct dcesrv_endpoint *ep;
155 struct dcesrv_if_list *ifl;
159 tcp = (strncasecmp(ep_name, "TCP-", 4) == 0);
162 ep_description.type = ENDPOINT_TCP;
163 ep_description.info.tcp_port = atoi(ep_name+4);
165 ep_description.type = ENDPOINT_SMB;
166 ep_description.info.smb_pipe = ep_name;
169 /* check if this endpoint exists
171 if ((ep=find_endpoint(dce_ctx, &ep_description))==NULL) {
172 ep = talloc(dce_ctx->mem_ctx, sizeof(*ep));
174 return NT_STATUS_NO_MEMORY;
178 ep->ep_description.type = ENDPOINT_TCP;
179 ep->ep_description.info.tcp_port = atoi(ep_name+4);
181 ep->ep_description.type = ENDPOINT_SMB;
182 ep->ep_description.info.smb_pipe = smb_xstrdup(ep_name);
187 /* see if the interface is already registered on te endpoint */
188 if (find_interface(ep, iface)!=NULL) {
189 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
190 iface->ndr->name, ep_name));
191 return NT_STATUS_OBJECT_NAME_COLLISION;
194 /* talloc a new interface list element */
195 ifl = talloc(dce_ctx->mem_ctx, sizeof(*ifl));
197 return NT_STATUS_NO_MEMORY;
200 /* copy the given interface struct to the one on the endpoints interface list */
201 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
203 /* if we have a security descriptor given,
204 * we should see if we can set it up on the endpoint
207 /* if there's currently no security descriptor given on the endpoint
210 if (ep->sd == NULL) {
211 ep->sd = copy_security_descriptor(dce_ctx->mem_ctx, sd);
214 /* if now there's no security descriptor given on the endpoint
215 * something goes wrong, either we failed to copy the security descriptor
216 * or there was already one on the endpoint
218 if (ep->sd != NULL) {
219 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
220 " on endpoint '%s'\n",
221 iface->ndr->name, ep_name));
222 if (add_ep) free(ep);
224 return NT_STATUS_OBJECT_NAME_COLLISION;
228 /* finally add the interface on the endpoint */
229 DLIST_ADD(ep->interface_list, ifl);
231 /* if it's a new endpoint add it to the dcesrv_context */
233 DLIST_ADD(dce_ctx->endpoint_list, ep);
236 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
237 iface->ndr->name, ep_name));
243 connect to a dcerpc endpoint
245 NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
246 const struct dcesrv_endpoint *ep,
247 struct dcesrv_connection **p)
251 mem_ctx = talloc_init("dcesrv_endpoint_connect");
253 return NT_STATUS_NO_MEMORY;
256 *p = talloc_p(mem_ctx, struct dcesrv_connection);
258 talloc_destroy(mem_ctx);
259 return NT_STATUS_NO_MEMORY;
262 (*p)->dce_ctx = dce_ctx;
263 (*p)->mem_ctx = mem_ctx;
266 (*p)->private = NULL;
267 (*p)->call_list = NULL;
268 (*p)->cli_max_recv_frag = 0;
269 (*p)->handles = NULL;
270 (*p)->partial_input = data_blob(NULL, 0);
271 (*p)->auth_state.ntlmssp_state = NULL;
272 (*p)->auth_state.auth_info = NULL;
278 search and connect to a dcerpc endpoint
280 NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
281 const struct dcesrv_ep_description *ep_description,
282 struct dcesrv_connection **dce_conn_p)
285 const struct dcesrv_endpoint *ep;
287 /* make sure this endpoint exists */
288 ep = find_endpoint(dce_ctx, ep_description);
290 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
293 status = dcesrv_endpoint_connect(dce_ctx, ep, dce_conn_p);
294 if (!NT_STATUS_IS_OK(status)) {
298 /* TODO: check security descriptor of the endpoint here
299 * if it's a smb named pipe
300 * if it's failed free dce_conn_p
308 disconnect a link to an endpoint
310 void dcesrv_endpoint_disconnect(struct dcesrv_connection *p)
313 p->iface->unbind(p, p->iface);
316 /* destroy any handles */
318 dcesrv_handle_destroy(p, p->handles);
321 talloc_destroy(p->mem_ctx);
324 static void dcesrv_init_hdr(struct dcerpc_packet *pkt)
327 pkt->rpc_vers_minor = 0;
328 if (lp_rpc_big_endian()) {
331 pkt->drep[0] = DCERPC_DREP_LE;
339 return a dcerpc fault
341 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32 fault_code)
343 struct dcerpc_packet pkt;
344 struct dcesrv_call_reply *rep;
347 /* setup a bind_ack */
348 dcesrv_init_hdr(&pkt);
350 pkt.call_id = call->pkt.call_id;
351 pkt.ptype = DCERPC_PKT_FAULT;
352 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
353 pkt.u.fault.alloc_hint = 0;
354 pkt.u.fault.context_id = 0;
355 pkt.u.fault.cancel_count = 0;
356 pkt.u.fault.status = fault_code;
358 rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
360 return NT_STATUS_NO_MEMORY;
363 status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt, NULL);
364 if (!NT_STATUS_IS_OK(status)) {
368 dcerpc_set_frag_length(&rep->data, rep->data.length);
370 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
377 return a dcerpc fault from a ntstatus code
379 static NTSTATUS dcesrv_fault_nt(struct dcesrv_call_state *call, NTSTATUS status)
381 uint32 fault_code = DCERPC_FAULT_OTHER;
383 /* TODO: we need to expand this table to include more mappings */
384 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
385 fault_code = DCERPC_FAULT_CONTEXT_MISMATCH;
388 return dcesrv_fault(call, fault_code);
393 return a dcerpc bind_nak
395 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32 reason)
397 struct dcerpc_packet pkt;
398 struct dcesrv_call_reply *rep;
401 /* setup a bind_ack */
402 dcesrv_init_hdr(&pkt);
404 pkt.call_id = call->pkt.call_id;
405 pkt.ptype = DCERPC_PKT_BIND_NAK;
406 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
407 pkt.u.bind_nak.reject_reason = reason;
408 pkt.u.bind_nak.num_versions = 0;
410 rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
412 return NT_STATUS_NO_MEMORY;
415 status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt, NULL);
416 if (!NT_STATUS_IS_OK(status)) {
420 dcerpc_set_frag_length(&rep->data, rep->data.length);
422 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
429 handle a bind request
431 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
433 const char *uuid, *transfer_syntax;
434 uint32 if_version, transfer_syntax_version;
435 struct dcerpc_packet pkt;
436 struct dcesrv_call_reply *rep;
438 uint32 result=0, reason=0;
440 if (call->pkt.u.bind.num_contexts != 1 ||
441 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
442 return dcesrv_bind_nak(call, 0);
445 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
446 uuid = GUID_string(call->mem_ctx, &call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid);
448 return dcesrv_bind_nak(call, 0);
451 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
452 transfer_syntax = GUID_string(call->mem_ctx,
453 &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid);
454 if (!transfer_syntax ||
455 strcasecmp(NDR_GUID, transfer_syntax) != 0 ||
456 NDR_GUID_VERSION != transfer_syntax_version) {
457 /* we only do NDR encoded dcerpc */
458 return dcesrv_bind_nak(call, 0);
461 call->conn->iface = find_interface_by_uuid(call->conn->endpoint, uuid, if_version);
462 if (!call->conn->iface) {
463 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
464 /* we don't know about that interface */
465 result = DCERPC_BIND_PROVIDER_REJECT;
466 reason = DCERPC_BIND_REASON_ASYNTAX;
469 if (call->conn->cli_max_recv_frag == 0) {
470 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
473 /* handle any authentication that is being requested */
474 if (!dcesrv_auth_bind(call)) {
475 return dcesrv_bind_nak(call, 0);
478 /* setup a bind_ack */
479 dcesrv_init_hdr(&pkt);
481 pkt.call_id = call->pkt.call_id;
482 pkt.ptype = DCERPC_PKT_BIND_ACK;
483 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
484 pkt.u.bind_ack.max_xmit_frag = 0x2000;
485 pkt.u.bind_ack.max_recv_frag = 0x2000;
486 pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
487 if (call->conn->iface && call->conn->iface->ndr) {
488 pkt.u.bind_ack.secondary_address = talloc_asprintf(call->mem_ctx, "\\PIPE\\%s",
489 call->conn->iface->ndr->name);
491 pkt.u.bind_ack.secondary_address = "";
493 pkt.u.bind_ack.num_results = 1;
494 pkt.u.bind_ack.ctx_list = talloc_p(call->mem_ctx, struct dcerpc_ack_ctx);
495 if (!pkt.u.bind_ack.ctx_list) {
496 return NT_STATUS_NO_MEMORY;
498 pkt.u.bind_ack.ctx_list[0].result = result;
499 pkt.u.bind_ack.ctx_list[0].reason = reason;
500 GUID_from_string(NDR_GUID, &pkt.u.bind_ack.ctx_list[0].syntax.uuid);
501 pkt.u.bind_ack.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
502 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
504 if (!dcesrv_auth_bind_ack(call, &pkt)) {
505 return dcesrv_bind_nak(call, 0);
508 if (call->conn->iface) {
509 status = call->conn->iface->bind(call, call->conn->iface);
510 if (!NT_STATUS_IS_OK(status)) {
511 DEBUG(2,("Request for dcerpc interface %s/%d rejected\n", uuid, if_version));
516 rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
518 return NT_STATUS_NO_MEMORY;
521 status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt,
522 call->conn->auth_state.auth_info);
523 if (!NT_STATUS_IS_OK(status)) {
527 dcerpc_set_frag_length(&rep->data, rep->data.length);
529 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
530 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
537 handle a auth3 request
539 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
541 /* handle the auth3 in the auth code */
542 if (!dcesrv_auth_auth3(call)) {
543 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
546 talloc_destroy(call->mem_ctx);
548 /* we don't send a reply to a auth3 request, except by a
555 handle a dcerpc request packet
557 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
559 struct ndr_pull *pull;
560 struct ndr_push *push;
566 opnum = call->pkt.u.request.opnum;
568 if (opnum >= call->conn->iface->ndr->num_calls) {
569 return dcesrv_fault(call, DCERPC_FAULT_OP_RNG_ERROR);
572 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call->mem_ctx);
574 return NT_STATUS_NO_MEMORY;
577 r = talloc(call->mem_ctx, call->conn->iface->ndr->calls[opnum].struct_size);
579 return NT_STATUS_NO_MEMORY;
582 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
583 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
586 /* unravel the NDR for the packet */
587 status = call->conn->iface->ndr->calls[opnum].ndr_pull(pull, NDR_IN, r);
588 if (!NT_STATUS_IS_OK(status)) {
589 return dcesrv_fault(call, DCERPC_FAULT_NDR);
592 /* call the dispatch function */
593 status = call->conn->iface->dispatch(call, call->mem_ctx, r);
594 if (!NT_STATUS_IS_OK(status)) {
595 return dcesrv_fault_nt(call, status);
598 /* form the reply NDR */
599 push = ndr_push_init_ctx(call->mem_ctx);
601 return NT_STATUS_NO_MEMORY;
604 if (lp_rpc_big_endian()) {
605 push->flags |= LIBNDR_FLAG_BIGENDIAN;
608 status = call->conn->iface->ndr->calls[opnum].ndr_push(push, NDR_OUT, r);
609 if (!NT_STATUS_IS_OK(status)) {
610 return dcesrv_fault(call, DCERPC_FAULT_NDR);
613 stub = ndr_push_blob(push);
617 struct dcesrv_call_reply *rep;
618 struct dcerpc_packet pkt;
620 rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
622 return NT_STATUS_NO_MEMORY;
625 length = stub.length;
626 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
627 /* the 32 is to cope with signing data */
628 length = call->conn->cli_max_recv_frag -
629 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
632 /* form the dcerpc response packet */
633 dcesrv_init_hdr(&pkt);
635 pkt.call_id = call->pkt.call_id;
636 pkt.ptype = DCERPC_PKT_RESPONSE;
638 if (!call->replies) {
639 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
641 if (length == stub.length) {
642 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
644 pkt.u.response.alloc_hint = stub.length;
645 pkt.u.response.context_id = call->pkt.u.request.context_id;
646 pkt.u.response.cancel_count = 0;
647 pkt.u.response.stub_and_verifier.data = stub.data;
648 pkt.u.response.stub_and_verifier.length = length;
650 if (!dcesrv_auth_response(call, &rep->data, &pkt)) {
651 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
654 dcerpc_set_frag_length(&rep->data, rep->data.length);
656 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
659 stub.length -= length;
660 } while (stub.length != 0);
662 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
669 work out if we have a full packet yet
671 static BOOL dce_full_packet(const DATA_BLOB *data)
673 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
676 if (dcerpc_get_frag_length(data) > data->length) {
683 we might have consumed only part of our input - advance past that part
685 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32 offset)
689 if (dce_conn->partial_input.length == offset) {
690 data_blob_free(&dce_conn->partial_input);
694 blob = dce_conn->partial_input;
695 dce_conn->partial_input = data_blob(blob.data + offset,
696 blob.length - offset);
697 data_blob_free(&blob);
701 process some input to a dcerpc endpoint server.
703 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
705 struct ndr_pull *ndr;
708 struct dcesrv_call_state *call;
711 mem_ctx = talloc_init("dcesrv_input");
713 return NT_STATUS_NO_MEMORY;
715 call = talloc_p(mem_ctx, struct dcesrv_call_state);
717 talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
718 talloc_destroy(mem_ctx);
719 return NT_STATUS_NO_MEMORY;
721 call->mem_ctx = mem_ctx;
722 call->conn = dce_conn;
723 call->replies = NULL;
725 blob = dce_conn->partial_input;
726 blob.length = dcerpc_get_frag_length(&blob);
728 ndr = ndr_pull_init_blob(&blob, mem_ctx);
730 talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
731 talloc_destroy(mem_ctx);
732 return NT_STATUS_NO_MEMORY;
735 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
736 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
739 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
740 if (!NT_STATUS_IS_OK(status)) {
741 talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
742 talloc_destroy(mem_ctx);
746 dce_partial_advance(dce_conn, blob.length);
748 /* we have to check the signing here, before combining the
750 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
751 !dcesrv_auth_request(call)) {
752 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
755 /* see if this is a continued packet */
756 if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
757 struct dcesrv_call_state *call2 = call;
760 /* we only allow fragmented requests, no other packet types */
761 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
762 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
765 /* this is a continuation of an existing call - find the call then
766 tack it on the end */
767 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
769 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
772 if (call->pkt.ptype != call2->pkt.ptype) {
773 /* trying to play silly buggers are we? */
774 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
777 alloc_size = call->pkt.u.request.stub_and_verifier.length +
778 call2->pkt.u.request.stub_and_verifier.length;
779 if (call->pkt.u.request.alloc_hint > alloc_size) {
780 alloc_size = call->pkt.u.request.alloc_hint;
783 call->pkt.u.request.stub_and_verifier.data =
784 talloc_realloc(call->mem_ctx,
785 call->pkt.u.request.stub_and_verifier.data, alloc_size);
786 if (!call->pkt.u.request.stub_and_verifier.data) {
787 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
789 memcpy(call->pkt.u.request.stub_and_verifier.data +
790 call->pkt.u.request.stub_and_verifier.length,
791 call2->pkt.u.request.stub_and_verifier.data,
792 call2->pkt.u.request.stub_and_verifier.length);
793 call->pkt.u.request.stub_and_verifier.length +=
794 call2->pkt.u.request.stub_and_verifier.length;
796 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
799 /* this may not be the last pdu in the chain - if its isn't then
800 just put it on the call_list and wait for the rest */
801 if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
802 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
806 switch (call->pkt.ptype) {
807 case DCERPC_PKT_BIND:
808 status = dcesrv_bind(call);
810 case DCERPC_PKT_AUTH3:
811 status = dcesrv_auth3(call);
813 case DCERPC_PKT_REQUEST:
814 status = dcesrv_request(call);
817 status = NT_STATUS_INVALID_PARAMETER;
821 /* if we are going to be sending a reply then add
822 it to the list of pending calls. We add it to the end to keep the call
823 list in the order we will answer */
824 if (!NT_STATUS_IS_OK(status)) {
825 talloc_destroy(mem_ctx);
833 provide some input to a dcerpc endpoint server. This passes data
834 from a dcerpc client into the server
836 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
840 /* handle the very common case that the input contains a full packet and there
841 is no partial packet pending. In this case we can avoid a copy of the
843 if (dce_conn->partial_input.length == 0) {
844 dce_conn->partial_input = *data;
845 /* make sure that dce_partial_advance doesn't free this data */
846 dce_conn->partial_input.free = NULL;
847 while (dce_full_packet(&dce_conn->partial_input)) {
848 status = dcesrv_input_process(dce_conn);
849 if (!NT_STATUS_IS_OK(status)) {
853 if (dce_conn->partial_input.length) {
854 /* there was some data left over. We have to copy this
855 as the caller may free the data */
856 dce_conn->partial_input =
857 data_blob(dce_conn->partial_input.data,
858 dce_conn->partial_input.length);
859 if (!dce_conn->partial_input.data) {
860 return NT_STATUS_NO_MEMORY;
866 dce_conn->partial_input.data = Realloc(dce_conn->partial_input.data,
867 dce_conn->partial_input.length + data->length);
868 if (!dce_conn->partial_input.data) {
869 return NT_STATUS_NO_MEMORY;
871 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
872 data->data, data->length);
873 dce_conn->partial_input.length += data->length;
875 while (dce_full_packet(&dce_conn->partial_input)) {
876 status = dcesrv_input_process(dce_conn);
877 if (!NT_STATUS_IS_OK(status)) {
886 retrieve some output from a dcerpc server
887 The caller supplies a function that will be called to do the
890 The first argument to write_fn() will be 'private', the second will
891 be a pointer to a buffer containing the data to be sent and the 3rd
892 will be the number of bytes to be sent.
894 write_fn() should return the number of bytes successfully written.
896 NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
898 ssize_t (*write_fn)(void *, const void *, size_t))
900 struct dcesrv_call_state *call;
901 struct dcesrv_call_reply *rep;
904 call = dce_conn->call_list;
905 if (!call || !call->replies) {
906 return NT_STATUS_FOOBAR;
910 nwritten = write_fn(private, rep->data.data, rep->data.length);
911 if (nwritten == -1) {
912 /* TODO: hmm, how do we cope with this? destroy the
913 connection perhaps? */
914 return NT_STATUS_UNSUCCESSFUL;
917 rep->data.length -= nwritten;
918 rep->data.data += nwritten;
920 if (rep->data.length == 0) {
921 /* we're done with this section of the call */
922 DLIST_REMOVE(call->replies, rep);
925 if (call->replies == NULL) {
926 /* we're done with the whole call */
927 DLIST_REMOVE(dce_conn->call_list, call);
928 talloc_destroy(call->mem_ctx);
936 write_fn() for dcesrv_output_blob()
938 static ssize_t dcesrv_output_blob_write_fn(void *private, const void *buf, size_t count)
940 DATA_BLOB *blob = private;
941 if (count < blob->length) {
942 blob->length = count;
944 memcpy(blob->data, buf, blob->length);
949 a simple wrapper for dcesrv_output() for when we want to output
952 NTSTATUS dcesrv_output_blob(struct dcesrv_connection *dce_conn,
955 return dcesrv_output(dce_conn, blob, dcesrv_output_blob_write_fn);
959 initialise the dcerpc server context
961 NTSTATUS dcesrv_init_context(struct dcesrv_context *dce_ctx)
964 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
966 dce_ctx->mem_ctx = talloc_init("struct dcesrv_context");
967 if (!dce_ctx->mem_ctx) {
968 DEBUG(3,("dcesrv_init_context: talloc_init failed\n"));
969 return NT_STATUS_NO_MEMORY;
972 dce_ctx->endpoint_list = NULL;
974 if (!endpoint_servers) {
975 DEBUG(3,("dcesrv_init_context: no endpoint servers configured\n"));
979 for (i=0;endpoint_servers[i];i++) {
981 const struct dcesrv_endpoint_server *ep_server;
983 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
985 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
986 return NT_STATUS_UNSUCCESSFUL;
989 ret = ep_server->init_server(dce_ctx, ep_server);
990 if (!NT_STATUS_IS_OK(ret)) {
991 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
999 /* the list of currently registered DCERPC endpoint servers.
1002 struct dcesrv_endpoint_server *ep_server;
1003 } *ep_servers = NULL;
1004 static int num_ep_servers;
1007 register a DCERPC endpoint server.
1009 The 'name' can be later used by other backends to find the operations
1010 structure for this backend.
1012 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1014 static NTSTATUS decrpc_register_ep_server(void *_ep_server)
1016 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1018 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1019 /* its already registered! */
1020 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1022 return NT_STATUS_OBJECT_NAME_COLLISION;
1025 ep_servers = Realloc(ep_servers, sizeof(ep_servers[0]) * (num_ep_servers+1));
1027 smb_panic("out of memory in decrpc_register");
1030 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1031 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1035 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1038 return NT_STATUS_OK;
1042 return the operations structure for a named backend of the specified type
1044 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1048 for (i=0;i<num_ep_servers;i++) {
1049 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1050 return ep_servers[i].ep_server;
1058 return the DCERPC module version, and the size of some critical types
1059 This can be used by endpoint server modules to either detect compilation errors, or provide
1060 multiple implementations for different smbd compilation options in one module
1062 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1064 static const struct dcesrv_critical_sizes critical_sizes = {
1065 DCERPC_MODULE_VERSION,
1066 sizeof(struct dcesrv_context),
1067 sizeof(struct dcesrv_endpoint),
1068 sizeof(struct dcesrv_endpoint_server),
1069 sizeof(struct dcesrv_ep_description),
1070 sizeof(struct dcesrv_interface),
1071 sizeof(struct dcesrv_if_list),
1072 sizeof(struct dcesrv_connection),
1073 sizeof(struct dcesrv_call_state),
1074 sizeof(struct dcesrv_auth),
1075 sizeof(struct dcesrv_handle)
1078 return &critical_sizes;
1082 initialise the DCERPC subsystem
1084 BOOL dcesrv_init(void)
1088 status = register_subsystem("dcerpc", decrpc_register_ep_server);
1089 if (!NT_STATUS_IS_OK(status)) {
1093 /* FIXME: Perhaps panic if a basic endpoint server, such as EPMAPER, fails to initialise? */
1096 DEBUG(3,("DCERPC subsystem version %d initialised\n", DCERPC_MODULE_VERSION));