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;
273 (*p)->session_key = data_blob(NULL, 0);
279 set the transport level session key
281 void dcesrv_set_session_key(struct dcesrv_connection *p, DATA_BLOB key)
283 p->session_key = data_blob_talloc(p->mem_ctx, key.data, key.length);
287 search and connect to a dcerpc endpoint
289 NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
290 const struct dcesrv_ep_description *ep_description,
291 struct dcesrv_connection **dce_conn_p)
294 const struct dcesrv_endpoint *ep;
296 /* make sure this endpoint exists */
297 ep = find_endpoint(dce_ctx, ep_description);
299 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
302 status = dcesrv_endpoint_connect(dce_ctx, ep, dce_conn_p);
303 if (!NT_STATUS_IS_OK(status)) {
307 /* TODO: check security descriptor of the endpoint here
308 * if it's a smb named pipe
309 * if it's failed free dce_conn_p
317 disconnect a link to an endpoint
319 void dcesrv_endpoint_disconnect(struct dcesrv_connection *p)
322 p->iface->unbind(p, p->iface);
325 /* destroy any handles */
327 dcesrv_handle_destroy(p, p->handles);
330 talloc_destroy(p->mem_ctx);
333 static void dcesrv_init_hdr(struct dcerpc_packet *pkt)
336 pkt->rpc_vers_minor = 0;
337 if (lp_rpc_big_endian()) {
340 pkt->drep[0] = DCERPC_DREP_LE;
348 return a dcerpc fault
350 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32 fault_code)
352 struct dcerpc_packet pkt;
353 struct dcesrv_call_reply *rep;
356 /* setup a bind_ack */
357 dcesrv_init_hdr(&pkt);
359 pkt.call_id = call->pkt.call_id;
360 pkt.ptype = DCERPC_PKT_FAULT;
361 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
362 pkt.u.fault.alloc_hint = 0;
363 pkt.u.fault.context_id = 0;
364 pkt.u.fault.cancel_count = 0;
365 pkt.u.fault.status = fault_code;
367 rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
369 return NT_STATUS_NO_MEMORY;
372 status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt, NULL);
373 if (!NT_STATUS_IS_OK(status)) {
377 dcerpc_set_frag_length(&rep->data, rep->data.length);
379 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
380 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
387 return a dcerpc bind_nak
389 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32 reason)
391 struct dcerpc_packet pkt;
392 struct dcesrv_call_reply *rep;
395 /* setup a bind_nak */
396 dcesrv_init_hdr(&pkt);
398 pkt.call_id = call->pkt.call_id;
399 pkt.ptype = DCERPC_PKT_BIND_NAK;
400 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
401 pkt.u.bind_nak.reject_reason = reason;
402 pkt.u.bind_nak.num_versions = 0;
404 rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
406 return NT_STATUS_NO_MEMORY;
409 status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt, NULL);
410 if (!NT_STATUS_IS_OK(status)) {
414 dcerpc_set_frag_length(&rep->data, rep->data.length);
416 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
417 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
424 handle a bind request
426 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
428 const char *uuid, *transfer_syntax;
429 uint32 if_version, transfer_syntax_version;
430 struct dcerpc_packet pkt;
431 struct dcesrv_call_reply *rep;
433 uint32 result=0, reason=0;
435 if (call->pkt.u.bind.num_contexts != 1 ||
436 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
437 return dcesrv_bind_nak(call, 0);
440 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
441 uuid = GUID_string(call->mem_ctx, &call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid);
443 return dcesrv_bind_nak(call, 0);
446 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
447 transfer_syntax = GUID_string(call->mem_ctx,
448 &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid);
449 if (!transfer_syntax ||
450 strcasecmp(NDR_GUID, transfer_syntax) != 0 ||
451 NDR_GUID_VERSION != transfer_syntax_version) {
452 /* we only do NDR encoded dcerpc */
453 return dcesrv_bind_nak(call, 0);
456 call->conn->iface = find_interface_by_uuid(call->conn->endpoint, uuid, if_version);
457 if (!call->conn->iface) {
458 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
459 /* we don't know about that interface */
460 result = DCERPC_BIND_PROVIDER_REJECT;
461 reason = DCERPC_BIND_REASON_ASYNTAX;
464 if (call->conn->cli_max_recv_frag == 0) {
465 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
468 /* handle any authentication that is being requested */
469 if (!dcesrv_auth_bind(call)) {
470 /* TODO: work out the right reject code */
471 return dcesrv_bind_nak(call, 0);
474 /* setup a bind_ack */
475 dcesrv_init_hdr(&pkt);
477 pkt.call_id = call->pkt.call_id;
478 pkt.ptype = DCERPC_PKT_BIND_ACK;
479 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
480 pkt.u.bind_ack.max_xmit_frag = 0x2000;
481 pkt.u.bind_ack.max_recv_frag = 0x2000;
482 pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
483 if (call->conn->iface && call->conn->iface->ndr) {
484 pkt.u.bind_ack.secondary_address = talloc_asprintf(call->mem_ctx, "\\PIPE\\%s",
485 call->conn->iface->ndr->name);
487 pkt.u.bind_ack.secondary_address = "";
489 pkt.u.bind_ack.num_results = 1;
490 pkt.u.bind_ack.ctx_list = talloc_p(call->mem_ctx, struct dcerpc_ack_ctx);
491 if (!pkt.u.bind_ack.ctx_list) {
492 return NT_STATUS_NO_MEMORY;
494 pkt.u.bind_ack.ctx_list[0].result = result;
495 pkt.u.bind_ack.ctx_list[0].reason = reason;
496 GUID_from_string(NDR_GUID, &pkt.u.bind_ack.ctx_list[0].syntax.uuid);
497 pkt.u.bind_ack.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
498 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
500 if (!dcesrv_auth_bind_ack(call, &pkt)) {
501 return dcesrv_bind_nak(call, 0);
504 if (call->conn->iface) {
505 status = call->conn->iface->bind(call, call->conn->iface);
506 if (!NT_STATUS_IS_OK(status)) {
507 DEBUG(2,("Request for dcerpc interface %s/%d rejected\n", uuid, if_version));
512 rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
514 return NT_STATUS_NO_MEMORY;
517 status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt,
518 call->conn->auth_state.auth_info);
519 if (!NT_STATUS_IS_OK(status)) {
523 dcerpc_set_frag_length(&rep->data, rep->data.length);
525 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
526 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
533 handle a auth3 request
535 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
537 /* handle the auth3 in the auth code */
538 if (!dcesrv_auth_auth3(call)) {
539 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
542 talloc_destroy(call->mem_ctx);
544 /* we don't send a reply to a auth3 request, except by a
551 handle a dcerpc request packet
553 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
555 struct ndr_pull *pull;
556 struct ndr_push *push;
564 if (!call->conn->iface) {
565 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
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->fault_code = 0;
596 /* call the dispatch function */
597 status = call->conn->iface->dispatch(call, call->mem_ctx, r);
598 if (!NT_STATUS_IS_OK(status)) {
599 return dcesrv_fault(call, call->fault_code);
602 /* form the reply NDR */
603 push = ndr_push_init_ctx(call->mem_ctx);
605 return NT_STATUS_NO_MEMORY;
608 if (lp_rpc_big_endian()) {
609 push->flags |= LIBNDR_FLAG_BIGENDIAN;
612 status = call->conn->iface->ndr->calls[opnum].ndr_push(push, NDR_OUT, r);
613 if (!NT_STATUS_IS_OK(status)) {
614 return dcesrv_fault(call, DCERPC_FAULT_NDR);
617 stub = ndr_push_blob(push);
619 total_length = stub.length;
623 struct dcesrv_call_reply *rep;
624 struct dcerpc_packet pkt;
626 rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
628 return NT_STATUS_NO_MEMORY;
631 length = stub.length;
632 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
633 /* the 32 is to cope with signing data */
634 length = call->conn->cli_max_recv_frag -
635 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
638 /* form the dcerpc response packet */
639 dcesrv_init_hdr(&pkt);
641 pkt.call_id = call->pkt.call_id;
642 pkt.ptype = DCERPC_PKT_RESPONSE;
644 if (stub.length == total_length) {
645 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
647 if (length == stub.length) {
648 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
650 pkt.u.response.alloc_hint = stub.length;
651 pkt.u.response.context_id = call->pkt.u.request.context_id;
652 pkt.u.response.cancel_count = 0;
653 pkt.u.response.stub_and_verifier.data = stub.data;
654 pkt.u.response.stub_and_verifier.length = length;
656 if (!dcesrv_auth_response(call, &rep->data, &pkt)) {
657 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
660 dcerpc_set_frag_length(&rep->data, rep->data.length);
662 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
665 stub.length -= length;
666 } while (stub.length != 0);
668 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
675 work out if we have a full packet yet
677 static BOOL dce_full_packet(const DATA_BLOB *data)
679 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
682 if (dcerpc_get_frag_length(data) > data->length) {
689 we might have consumed only part of our input - advance past that part
691 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32 offset)
695 if (dce_conn->partial_input.length == offset) {
696 data_blob_free(&dce_conn->partial_input);
700 blob = dce_conn->partial_input;
701 dce_conn->partial_input = data_blob(blob.data + offset,
702 blob.length - offset);
703 data_blob_free(&blob);
707 process some input to a dcerpc endpoint server.
709 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
711 struct ndr_pull *ndr;
714 struct dcesrv_call_state *call;
717 mem_ctx = talloc_init("dcesrv_input");
719 return NT_STATUS_NO_MEMORY;
721 call = talloc_p(mem_ctx, struct dcesrv_call_state);
723 talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
724 talloc_destroy(mem_ctx);
725 return NT_STATUS_NO_MEMORY;
727 call->mem_ctx = mem_ctx;
728 call->conn = dce_conn;
729 call->replies = NULL;
731 blob = dce_conn->partial_input;
732 blob.length = dcerpc_get_frag_length(&blob);
734 ndr = ndr_pull_init_blob(&blob, mem_ctx);
736 talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
737 talloc_destroy(mem_ctx);
738 return NT_STATUS_NO_MEMORY;
741 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
742 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
745 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
746 if (!NT_STATUS_IS_OK(status)) {
747 talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
748 talloc_destroy(mem_ctx);
752 dce_partial_advance(dce_conn, blob.length);
754 /* we have to check the signing here, before combining the
756 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
757 !dcesrv_auth_request(call)) {
758 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
761 /* see if this is a continued packet */
762 if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
763 struct dcesrv_call_state *call2 = call;
766 /* we only allow fragmented requests, no other packet types */
767 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
768 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
771 /* this is a continuation of an existing call - find the call then
772 tack it on the end */
773 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
775 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
778 if (call->pkt.ptype != call2->pkt.ptype) {
779 /* trying to play silly buggers are we? */
780 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
783 alloc_size = call->pkt.u.request.stub_and_verifier.length +
784 call2->pkt.u.request.stub_and_verifier.length;
785 if (call->pkt.u.request.alloc_hint > alloc_size) {
786 alloc_size = call->pkt.u.request.alloc_hint;
789 call->pkt.u.request.stub_and_verifier.data =
790 talloc_realloc(call->mem_ctx,
791 call->pkt.u.request.stub_and_verifier.data, alloc_size);
792 if (!call->pkt.u.request.stub_and_verifier.data) {
793 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
795 memcpy(call->pkt.u.request.stub_and_verifier.data +
796 call->pkt.u.request.stub_and_verifier.length,
797 call2->pkt.u.request.stub_and_verifier.data,
798 call2->pkt.u.request.stub_and_verifier.length);
799 call->pkt.u.request.stub_and_verifier.length +=
800 call2->pkt.u.request.stub_and_verifier.length;
802 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
805 /* this may not be the last pdu in the chain - if its isn't then
806 just put it on the call_list and wait for the rest */
807 if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
808 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
812 switch (call->pkt.ptype) {
813 case DCERPC_PKT_BIND:
814 status = dcesrv_bind(call);
816 case DCERPC_PKT_AUTH3:
817 status = dcesrv_auth3(call);
819 case DCERPC_PKT_REQUEST:
820 status = dcesrv_request(call);
823 status = NT_STATUS_INVALID_PARAMETER;
827 /* if we are going to be sending a reply then add
828 it to the list of pending calls. We add it to the end to keep the call
829 list in the order we will answer */
830 if (!NT_STATUS_IS_OK(status)) {
831 talloc_destroy(mem_ctx);
839 provide some input to a dcerpc endpoint server. This passes data
840 from a dcerpc client into the server
842 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
846 /* handle the very common case that the input contains a full packet and there
847 is no partial packet pending. In this case we can avoid a copy of the
849 if (dce_conn->partial_input.length == 0) {
850 dce_conn->partial_input = *data;
851 /* make sure that dce_partial_advance doesn't free this data */
852 dce_conn->partial_input.free = NULL;
853 while (dce_full_packet(&dce_conn->partial_input)) {
854 status = dcesrv_input_process(dce_conn);
855 if (!NT_STATUS_IS_OK(status)) {
859 if (dce_conn->partial_input.length) {
860 /* there was some data left over. We have to copy this
861 as the caller may free the data */
862 dce_conn->partial_input =
863 data_blob(dce_conn->partial_input.data,
864 dce_conn->partial_input.length);
865 if (!dce_conn->partial_input.data) {
866 return NT_STATUS_NO_MEMORY;
872 dce_conn->partial_input.data = Realloc(dce_conn->partial_input.data,
873 dce_conn->partial_input.length + data->length);
874 if (!dce_conn->partial_input.data) {
875 return NT_STATUS_NO_MEMORY;
877 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
878 data->data, data->length);
879 dce_conn->partial_input.length += data->length;
881 while (dce_full_packet(&dce_conn->partial_input)) {
882 status = dcesrv_input_process(dce_conn);
883 if (!NT_STATUS_IS_OK(status)) {
892 retrieve some output from a dcerpc server
893 The caller supplies a function that will be called to do the
896 The first argument to write_fn() will be 'private', the second will
897 be a pointer to a buffer containing the data to be sent and the 3rd
898 will be the number of bytes to be sent.
900 write_fn() should return the number of bytes successfully written.
902 NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
904 ssize_t (*write_fn)(void *, const void *, size_t))
906 struct dcesrv_call_state *call;
907 struct dcesrv_call_reply *rep;
910 call = dce_conn->call_list;
911 if (!call || !call->replies) {
912 return NT_STATUS_FOOBAR;
916 nwritten = write_fn(private, rep->data.data, rep->data.length);
917 if (nwritten == -1) {
918 /* TODO: hmm, how do we cope with this? destroy the
919 connection perhaps? */
920 return NT_STATUS_UNSUCCESSFUL;
923 rep->data.length -= nwritten;
924 rep->data.data += nwritten;
926 if (rep->data.length == 0) {
927 /* we're done with this section of the call */
928 DLIST_REMOVE(call->replies, rep);
931 if (call->replies == NULL) {
932 /* we're done with the whole call */
933 DLIST_REMOVE(dce_conn->call_list, call);
934 talloc_destroy(call->mem_ctx);
942 write_fn() for dcesrv_output_blob()
944 static ssize_t dcesrv_output_blob_write_fn(void *private, const void *buf, size_t count)
946 DATA_BLOB *blob = private;
947 if (count < blob->length) {
948 blob->length = count;
950 memcpy(blob->data, buf, blob->length);
955 a simple wrapper for dcesrv_output() for when we want to output
958 NTSTATUS dcesrv_output_blob(struct dcesrv_connection *dce_conn,
961 return dcesrv_output(dce_conn, blob, dcesrv_output_blob_write_fn);
965 initialise the dcerpc server context
967 NTSTATUS dcesrv_init_context(struct dcesrv_context *dce_ctx)
970 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
972 dce_ctx->mem_ctx = talloc_init("struct dcesrv_context");
973 if (!dce_ctx->mem_ctx) {
974 DEBUG(3,("dcesrv_init_context: talloc_init failed\n"));
975 return NT_STATUS_NO_MEMORY;
978 dce_ctx->endpoint_list = NULL;
980 if (!endpoint_servers) {
981 DEBUG(3,("dcesrv_init_context: no endpoint servers configured\n"));
985 for (i=0;endpoint_servers[i];i++) {
987 const struct dcesrv_endpoint_server *ep_server;
989 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
991 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
992 return NT_STATUS_UNSUCCESSFUL;
995 ret = ep_server->init_server(dce_ctx, ep_server);
996 if (!NT_STATUS_IS_OK(ret)) {
997 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1002 return NT_STATUS_OK;
1005 /* the list of currently registered DCERPC endpoint servers.
1008 struct dcesrv_endpoint_server *ep_server;
1009 } *ep_servers = NULL;
1010 static int num_ep_servers;
1013 register a DCERPC endpoint server.
1015 The 'name' can be later used by other backends to find the operations
1016 structure for this backend.
1018 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1020 static NTSTATUS decrpc_register_ep_server(void *_ep_server)
1022 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1024 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1025 /* its already registered! */
1026 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1028 return NT_STATUS_OBJECT_NAME_COLLISION;
1031 ep_servers = Realloc(ep_servers, sizeof(ep_servers[0]) * (num_ep_servers+1));
1033 smb_panic("out of memory in decrpc_register");
1036 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1037 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1041 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1044 return NT_STATUS_OK;
1048 return the operations structure for a named backend of the specified type
1050 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1054 for (i=0;i<num_ep_servers;i++) {
1055 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1056 return ep_servers[i].ep_server;
1064 return the DCERPC module version, and the size of some critical types
1065 This can be used by endpoint server modules to either detect compilation errors, or provide
1066 multiple implementations for different smbd compilation options in one module
1068 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1070 static const struct dcesrv_critical_sizes critical_sizes = {
1071 DCERPC_MODULE_VERSION,
1072 sizeof(struct dcesrv_context),
1073 sizeof(struct dcesrv_endpoint),
1074 sizeof(struct dcesrv_endpoint_server),
1075 sizeof(struct dcesrv_ep_description),
1076 sizeof(struct dcesrv_interface),
1077 sizeof(struct dcesrv_if_list),
1078 sizeof(struct dcesrv_connection),
1079 sizeof(struct dcesrv_call_state),
1080 sizeof(struct dcesrv_auth),
1081 sizeof(struct dcesrv_handle)
1084 return &critical_sizes;
1088 initialise the DCERPC subsystem
1090 BOOL dcesrv_init(void)
1094 status = register_subsystem("dcerpc", decrpc_register_ep_server);
1095 if (!NT_STATUS_IS_OK(status)) {
1099 /* FIXME: Perhaps panic if a basic endpoint server, such as EPMAPER, fails to initialise? */
1102 DEBUG(3,("DCERPC subsystem version %d initialised\n", DCERPC_MODULE_VERSION));