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 TALLOC_CTX *m = p->handles->mem_ctx;
319 DLIST_REMOVE(p->handles, p->handles);
323 talloc_destroy(p->mem_ctx);
326 static void dcesrv_init_hdr(struct dcerpc_packet *pkt)
329 pkt->rpc_vers_minor = 0;
330 if (lp_rpc_big_endian()) {
333 pkt->drep[0] = DCERPC_DREP_LE;
341 return a dcerpc fault
343 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32 fault_code)
345 struct dcerpc_packet pkt;
346 struct dcesrv_call_reply *rep;
349 /* setup a bind_ack */
350 dcesrv_init_hdr(&pkt);
352 pkt.call_id = call->pkt.call_id;
353 pkt.ptype = DCERPC_PKT_FAULT;
354 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
355 pkt.u.fault.alloc_hint = 0;
356 pkt.u.fault.context_id = 0;
357 pkt.u.fault.cancel_count = 0;
358 pkt.u.fault.status = fault_code;
360 rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
362 return NT_STATUS_NO_MEMORY;
365 status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt, NULL);
366 if (!NT_STATUS_IS_OK(status)) {
370 dcerpc_set_frag_length(&rep->data, rep->data.length);
372 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
379 return a dcerpc fault from a ntstatus code
381 static NTSTATUS dcesrv_fault_nt(struct dcesrv_call_state *call, NTSTATUS status)
383 uint32 fault_code = DCERPC_FAULT_OTHER;
385 /* TODO: we need to expand this table to include more mappings */
386 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
387 fault_code = DCERPC_FAULT_CONTEXT_MISMATCH;
390 return dcesrv_fault(call, fault_code);
395 return a dcerpc bind_nak
397 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32 reason)
399 struct dcerpc_packet pkt;
400 struct dcesrv_call_reply *rep;
403 /* setup a bind_ack */
404 dcesrv_init_hdr(&pkt);
406 pkt.call_id = call->pkt.call_id;
407 pkt.ptype = DCERPC_PKT_BIND_NAK;
408 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
409 pkt.u.bind_nak.reject_reason = reason;
410 pkt.u.bind_nak.num_versions = 0;
412 rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
414 return NT_STATUS_NO_MEMORY;
417 status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt, NULL);
418 if (!NT_STATUS_IS_OK(status)) {
422 dcerpc_set_frag_length(&rep->data, rep->data.length);
424 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
431 handle a bind request
433 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
435 const char *uuid, *transfer_syntax;
436 uint32 if_version, transfer_syntax_version;
437 struct dcerpc_packet pkt;
438 struct dcesrv_call_reply *rep;
440 uint32 result=0, reason=0;
442 if (call->pkt.u.bind.num_contexts != 1 ||
443 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
444 return dcesrv_bind_nak(call, 0);
447 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
448 uuid = GUID_string(call->mem_ctx, &call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid);
450 return dcesrv_bind_nak(call, 0);
453 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
454 transfer_syntax = GUID_string(call->mem_ctx,
455 &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid);
456 if (!transfer_syntax ||
457 strcasecmp(NDR_GUID, transfer_syntax) != 0 ||
458 NDR_GUID_VERSION != transfer_syntax_version) {
459 /* we only do NDR encoded dcerpc */
460 return dcesrv_bind_nak(call, 0);
463 call->conn->iface = find_interface_by_uuid(call->conn->endpoint, uuid, if_version);
464 if (!call->conn->iface) {
465 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
466 /* we don't know about that interface */
467 result = DCERPC_BIND_PROVIDER_REJECT;
468 reason = DCERPC_BIND_REASON_ASYNTAX;
471 if (call->conn->cli_max_recv_frag == 0) {
472 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
475 /* handle any authentication that is being requested */
476 if (!dcesrv_auth_bind(call)) {
477 return dcesrv_bind_nak(call, 0);
480 /* setup a bind_ack */
481 dcesrv_init_hdr(&pkt);
483 pkt.call_id = call->pkt.call_id;
484 pkt.ptype = DCERPC_PKT_BIND_ACK;
485 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
486 pkt.u.bind_ack.max_xmit_frag = 0x2000;
487 pkt.u.bind_ack.max_recv_frag = 0x2000;
488 pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
489 if (call->conn->iface && call->conn->iface->ndr) {
490 pkt.u.bind_ack.secondary_address = talloc_asprintf(call->mem_ctx, "\\PIPE\\%s",
491 call->conn->iface->ndr->name);
493 pkt.u.bind_ack.secondary_address = "";
495 pkt.u.bind_ack.num_results = 1;
496 pkt.u.bind_ack.ctx_list = talloc_p(call->mem_ctx, struct dcerpc_ack_ctx);
497 if (!pkt.u.bind_ack.ctx_list) {
498 return NT_STATUS_NO_MEMORY;
500 pkt.u.bind_ack.ctx_list[0].result = result;
501 pkt.u.bind_ack.ctx_list[0].reason = reason;
502 GUID_from_string(NDR_GUID, &pkt.u.bind_ack.ctx_list[0].syntax.uuid);
503 pkt.u.bind_ack.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
504 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
506 if (!dcesrv_auth_bind_ack(call, &pkt)) {
507 return dcesrv_bind_nak(call, 0);
510 if (call->conn->iface) {
511 status = call->conn->iface->bind(call, call->conn->iface);
512 if (!NT_STATUS_IS_OK(status)) {
513 DEBUG(2,("Request for dcerpc interface %s/%d rejected\n", uuid, if_version));
518 rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
520 return NT_STATUS_NO_MEMORY;
523 status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt,
524 call->conn->auth_state.auth_info);
525 if (!NT_STATUS_IS_OK(status)) {
529 dcerpc_set_frag_length(&rep->data, rep->data.length);
531 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
532 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
539 handle a auth3 request
541 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
543 /* handle the auth3 in the auth code */
544 if (!dcesrv_auth_auth3(call)) {
545 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
548 talloc_destroy(call->mem_ctx);
550 /* we don't send a reply to a auth3 request, except by a
557 handle a dcerpc request packet
559 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
561 struct ndr_pull *pull;
562 struct ndr_push *push;
568 opnum = call->pkt.u.request.opnum;
570 if (opnum >= call->conn->iface->ndr->num_calls) {
571 return dcesrv_fault(call, DCERPC_FAULT_OP_RNG_ERROR);
574 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call->mem_ctx);
576 return NT_STATUS_NO_MEMORY;
579 r = talloc(call->mem_ctx, call->conn->iface->ndr->calls[opnum].struct_size);
581 return NT_STATUS_NO_MEMORY;
584 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
585 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
588 /* unravel the NDR for the packet */
589 status = call->conn->iface->ndr->calls[opnum].ndr_pull(pull, NDR_IN, r);
590 if (!NT_STATUS_IS_OK(status)) {
591 return dcesrv_fault(call, DCERPC_FAULT_NDR);
594 /* call the dispatch function */
595 status = call->conn->iface->dispatch(call, call->mem_ctx, r);
596 if (!NT_STATUS_IS_OK(status)) {
597 return dcesrv_fault_nt(call, status);
600 /* form the reply NDR */
601 push = ndr_push_init_ctx(call->mem_ctx);
603 return NT_STATUS_NO_MEMORY;
606 if (lp_rpc_big_endian()) {
607 push->flags |= LIBNDR_FLAG_BIGENDIAN;
610 status = call->conn->iface->ndr->calls[opnum].ndr_push(push, NDR_OUT, r);
611 if (!NT_STATUS_IS_OK(status)) {
612 return dcesrv_fault(call, DCERPC_FAULT_NDR);
615 stub = ndr_push_blob(push);
619 struct dcesrv_call_reply *rep;
620 struct dcerpc_packet pkt;
622 rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
624 return NT_STATUS_NO_MEMORY;
627 length = stub.length;
628 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
629 /* the 32 is to cope with signing data */
630 length = call->conn->cli_max_recv_frag -
631 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
634 /* form the dcerpc response packet */
635 dcesrv_init_hdr(&pkt);
637 pkt.call_id = call->pkt.call_id;
638 pkt.ptype = DCERPC_PKT_RESPONSE;
640 if (!call->replies) {
641 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
643 if (length == stub.length) {
644 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
646 pkt.u.response.alloc_hint = stub.length;
647 pkt.u.response.context_id = call->pkt.u.request.context_id;
648 pkt.u.response.cancel_count = 0;
649 pkt.u.response.stub_and_verifier.data = stub.data;
650 pkt.u.response.stub_and_verifier.length = length;
652 if (!dcesrv_auth_response(call, &rep->data, &pkt)) {
653 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
656 dcerpc_set_frag_length(&rep->data, rep->data.length);
658 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
661 stub.length -= length;
662 } while (stub.length != 0);
664 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
671 work out if we have a full packet yet
673 static BOOL dce_full_packet(const DATA_BLOB *data)
675 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
678 if (dcerpc_get_frag_length(data) > data->length) {
685 we might have consumed only part of our input - advance past that part
687 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32 offset)
691 if (dce_conn->partial_input.length == offset) {
692 data_blob_free(&dce_conn->partial_input);
696 blob = dce_conn->partial_input;
697 dce_conn->partial_input = data_blob(blob.data + offset,
698 blob.length - offset);
699 data_blob_free(&blob);
703 process some input to a dcerpc endpoint server.
705 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
707 struct ndr_pull *ndr;
710 struct dcesrv_call_state *call;
713 mem_ctx = talloc_init("dcesrv_input");
715 return NT_STATUS_NO_MEMORY;
717 call = talloc_p(mem_ctx, struct dcesrv_call_state);
719 talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
720 talloc_destroy(mem_ctx);
721 return NT_STATUS_NO_MEMORY;
723 call->mem_ctx = mem_ctx;
724 call->conn = dce_conn;
725 call->replies = NULL;
727 blob = dce_conn->partial_input;
728 blob.length = dcerpc_get_frag_length(&blob);
730 ndr = ndr_pull_init_blob(&blob, mem_ctx);
732 talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
733 talloc_destroy(mem_ctx);
734 return NT_STATUS_NO_MEMORY;
737 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
738 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
741 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
742 if (!NT_STATUS_IS_OK(status)) {
743 talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
744 talloc_destroy(mem_ctx);
748 dce_partial_advance(dce_conn, blob.length);
750 /* we have to check the signing here, before combining the
752 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
753 !dcesrv_auth_request(call)) {
754 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
757 /* see if this is a continued packet */
758 if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
759 struct dcesrv_call_state *call2 = call;
762 /* we only allow fragmented requests, no other packet types */
763 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
764 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
767 /* this is a continuation of an existing call - find the call then
768 tack it on the end */
769 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
771 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
774 if (call->pkt.ptype != call2->pkt.ptype) {
775 /* trying to play silly buggers are we? */
776 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
779 alloc_size = call->pkt.u.request.stub_and_verifier.length +
780 call2->pkt.u.request.stub_and_verifier.length;
781 if (call->pkt.u.request.alloc_hint > alloc_size) {
782 alloc_size = call->pkt.u.request.alloc_hint;
785 call->pkt.u.request.stub_and_verifier.data =
786 talloc_realloc(call->mem_ctx,
787 call->pkt.u.request.stub_and_verifier.data, alloc_size);
788 if (!call->pkt.u.request.stub_and_verifier.data) {
789 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
791 memcpy(call->pkt.u.request.stub_and_verifier.data +
792 call->pkt.u.request.stub_and_verifier.length,
793 call2->pkt.u.request.stub_and_verifier.data,
794 call2->pkt.u.request.stub_and_verifier.length);
795 call->pkt.u.request.stub_and_verifier.length +=
796 call2->pkt.u.request.stub_and_verifier.length;
798 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
801 /* this may not be the last pdu in the chain - if its isn't then
802 just put it on the call_list and wait for the rest */
803 if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
804 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
808 switch (call->pkt.ptype) {
809 case DCERPC_PKT_BIND:
810 status = dcesrv_bind(call);
812 case DCERPC_PKT_AUTH3:
813 status = dcesrv_auth3(call);
815 case DCERPC_PKT_REQUEST:
816 status = dcesrv_request(call);
819 status = NT_STATUS_INVALID_PARAMETER;
823 /* if we are going to be sending a reply then add
824 it to the list of pending calls. We add it to the end to keep the call
825 list in the order we will answer */
826 if (!NT_STATUS_IS_OK(status)) {
827 talloc_destroy(mem_ctx);
835 provide some input to a dcerpc endpoint server. This passes data
836 from a dcerpc client into the server
838 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
842 /* handle the very common case that the input contains a full packet and there
843 is no partial packet pending. In this case we can avoid a copy of the
845 if (dce_conn->partial_input.length == 0) {
846 dce_conn->partial_input = *data;
847 /* make sure that dce_partial_advance doesn't free this data */
848 dce_conn->partial_input.free = NULL;
849 while (dce_full_packet(&dce_conn->partial_input)) {
850 status = dcesrv_input_process(dce_conn);
851 if (!NT_STATUS_IS_OK(status)) {
855 if (dce_conn->partial_input.length) {
856 /* there was some data left over. We have to copy this
857 as the caller may free the data */
858 dce_conn->partial_input =
859 data_blob(dce_conn->partial_input.data,
860 dce_conn->partial_input.length);
861 if (!dce_conn->partial_input.data) {
862 return NT_STATUS_NO_MEMORY;
868 dce_conn->partial_input.data = Realloc(dce_conn->partial_input.data,
869 dce_conn->partial_input.length + data->length);
870 if (!dce_conn->partial_input.data) {
871 return NT_STATUS_NO_MEMORY;
873 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
874 data->data, data->length);
875 dce_conn->partial_input.length += data->length;
877 while (dce_full_packet(&dce_conn->partial_input)) {
878 status = dcesrv_input_process(dce_conn);
879 if (!NT_STATUS_IS_OK(status)) {
888 retrieve some output from a dcerpc server
889 The caller supplies a function that will be called to do the
892 The first argument to write_fn() will be 'private', the second will
893 be a pointer to a buffer containing the data to be sent and the 3rd
894 will be the number of bytes to be sent.
896 write_fn() should return the number of bytes successfully written.
898 NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
900 ssize_t (*write_fn)(void *, const void *, size_t))
902 struct dcesrv_call_state *call;
903 struct dcesrv_call_reply *rep;
906 call = dce_conn->call_list;
907 if (!call || !call->replies) {
908 return NT_STATUS_FOOBAR;
912 nwritten = write_fn(private, rep->data.data, rep->data.length);
913 if (nwritten == -1) {
914 /* TODO: hmm, how do we cope with this? destroy the
915 connection perhaps? */
916 return NT_STATUS_UNSUCCESSFUL;
919 rep->data.length -= nwritten;
920 rep->data.data += nwritten;
922 if (rep->data.length == 0) {
923 /* we're done with this section of the call */
924 DLIST_REMOVE(call->replies, rep);
927 if (call->replies == NULL) {
928 /* we're done with the whole call */
929 DLIST_REMOVE(dce_conn->call_list, call);
930 talloc_destroy(call->mem_ctx);
938 write_fn() for dcesrv_output_blob()
940 static ssize_t dcesrv_output_blob_write_fn(void *private, const void *buf, size_t count)
942 DATA_BLOB *blob = private;
943 if (count < blob->length) {
944 blob->length = count;
946 memcpy(blob->data, buf, blob->length);
951 a simple wrapper for dcesrv_output() for when we want to output
954 NTSTATUS dcesrv_output_blob(struct dcesrv_connection *dce_conn,
957 return dcesrv_output(dce_conn, blob, dcesrv_output_blob_write_fn);
961 initialise the dcerpc server context
963 NTSTATUS dcesrv_init_context(struct dcesrv_context *dce_ctx)
966 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
968 dce_ctx->mem_ctx = talloc_init("struct dcesrv_context");
969 if (!dce_ctx->mem_ctx) {
970 DEBUG(3,("dcesrv_init_context: talloc_init failed\n"));
971 return NT_STATUS_NO_MEMORY;
974 dce_ctx->endpoint_list = NULL;
976 if (!endpoint_servers) {
977 DEBUG(3,("dcesrv_init_context: no endpoint servers configured\n"));
981 for (i=0;endpoint_servers[i];i++) {
983 const struct dcesrv_endpoint_server *ep_server;
985 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
987 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
988 return NT_STATUS_UNSUCCESSFUL;
991 ret = ep_server->init_server(dce_ctx, ep_server);
992 if (!NT_STATUS_IS_OK(ret)) {
993 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1001 /* the list of currently registered DCERPC endpoint servers.
1004 struct dcesrv_endpoint_server *ep_server;
1005 } *ep_servers = NULL;
1006 static int num_ep_servers;
1009 register a DCERPC endpoint server.
1011 The 'name' can be later used by other backends to find the operations
1012 structure for this backend.
1014 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1016 static NTSTATUS decrpc_register_ep_server(void *_ep_server)
1018 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1020 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1021 /* its already registered! */
1022 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1024 return NT_STATUS_OBJECT_NAME_COLLISION;
1027 ep_servers = Realloc(ep_servers, sizeof(ep_servers[0]) * (num_ep_servers+1));
1029 smb_panic("out of memory in decrpc_register");
1032 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1033 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1037 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1040 return NT_STATUS_OK;
1044 return the operations structure for a named backend of the specified type
1046 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1050 for (i=0;i<num_ep_servers;i++) {
1051 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1052 return ep_servers[i].ep_server;
1060 return the DCERPC module version, and the size of some critical types
1061 This can be used by endpoint server modules to either detect compilation errors, or provide
1062 multiple implementations for different smbd compilation options in one module
1064 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1066 static const struct dcesrv_critical_sizes critical_sizes = {
1067 DCERPC_MODULE_VERSION,
1068 sizeof(struct dcesrv_context),
1069 sizeof(struct dcesrv_endpoint),
1070 sizeof(struct dcesrv_endpoint_server),
1071 sizeof(struct dcesrv_ep_description),
1072 sizeof(struct dcesrv_interface),
1073 sizeof(struct dcesrv_if_list),
1074 sizeof(struct dcesrv_connection),
1075 sizeof(struct dcesrv_call_state),
1076 sizeof(struct dcesrv_auth),
1077 sizeof(struct dcesrv_handle)
1080 return &critical_sizes;
1084 initialise the DCERPC subsystem
1086 BOOL dcesrv_init(void)
1090 status = register_subsystem("dcerpc", decrpc_register_ep_server);
1091 if (!NT_STATUS_IS_OK(status)) {
1095 /* FIXME: Perhaps panic if a basic endpoint server, such as EPMAPER, fails to initialise? */
1098 DEBUG(3,("DCERPC subsystem version %d initialised\n", DCERPC_MODULE_VERSION));