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.gensec_security = NULL;
273 (*p)->auth_state.session_info = NULL;
279 search and connect to a dcerpc endpoint
281 NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
282 const struct dcesrv_ep_description *ep_description,
283 struct auth_session_info *session_info,
284 struct dcesrv_connection **dce_conn_p)
287 const struct dcesrv_endpoint *ep;
289 /* make sure this endpoint exists */
290 ep = find_endpoint(dce_ctx, ep_description);
292 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
295 status = dcesrv_endpoint_connect(dce_ctx, ep, dce_conn_p);
296 if (!NT_STATUS_IS_OK(status)) {
300 session_info->refcount++;
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.gensec_security) {
327 gensec_end(&p->auth_state.gensec_security);
330 if (p->auth_state.session_info) {
331 free_session_info(&p->auth_state.session_info);
334 talloc_destroy(p->mem_ctx);
337 static void dcesrv_init_hdr(struct dcerpc_packet *pkt)
340 pkt->rpc_vers_minor = 0;
341 if (lp_rpc_big_endian()) {
344 pkt->drep[0] = DCERPC_DREP_LE;
352 return a dcerpc fault
354 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
356 struct dcerpc_packet pkt;
357 struct dcesrv_call_reply *rep;
360 /* setup a bind_ack */
361 dcesrv_init_hdr(&pkt);
363 pkt.call_id = call->pkt.call_id;
364 pkt.ptype = DCERPC_PKT_FAULT;
365 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
366 pkt.u.fault.alloc_hint = 0;
367 pkt.u.fault.context_id = 0;
368 pkt.u.fault.cancel_count = 0;
369 pkt.u.fault.status = fault_code;
371 rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
373 return NT_STATUS_NO_MEMORY;
376 status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt, NULL);
377 if (!NT_STATUS_IS_OK(status)) {
381 dcerpc_set_frag_length(&rep->data, rep->data.length);
383 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
384 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
391 return a dcerpc bind_nak
393 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
395 struct dcerpc_packet pkt;
396 struct dcesrv_call_reply *rep;
399 /* setup a bind_nak */
400 dcesrv_init_hdr(&pkt);
402 pkt.call_id = call->pkt.call_id;
403 pkt.ptype = DCERPC_PKT_BIND_NAK;
404 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
405 pkt.u.bind_nak.reject_reason = reason;
406 pkt.u.bind_nak.num_versions = 0;
408 rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
410 return NT_STATUS_NO_MEMORY;
413 status = dcerpc_push_auth(&rep->data, call->mem_ctx, &pkt, NULL);
414 if (!NT_STATUS_IS_OK(status)) {
418 dcerpc_set_frag_length(&rep->data, rep->data.length);
420 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
421 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
428 handle a bind request
430 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
432 const char *uuid, *transfer_syntax;
433 uint32_t if_version, transfer_syntax_version;
434 struct dcerpc_packet pkt;
435 struct dcesrv_call_reply *rep;
437 uint32_t result=0, reason=0;
439 if (call->pkt.u.bind.num_contexts != 1 ||
440 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
441 return dcesrv_bind_nak(call, 0);
444 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
445 uuid = GUID_string(call->mem_ctx, &call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid);
447 return dcesrv_bind_nak(call, 0);
450 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
451 transfer_syntax = GUID_string(call->mem_ctx,
452 &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid);
453 if (!transfer_syntax ||
454 strcasecmp(NDR_GUID, transfer_syntax) != 0 ||
455 NDR_GUID_VERSION != transfer_syntax_version) {
456 /* we only do NDR encoded dcerpc */
457 return dcesrv_bind_nak(call, 0);
460 call->conn->iface = find_interface_by_uuid(call->conn->endpoint, uuid, if_version);
461 if (!call->conn->iface) {
462 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
463 /* we don't know about that interface */
464 result = DCERPC_BIND_PROVIDER_REJECT;
465 reason = DCERPC_BIND_REASON_ASYNTAX;
468 if (call->conn->cli_max_recv_frag == 0) {
469 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
472 /* handle any authentication that is being requested */
473 if (!dcesrv_auth_bind(call)) {
474 /* TODO: work out the right reject code */
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;
565 uint32_t total_length;
568 if (!call->conn->iface) {
569 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
572 opnum = call->pkt.u.request.opnum;
574 if (opnum >= call->conn->iface->ndr->num_calls) {
575 return dcesrv_fault(call, DCERPC_FAULT_OP_RNG_ERROR);
578 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call->mem_ctx);
580 return NT_STATUS_NO_MEMORY;
583 r = talloc(call->mem_ctx, call->conn->iface->ndr->calls[opnum].struct_size);
585 return NT_STATUS_NO_MEMORY;
588 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
589 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
592 /* unravel the NDR for the packet */
593 status = call->conn->iface->ndr->calls[opnum].ndr_pull(pull, NDR_IN, r);
594 if (!NT_STATUS_IS_OK(status)) {
595 dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN,
596 &call->pkt.u.request.stub_and_verifier);
597 return dcesrv_fault(call, DCERPC_FAULT_NDR);
600 call->fault_code = 0;
602 /* call the dispatch function */
603 status = call->conn->iface->dispatch(call, call->mem_ctx, r);
604 if (!NT_STATUS_IS_OK(status)) {
605 dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN,
606 &call->pkt.u.request.stub_and_verifier);
607 return dcesrv_fault(call, call->fault_code);
610 /* form the reply NDR */
611 push = ndr_push_init_ctx(call->mem_ctx);
613 return NT_STATUS_NO_MEMORY;
616 if (lp_rpc_big_endian()) {
617 push->flags |= LIBNDR_FLAG_BIGENDIAN;
620 status = call->conn->iface->ndr->calls[opnum].ndr_push(push, NDR_OUT, r);
621 if (!NT_STATUS_IS_OK(status)) {
622 return dcesrv_fault(call, DCERPC_FAULT_NDR);
625 stub = ndr_push_blob(push);
627 total_length = stub.length;
631 struct dcesrv_call_reply *rep;
632 struct dcerpc_packet pkt;
634 rep = talloc_p(call->mem_ctx, struct dcesrv_call_reply);
636 return NT_STATUS_NO_MEMORY;
639 length = stub.length;
640 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
641 /* the 32 is to cope with signing data */
642 length = call->conn->cli_max_recv_frag -
643 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
646 /* form the dcerpc response packet */
647 dcesrv_init_hdr(&pkt);
649 pkt.call_id = call->pkt.call_id;
650 pkt.ptype = DCERPC_PKT_RESPONSE;
652 if (stub.length == total_length) {
653 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
655 if (length == stub.length) {
656 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
658 pkt.u.response.alloc_hint = stub.length;
659 pkt.u.response.context_id = call->pkt.u.request.context_id;
660 pkt.u.response.cancel_count = 0;
661 pkt.u.response.stub_and_verifier.data = stub.data;
662 pkt.u.response.stub_and_verifier.length = length;
664 if (!dcesrv_auth_response(call, &rep->data, &pkt)) {
665 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
668 dcerpc_set_frag_length(&rep->data, rep->data.length);
670 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
673 stub.length -= length;
674 } while (stub.length != 0);
676 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
683 work out if we have a full packet yet
685 static BOOL dce_full_packet(const DATA_BLOB *data)
687 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
690 if (dcerpc_get_frag_length(data) > data->length) {
697 we might have consumed only part of our input - advance past that part
699 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
703 if (dce_conn->partial_input.length == offset) {
704 data_blob_free(&dce_conn->partial_input);
708 blob = dce_conn->partial_input;
709 dce_conn->partial_input = data_blob(blob.data + offset,
710 blob.length - offset);
711 data_blob_free(&blob);
715 process some input to a dcerpc endpoint server.
717 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
719 struct ndr_pull *ndr;
722 struct dcesrv_call_state *call;
725 mem_ctx = talloc_init("dcesrv_input");
727 return NT_STATUS_NO_MEMORY;
729 call = talloc_p(mem_ctx, struct dcesrv_call_state);
731 talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
732 talloc_destroy(mem_ctx);
733 return NT_STATUS_NO_MEMORY;
735 call->mem_ctx = mem_ctx;
736 call->conn = dce_conn;
737 call->replies = NULL;
739 blob = dce_conn->partial_input;
740 blob.length = dcerpc_get_frag_length(&blob);
742 ndr = ndr_pull_init_blob(&blob, mem_ctx);
744 talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
745 talloc_destroy(mem_ctx);
746 return NT_STATUS_NO_MEMORY;
749 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
750 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
753 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
754 if (!NT_STATUS_IS_OK(status)) {
755 talloc_free(dce_conn->mem_ctx, dce_conn->partial_input.data);
756 talloc_destroy(mem_ctx);
760 dce_partial_advance(dce_conn, blob.length);
762 /* we have to check the signing here, before combining the
764 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
765 !dcesrv_auth_request(call)) {
766 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
769 /* see if this is a continued packet */
770 if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
771 struct dcesrv_call_state *call2 = call;
774 /* we only allow fragmented requests, no other packet types */
775 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
776 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
779 /* this is a continuation of an existing call - find the call then
780 tack it on the end */
781 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
783 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
786 if (call->pkt.ptype != call2->pkt.ptype) {
787 /* trying to play silly buggers are we? */
788 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
791 alloc_size = call->pkt.u.request.stub_and_verifier.length +
792 call2->pkt.u.request.stub_and_verifier.length;
793 if (call->pkt.u.request.alloc_hint > alloc_size) {
794 alloc_size = call->pkt.u.request.alloc_hint;
797 call->pkt.u.request.stub_and_verifier.data =
798 talloc_realloc(call->mem_ctx,
799 call->pkt.u.request.stub_and_verifier.data, alloc_size);
800 if (!call->pkt.u.request.stub_and_verifier.data) {
801 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
803 memcpy(call->pkt.u.request.stub_and_verifier.data +
804 call->pkt.u.request.stub_and_verifier.length,
805 call2->pkt.u.request.stub_and_verifier.data,
806 call2->pkt.u.request.stub_and_verifier.length);
807 call->pkt.u.request.stub_and_verifier.length +=
808 call2->pkt.u.request.stub_and_verifier.length;
810 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
813 /* this may not be the last pdu in the chain - if its isn't then
814 just put it on the call_list and wait for the rest */
815 if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
816 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
820 switch (call->pkt.ptype) {
821 case DCERPC_PKT_BIND:
822 status = dcesrv_bind(call);
824 case DCERPC_PKT_AUTH3:
825 status = dcesrv_auth3(call);
827 case DCERPC_PKT_REQUEST:
828 status = dcesrv_request(call);
831 status = NT_STATUS_INVALID_PARAMETER;
835 /* if we are going to be sending a reply then add
836 it to the list of pending calls. We add it to the end to keep the call
837 list in the order we will answer */
838 if (!NT_STATUS_IS_OK(status)) {
839 talloc_destroy(mem_ctx);
847 provide some input to a dcerpc endpoint server. This passes data
848 from a dcerpc client into the server
850 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
854 /* handle the very common case that the input contains a full packet and there
855 is no partial packet pending. In this case we can avoid a copy of the
857 if (dce_conn->partial_input.length == 0) {
858 dce_conn->partial_input = *data;
859 /* make sure that dce_partial_advance doesn't free this data */
860 dce_conn->partial_input.free = NULL;
861 while (dce_full_packet(&dce_conn->partial_input)) {
862 status = dcesrv_input_process(dce_conn);
863 if (!NT_STATUS_IS_OK(status)) {
867 if (dce_conn->partial_input.length) {
868 /* there was some data left over. We have to copy this
869 as the caller may free the data */
870 dce_conn->partial_input =
871 data_blob(dce_conn->partial_input.data,
872 dce_conn->partial_input.length);
873 if (!dce_conn->partial_input.data) {
874 return NT_STATUS_NO_MEMORY;
880 dce_conn->partial_input.data = Realloc(dce_conn->partial_input.data,
881 dce_conn->partial_input.length + data->length);
882 if (!dce_conn->partial_input.data) {
883 return NT_STATUS_NO_MEMORY;
885 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
886 data->data, data->length);
887 dce_conn->partial_input.length += data->length;
889 while (dce_full_packet(&dce_conn->partial_input)) {
890 status = dcesrv_input_process(dce_conn);
891 if (!NT_STATUS_IS_OK(status)) {
900 retrieve some output from a dcerpc server
901 The caller supplies a function that will be called to do the
904 The first argument to write_fn() will be 'private', the second will
905 be a pointer to a buffer containing the data to be sent and the 3rd
906 will be the number of bytes to be sent.
908 write_fn() should return the number of bytes successfully written.
910 this will return STATUS_BUFFER_OVERFLOW if there is more to be read
911 from the current fragment
913 NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
915 ssize_t (*write_fn)(void *, const void *, size_t))
917 struct dcesrv_call_state *call;
918 struct dcesrv_call_reply *rep;
920 NTSTATUS status = NT_STATUS_OK;
922 call = dce_conn->call_list;
923 if (!call || !call->replies) {
924 return NT_STATUS_FOOBAR;
928 nwritten = write_fn(private, rep->data.data, rep->data.length);
929 if (nwritten == -1) {
930 /* TODO: hmm, how do we cope with this? destroy the
931 connection perhaps? */
932 return NT_STATUS_UNSUCCESSFUL;
935 rep->data.length -= nwritten;
936 rep->data.data += nwritten;
938 if (rep->data.length == 0) {
939 /* we're done with this section of the call */
940 DLIST_REMOVE(call->replies, rep);
942 status = STATUS_BUFFER_OVERFLOW;
945 if (call->replies == NULL) {
946 /* we're done with the whole call */
947 DLIST_REMOVE(dce_conn->call_list, call);
948 talloc_destroy(call->mem_ctx);
956 write_fn() for dcesrv_output_blob()
958 static ssize_t dcesrv_output_blob_write_fn(void *private, const void *buf, size_t count)
960 DATA_BLOB *blob = private;
961 if (count < blob->length) {
962 blob->length = count;
964 memcpy(blob->data, buf, blob->length);
969 a simple wrapper for dcesrv_output() for when we want to output
972 NTSTATUS dcesrv_output_blob(struct dcesrv_connection *dce_conn,
975 return dcesrv_output(dce_conn, blob, dcesrv_output_blob_write_fn);
979 initialise the dcerpc server context
981 NTSTATUS dcesrv_init_context(struct dcesrv_context *dce_ctx)
984 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
986 dce_ctx->mem_ctx = talloc_init("struct dcesrv_context");
987 if (!dce_ctx->mem_ctx) {
988 DEBUG(3,("dcesrv_init_context: talloc_init failed\n"));
989 return NT_STATUS_NO_MEMORY;
992 dce_ctx->endpoint_list = NULL;
994 if (!endpoint_servers) {
995 DEBUG(3,("dcesrv_init_context: no endpoint servers configured\n"));
999 for (i=0;endpoint_servers[i];i++) {
1001 const struct dcesrv_endpoint_server *ep_server;
1003 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1005 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1006 return NT_STATUS_UNSUCCESSFUL;
1009 ret = ep_server->init_server(dce_ctx, ep_server);
1010 if (!NT_STATUS_IS_OK(ret)) {
1011 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1016 return NT_STATUS_OK;
1019 /* the list of currently registered DCERPC endpoint servers.
1022 struct dcesrv_endpoint_server *ep_server;
1023 } *ep_servers = NULL;
1024 static int num_ep_servers;
1027 register a DCERPC endpoint server.
1029 The 'name' can be later used by other backends to find the operations
1030 structure for this backend.
1032 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1034 static NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1036 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1038 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1039 /* its already registered! */
1040 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1042 return NT_STATUS_OBJECT_NAME_COLLISION;
1045 ep_servers = Realloc(ep_servers, sizeof(ep_servers[0]) * (num_ep_servers+1));
1047 smb_panic("out of memory in dcerpc_register");
1050 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1051 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1055 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1058 return NT_STATUS_OK;
1062 return the operations structure for a named backend of the specified type
1064 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1068 for (i=0;i<num_ep_servers;i++) {
1069 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1070 return ep_servers[i].ep_server;
1078 return the DCERPC module version, and the size of some critical types
1079 This can be used by endpoint server modules to either detect compilation errors, or provide
1080 multiple implementations for different smbd compilation options in one module
1082 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1084 static const struct dcesrv_critical_sizes critical_sizes = {
1085 DCERPC_MODULE_VERSION,
1086 sizeof(struct dcesrv_context),
1087 sizeof(struct dcesrv_endpoint),
1088 sizeof(struct dcesrv_endpoint_server),
1089 sizeof(struct dcesrv_ep_description),
1090 sizeof(struct dcesrv_interface),
1091 sizeof(struct dcesrv_if_list),
1092 sizeof(struct dcesrv_connection),
1093 sizeof(struct dcesrv_call_state),
1094 sizeof(struct dcesrv_auth),
1095 sizeof(struct dcesrv_handle)
1098 return &critical_sizes;
1102 initialise the DCERPC subsystem
1104 BOOL dcesrv_init(void)
1108 status = register_subsystem("dcerpc", dcerpc_register_ep_server);
1109 if (!NT_STATUS_IS_OK(status)) {
1113 /* FIXME: Perhaps panic if a basic endpoint server, such as EPMAPER, fails to initialise? */
1116 DEBUG(3,("DCERPC subsystem version %d initialised\n", DCERPC_MODULE_VERSION));