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 (strcasecmp(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_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_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.auth_info = NULL;
272 (*p)->auth_state.crypto_ctx.private_data = NULL;
273 (*p)->auth_state.crypto_ctx.ops = NULL;
274 (*p)->auth_state.session_info = NULL;
280 search and connect to a dcerpc endpoint
282 NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
283 const struct dcesrv_ep_description *ep_description,
284 struct auth_session_info *session_info,
285 struct dcesrv_connection **dce_conn_p)
288 const struct dcesrv_endpoint *ep;
290 /* make sure this endpoint exists */
291 ep = find_endpoint(dce_ctx, ep_description);
293 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
296 status = dcesrv_endpoint_connect(dce_ctx, ep, dce_conn_p);
297 if (!NT_STATUS_IS_OK(status)) {
301 (*dce_conn_p)->auth_state.session_info = session_info;
303 /* TODO: check security descriptor of the endpoint here
304 * if it's a smb named pipe
305 * if it's failed free dce_conn_p
313 disconnect a link to an endpoint
315 void dcesrv_endpoint_disconnect(struct dcesrv_connection *p)
318 p->iface->unbind(p, p->iface);
321 /* destroy any handles */
323 dcesrv_handle_destroy(p, p->handles);
326 if (p->auth_state.crypto_ctx.ops) {
327 p->auth_state.crypto_ctx.ops->end(&p->auth_state);
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_t 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_t 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_t if_version, transfer_syntax_version;
430 struct dcerpc_packet pkt;
431 struct dcesrv_call_reply *rep;
433 uint32_t 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;
561 uint32_t total_length;
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 dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN,
592 &call->pkt.u.request.stub_and_verifier);
593 return dcesrv_fault(call, DCERPC_FAULT_NDR);
596 call->fault_code = 0;
598 /* call the dispatch function */
599 status = call->conn->iface->dispatch(call, call->mem_ctx, r);
600 if (!NT_STATUS_IS_OK(status)) {
601 dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN,
602 &call->pkt.u.request.stub_and_verifier);
603 return dcesrv_fault(call, call->fault_code);
606 /* form the reply NDR */
607 push = ndr_push_init_ctx(call->mem_ctx);
609 return NT_STATUS_NO_MEMORY;
612 if (lp_rpc_big_endian()) {
613 push->flags |= LIBNDR_FLAG_BIGENDIAN;
616 status = call->conn->iface->ndr->calls[opnum].ndr_push(push, NDR_OUT, r);
617 if (!NT_STATUS_IS_OK(status)) {
618 return dcesrv_fault(call, DCERPC_FAULT_NDR);
621 stub = ndr_push_blob(push);
623 total_length = stub.length;
627 struct dcesrv_call_reply *rep;
628 struct dcerpc_packet pkt;
630 rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
632 return NT_STATUS_NO_MEMORY;
635 length = stub.length;
636 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
637 /* the 32 is to cope with signing data */
638 length = call->conn->cli_max_recv_frag -
639 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
642 /* form the dcerpc response packet */
643 dcesrv_init_hdr(&pkt);
645 pkt.call_id = call->pkt.call_id;
646 pkt.ptype = DCERPC_PKT_RESPONSE;
648 if (stub.length == total_length) {
649 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
651 if (length == stub.length) {
652 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
654 pkt.u.response.alloc_hint = stub.length;
655 pkt.u.response.context_id = call->pkt.u.request.context_id;
656 pkt.u.response.cancel_count = 0;
657 pkt.u.response.stub_and_verifier.data = stub.data;
658 pkt.u.response.stub_and_verifier.length = length;
660 if (!dcesrv_auth_response(call, &rep->data, &pkt)) {
661 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
664 dcerpc_set_frag_length(&rep->data, rep->data.length);
666 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
669 stub.length -= length;
670 } while (stub.length != 0);
672 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
679 work out if we have a full packet yet
681 static BOOL dce_full_packet(const DATA_BLOB *data)
683 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
686 if (dcerpc_get_frag_length(data) > data->length) {
693 we might have consumed only part of our input - advance past that part
695 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
699 if (dce_conn->partial_input.length == offset) {
700 data_blob_free(&dce_conn->partial_input);
704 blob = dce_conn->partial_input;
705 dce_conn->partial_input = data_blob(blob.data + offset,
706 blob.length - offset);
707 data_blob_free(&blob);
711 process some input to a dcerpc endpoint server.
713 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
715 struct ndr_pull *ndr;
718 struct dcesrv_call_state *call;
721 mem_ctx = talloc_init("dcesrv_input");
723 return NT_STATUS_NO_MEMORY;
725 call = talloc_p(mem_ctx, struct dcesrv_call_state);
727 talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
728 talloc_destroy(mem_ctx);
729 return NT_STATUS_NO_MEMORY;
731 call->mem_ctx = mem_ctx;
732 call->conn = dce_conn;
733 call->replies = NULL;
735 blob = dce_conn->partial_input;
736 blob.length = dcerpc_get_frag_length(&blob);
738 ndr = ndr_pull_init_blob(&blob, mem_ctx);
740 talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
741 talloc_destroy(mem_ctx);
742 return NT_STATUS_NO_MEMORY;
745 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
746 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
749 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
750 if (!NT_STATUS_IS_OK(status)) {
751 talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
752 talloc_destroy(mem_ctx);
756 dce_partial_advance(dce_conn, blob.length);
758 /* we have to check the signing here, before combining the
760 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
761 !dcesrv_auth_request(call)) {
762 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
765 /* see if this is a continued packet */
766 if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
767 struct dcesrv_call_state *call2 = call;
770 /* we only allow fragmented requests, no other packet types */
771 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
772 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
775 /* this is a continuation of an existing call - find the call then
776 tack it on the end */
777 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
779 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
782 if (call->pkt.ptype != call2->pkt.ptype) {
783 /* trying to play silly buggers are we? */
784 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
787 alloc_size = call->pkt.u.request.stub_and_verifier.length +
788 call2->pkt.u.request.stub_and_verifier.length;
789 if (call->pkt.u.request.alloc_hint > alloc_size) {
790 alloc_size = call->pkt.u.request.alloc_hint;
793 call->pkt.u.request.stub_and_verifier.data =
794 talloc_realloc(call->mem_ctx,
795 call->pkt.u.request.stub_and_verifier.data, alloc_size);
796 if (!call->pkt.u.request.stub_and_verifier.data) {
797 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
799 memcpy(call->pkt.u.request.stub_and_verifier.data +
800 call->pkt.u.request.stub_and_verifier.length,
801 call2->pkt.u.request.stub_and_verifier.data,
802 call2->pkt.u.request.stub_and_verifier.length);
803 call->pkt.u.request.stub_and_verifier.length +=
804 call2->pkt.u.request.stub_and_verifier.length;
806 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
809 /* this may not be the last pdu in the chain - if its isn't then
810 just put it on the call_list and wait for the rest */
811 if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
812 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
816 switch (call->pkt.ptype) {
817 case DCERPC_PKT_BIND:
818 status = dcesrv_bind(call);
820 case DCERPC_PKT_AUTH3:
821 status = dcesrv_auth3(call);
823 case DCERPC_PKT_REQUEST:
824 status = dcesrv_request(call);
827 status = NT_STATUS_INVALID_PARAMETER;
831 /* if we are going to be sending a reply then add
832 it to the list of pending calls. We add it to the end to keep the call
833 list in the order we will answer */
834 if (!NT_STATUS_IS_OK(status)) {
835 talloc_destroy(mem_ctx);
843 provide some input to a dcerpc endpoint server. This passes data
844 from a dcerpc client into the server
846 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
850 /* handle the very common case that the input contains a full packet and there
851 is no partial packet pending. In this case we can avoid a copy of the
853 if (dce_conn->partial_input.length == 0) {
854 dce_conn->partial_input = *data;
855 /* make sure that dce_partial_advance doesn't free this data */
856 dce_conn->partial_input.free = NULL;
857 while (dce_full_packet(&dce_conn->partial_input)) {
858 status = dcesrv_input_process(dce_conn);
859 if (!NT_STATUS_IS_OK(status)) {
863 if (dce_conn->partial_input.length) {
864 /* there was some data left over. We have to copy this
865 as the caller may free the data */
866 dce_conn->partial_input =
867 data_blob(dce_conn->partial_input.data,
868 dce_conn->partial_input.length);
869 if (!dce_conn->partial_input.data) {
870 return NT_STATUS_NO_MEMORY;
876 dce_conn->partial_input.data = Realloc(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 *, const void *, size_t))
913 struct dcesrv_call_state *call;
914 struct dcesrv_call_reply *rep;
916 NTSTATUS status = NT_STATUS_OK;
918 call = dce_conn->call_list;
919 if (!call || !call->replies) {
920 return NT_STATUS_FOOBAR;
924 nwritten = write_fn(private, rep->data.data, rep->data.length);
925 if (nwritten == -1) {
926 /* TODO: hmm, how do we cope with this? destroy the
927 connection perhaps? */
928 return NT_STATUS_UNSUCCESSFUL;
931 rep->data.length -= nwritten;
932 rep->data.data += nwritten;
934 if (rep->data.length == 0) {
935 /* we're done with this section of the call */
936 DLIST_REMOVE(call->replies, rep);
938 status = STATUS_BUFFER_OVERFLOW;
941 if (call->replies == NULL) {
942 /* we're done with the whole call */
943 DLIST_REMOVE(dce_conn->call_list, call);
944 talloc_destroy(call->mem_ctx);
952 write_fn() for dcesrv_output_blob()
954 static ssize_t dcesrv_output_blob_write_fn(void *private, const void *buf, size_t count)
956 DATA_BLOB *blob = private;
957 if (count < blob->length) {
958 blob->length = count;
960 memcpy(blob->data, buf, blob->length);
965 a simple wrapper for dcesrv_output() for when we want to output
968 NTSTATUS dcesrv_output_blob(struct dcesrv_connection *dce_conn,
971 return dcesrv_output(dce_conn, blob, dcesrv_output_blob_write_fn);
975 initialise the dcerpc server context
977 NTSTATUS dcesrv_init_context(struct dcesrv_context *dce_ctx)
980 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
982 dce_ctx->mem_ctx = talloc_init("struct dcesrv_context");
983 if (!dce_ctx->mem_ctx) {
984 DEBUG(3,("dcesrv_init_context: talloc_init failed\n"));
985 return NT_STATUS_NO_MEMORY;
988 dce_ctx->endpoint_list = NULL;
990 if (!endpoint_servers) {
991 DEBUG(3,("dcesrv_init_context: no endpoint servers configured\n"));
995 for (i=0;endpoint_servers[i];i++) {
997 const struct dcesrv_endpoint_server *ep_server;
999 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1001 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1002 return NT_STATUS_UNSUCCESSFUL;
1005 ret = ep_server->init_server(dce_ctx, ep_server);
1006 if (!NT_STATUS_IS_OK(ret)) {
1007 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1012 return NT_STATUS_OK;
1015 /* the list of currently registered DCERPC endpoint servers.
1018 struct dcesrv_endpoint_server *ep_server;
1019 } *ep_servers = NULL;
1020 static int num_ep_servers;
1023 register a DCERPC endpoint server.
1025 The 'name' can be later used by other backends to find the operations
1026 structure for this backend.
1028 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1030 static NTSTATUS decrpc_register_ep_server(void *_ep_server)
1032 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1034 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1035 /* its already registered! */
1036 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1038 return NT_STATUS_OBJECT_NAME_COLLISION;
1041 ep_servers = Realloc(ep_servers, sizeof(ep_servers[0]) * (num_ep_servers+1));
1043 smb_panic("out of memory in decrpc_register");
1046 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1047 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1051 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1054 return NT_STATUS_OK;
1058 return the operations structure for a named backend of the specified type
1060 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1064 for (i=0;i<num_ep_servers;i++) {
1065 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1066 return ep_servers[i].ep_server;
1074 return the DCERPC module version, and the size of some critical types
1075 This can be used by endpoint server modules to either detect compilation errors, or provide
1076 multiple implementations for different smbd compilation options in one module
1078 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1080 static const struct dcesrv_critical_sizes critical_sizes = {
1081 DCERPC_MODULE_VERSION,
1082 sizeof(struct dcesrv_context),
1083 sizeof(struct dcesrv_endpoint),
1084 sizeof(struct dcesrv_endpoint_server),
1085 sizeof(struct dcesrv_ep_description),
1086 sizeof(struct dcesrv_interface),
1087 sizeof(struct dcesrv_if_list),
1088 sizeof(struct dcesrv_connection),
1089 sizeof(struct dcesrv_call_state),
1090 sizeof(struct dcesrv_auth),
1091 sizeof(struct dcesrv_handle)
1094 return &critical_sizes;
1098 initialise the DCERPC subsystem
1100 BOOL dcesrv_init(void)
1104 status = register_subsystem("dcerpc", decrpc_register_ep_server);
1105 if (!NT_STATUS_IS_OK(status)) {
1109 /* FIXME: Perhaps panic if a basic endpoint server, such as EPMAPER, fails to initialise? */
1112 DEBUG(3,("DCERPC subsystem version %d initialised\n", DCERPC_MODULE_VERSION));