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_p(dce_ctx, struct dcesrv_endpoint);
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_p(dce_ctx, struct dcesrv_if_list);
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, 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));
242 static NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
243 DATA_BLOB *session_key)
245 if (p->auth_state.session_info->session_key.length) {
246 *session_key = p->auth_state.session_info->session_key;
249 return NT_STATUS_NO_USER_SESSION_KEY;
252 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
253 DATA_BLOB *session_key)
255 /* this took quite a few CPU cycles to find ... */
256 session_key->data = "SystemLibraryDTC";
257 session_key->length = 16;
262 fetch the user session key - may be default (above) or the SMB session key
264 NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
265 DATA_BLOB *session_key)
267 return p->auth_state.session_key(p, session_key);
272 destroy a link to an endpoint
274 static int dcesrv_endpoint_destructor(void *ptr)
276 struct dcesrv_connection *p = ptr;
278 p->iface->unbind(p, p->iface);
281 /* destroy any handles */
283 dcesrv_handle_destroy(p, p->handles);
286 if (p->auth_state.gensec_security) {
287 gensec_end(&p->auth_state.gensec_security);
295 connect to a dcerpc endpoint
297 NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
298 const struct dcesrv_endpoint *ep,
299 struct dcesrv_connection **p)
301 *p = talloc_p(dce_ctx, struct dcesrv_connection);
303 return NT_STATUS_NO_MEMORY;
306 (*p)->dce_ctx = dce_ctx;
309 (*p)->private = NULL;
310 (*p)->call_list = NULL;
311 (*p)->cli_max_recv_frag = 0;
312 (*p)->handles = NULL;
313 (*p)->partial_input = data_blob(NULL, 0);
314 (*p)->auth_state.auth_info = NULL;
315 (*p)->auth_state.gensec_security = NULL;
316 (*p)->auth_state.session_info = NULL;
317 (*p)->auth_state.session_key = dcesrv_generic_session_key;
318 (*p)->srv_conn = NULL;
320 talloc_set_destructor(*p, dcesrv_endpoint_destructor);
326 search and connect to a dcerpc endpoint
328 NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
329 const struct dcesrv_ep_description *ep_description,
330 struct auth_session_info *session_info,
331 struct dcesrv_connection **dce_conn_p)
334 const struct dcesrv_endpoint *ep;
336 /* make sure this endpoint exists */
337 ep = find_endpoint(dce_ctx, ep_description);
339 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
342 status = dcesrv_endpoint_connect(dce_ctx, ep, dce_conn_p);
343 if (!NT_STATUS_IS_OK(status)) {
347 session_info->refcount++;
348 (*dce_conn_p)->auth_state.session_info = session_info;
349 (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
351 /* TODO: check security descriptor of the endpoint here
352 * if it's a smb named pipe
353 * if it's failed free dce_conn_p
360 static void dcesrv_init_hdr(struct dcerpc_packet *pkt)
363 pkt->rpc_vers_minor = 0;
364 if (lp_rpc_big_endian()) {
367 pkt->drep[0] = DCERPC_DREP_LE;
375 return a dcerpc fault
377 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
379 struct dcerpc_packet pkt;
380 struct dcesrv_call_reply *rep;
383 /* setup a bind_ack */
384 dcesrv_init_hdr(&pkt);
386 pkt.call_id = call->pkt.call_id;
387 pkt.ptype = DCERPC_PKT_FAULT;
388 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
389 pkt.u.fault.alloc_hint = 0;
390 pkt.u.fault.context_id = 0;
391 pkt.u.fault.cancel_count = 0;
392 pkt.u.fault.status = fault_code;
394 rep = talloc_p(call, struct dcesrv_call_reply);
396 return NT_STATUS_NO_MEMORY;
399 status = dcerpc_push_auth(&rep->data, call, &pkt, NULL);
400 if (!NT_STATUS_IS_OK(status)) {
404 dcerpc_set_frag_length(&rep->data, rep->data.length);
406 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
407 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
414 return a dcerpc bind_nak
416 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
418 struct dcerpc_packet pkt;
419 struct dcesrv_call_reply *rep;
422 /* setup a bind_nak */
423 dcesrv_init_hdr(&pkt);
425 pkt.call_id = call->pkt.call_id;
426 pkt.ptype = DCERPC_PKT_BIND_NAK;
427 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
428 pkt.u.bind_nak.reject_reason = reason;
429 pkt.u.bind_nak.num_versions = 0;
431 rep = talloc_p(call, struct dcesrv_call_reply);
433 return NT_STATUS_NO_MEMORY;
436 status = dcerpc_push_auth(&rep->data, call, &pkt, NULL);
437 if (!NT_STATUS_IS_OK(status)) {
441 dcerpc_set_frag_length(&rep->data, rep->data.length);
443 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
444 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
451 handle a bind request
453 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
455 const char *uuid, *transfer_syntax;
456 uint32_t if_version, transfer_syntax_version;
457 struct dcerpc_packet pkt;
458 struct dcesrv_call_reply *rep;
460 uint32_t result=0, reason=0;
462 if (call->pkt.u.bind.num_contexts != 1 ||
463 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
464 return dcesrv_bind_nak(call, 0);
467 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
468 uuid = GUID_string(call, &call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid);
470 return dcesrv_bind_nak(call, 0);
473 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
474 transfer_syntax = GUID_string(call,
475 &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid);
476 if (!transfer_syntax ||
477 strcasecmp(NDR_GUID, transfer_syntax) != 0 ||
478 NDR_GUID_VERSION != transfer_syntax_version) {
479 /* we only do NDR encoded dcerpc */
480 return dcesrv_bind_nak(call, 0);
483 call->conn->iface = find_interface_by_uuid(call->conn->endpoint, uuid, if_version);
484 if (!call->conn->iface) {
485 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
486 /* we don't know about that interface */
487 result = DCERPC_BIND_PROVIDER_REJECT;
488 reason = DCERPC_BIND_REASON_ASYNTAX;
491 if (call->conn->cli_max_recv_frag == 0) {
492 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
495 /* handle any authentication that is being requested */
496 if (!dcesrv_auth_bind(call)) {
497 /* TODO: work out the right reject code */
498 return dcesrv_bind_nak(call, 0);
501 /* setup a bind_ack */
502 dcesrv_init_hdr(&pkt);
504 pkt.call_id = call->pkt.call_id;
505 pkt.ptype = DCERPC_PKT_BIND_ACK;
506 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
507 pkt.u.bind_ack.max_xmit_frag = 0x2000;
508 pkt.u.bind_ack.max_recv_frag = 0x2000;
509 pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
510 if (call->conn->iface && call->conn->iface->ndr) {
511 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s",
512 call->conn->iface->ndr->name);
514 pkt.u.bind_ack.secondary_address = "";
516 pkt.u.bind_ack.num_results = 1;
517 pkt.u.bind_ack.ctx_list = talloc_p(call, struct dcerpc_ack_ctx);
518 if (!pkt.u.bind_ack.ctx_list) {
519 return NT_STATUS_NO_MEMORY;
521 pkt.u.bind_ack.ctx_list[0].result = result;
522 pkt.u.bind_ack.ctx_list[0].reason = reason;
523 GUID_from_string(NDR_GUID, &pkt.u.bind_ack.ctx_list[0].syntax.uuid);
524 pkt.u.bind_ack.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
525 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
527 if (!dcesrv_auth_bind_ack(call, &pkt)) {
528 return dcesrv_bind_nak(call, 0);
531 if (call->conn->iface) {
532 status = call->conn->iface->bind(call, call->conn->iface);
533 if (!NT_STATUS_IS_OK(status)) {
534 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n", uuid, if_version, nt_errstr(status)));
535 return dcesrv_bind_nak(call, 0);
539 rep = talloc_p(call, struct dcesrv_call_reply);
541 return NT_STATUS_NO_MEMORY;
544 status = dcerpc_push_auth(&rep->data, call, &pkt,
545 call->conn->auth_state.auth_info);
546 if (!NT_STATUS_IS_OK(status)) {
550 dcerpc_set_frag_length(&rep->data, rep->data.length);
552 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
553 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
560 handle a auth3 request
562 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
564 /* handle the auth3 in the auth code */
565 if (!dcesrv_auth_auth3(call)) {
566 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
571 /* we don't send a reply to a auth3 request, except by a
578 handle a dcerpc request packet
580 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
582 struct ndr_pull *pull;
583 struct ndr_push *push;
588 uint32_t total_length;
591 if (!call->conn->iface) {
592 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
595 opnum = call->pkt.u.request.opnum;
597 if (opnum >= call->conn->iface->ndr->num_calls) {
598 return dcesrv_fault(call, DCERPC_FAULT_OP_RNG_ERROR);
601 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
603 return NT_STATUS_NO_MEMORY;
606 r = talloc(call, call->conn->iface->ndr->calls[opnum].struct_size);
608 return NT_STATUS_NO_MEMORY;
611 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
612 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
615 /* unravel the NDR for the packet */
616 status = call->conn->iface->ndr->calls[opnum].ndr_pull(pull, NDR_IN, r);
617 if (!NT_STATUS_IS_OK(status)) {
618 dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN,
619 &call->pkt.u.request.stub_and_verifier);
620 return dcesrv_fault(call, DCERPC_FAULT_NDR);
623 if (pull->offset != pull->data_size) {
624 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
625 pull->data_size - pull->offset));
626 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
629 call->fault_code = 0;
631 /* call the dispatch function */
632 status = call->conn->iface->dispatch(call, call, r);
633 if (!NT_STATUS_IS_OK(status)) {
634 dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN,
635 &call->pkt.u.request.stub_and_verifier);
636 return dcesrv_fault(call, call->fault_code);
639 /* form the reply NDR */
640 push = ndr_push_init_ctx(call);
642 return NT_STATUS_NO_MEMORY;
645 /* carry over the pointer count to the reply in case we are
646 using full pointer. See NDR specification for full
648 push->ptr_count = pull->ptr_count;
650 if (lp_rpc_big_endian()) {
651 push->flags |= LIBNDR_FLAG_BIGENDIAN;
654 status = call->conn->iface->ndr->calls[opnum].ndr_push(push, NDR_OUT, r);
655 if (!NT_STATUS_IS_OK(status)) {
656 return dcesrv_fault(call, DCERPC_FAULT_NDR);
659 stub = ndr_push_blob(push);
661 total_length = stub.length;
665 struct dcesrv_call_reply *rep;
666 struct dcerpc_packet pkt;
668 rep = talloc_p(call, struct dcesrv_call_reply);
670 return NT_STATUS_NO_MEMORY;
673 length = stub.length;
674 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
675 /* the 32 is to cope with signing data */
676 length = call->conn->cli_max_recv_frag -
677 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
680 /* form the dcerpc response packet */
681 dcesrv_init_hdr(&pkt);
683 pkt.call_id = call->pkt.call_id;
684 pkt.ptype = DCERPC_PKT_RESPONSE;
686 if (stub.length == total_length) {
687 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
689 if (length == stub.length) {
690 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
692 pkt.u.response.alloc_hint = stub.length;
693 pkt.u.response.context_id = call->pkt.u.request.context_id;
694 pkt.u.response.cancel_count = 0;
695 pkt.u.response.stub_and_verifier.data = stub.data;
696 pkt.u.response.stub_and_verifier.length = length;
698 if (!dcesrv_auth_response(call, &rep->data, &pkt)) {
699 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
702 dcerpc_set_frag_length(&rep->data, rep->data.length);
704 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
707 stub.length -= length;
708 } while (stub.length != 0);
710 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
717 work out if we have a full packet yet
719 static BOOL dce_full_packet(const DATA_BLOB *data)
721 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
724 if (dcerpc_get_frag_length(data) > data->length) {
731 we might have consumed only part of our input - advance past that part
733 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
737 if (dce_conn->partial_input.length == offset) {
738 data_blob_free(&dce_conn->partial_input);
742 blob = dce_conn->partial_input;
743 dce_conn->partial_input = data_blob(blob.data + offset,
744 blob.length - offset);
745 data_blob_free(&blob);
749 process some input to a dcerpc endpoint server.
751 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
753 struct ndr_pull *ndr;
755 struct dcesrv_call_state *call;
758 call = talloc_p(dce_conn, struct dcesrv_call_state);
760 talloc_free(dce_conn->partial_input.data);
761 return NT_STATUS_NO_MEMORY;
763 call->conn = dce_conn;
764 call->replies = NULL;
766 blob = dce_conn->partial_input;
767 blob.length = dcerpc_get_frag_length(&blob);
769 ndr = ndr_pull_init_blob(&blob, call);
771 talloc_free(dce_conn->partial_input.data);
773 return NT_STATUS_NO_MEMORY;
776 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
777 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
780 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
781 if (!NT_STATUS_IS_OK(status)) {
782 talloc_free(dce_conn->partial_input.data);
787 /* we have to check the signing here, before combining the
789 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
790 !dcesrv_auth_request(call, &blob)) {
791 dce_partial_advance(dce_conn, blob.length);
792 return dcesrv_fault(call, DCERPC_FAULT_LOGON_FAILURE);
795 dce_partial_advance(dce_conn, blob.length);
797 /* see if this is a continued packet */
798 if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
799 struct dcesrv_call_state *call2 = call;
802 /* we only allow fragmented requests, no other packet types */
803 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
804 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
807 /* this is a continuation of an existing call - find the call then
808 tack it on the end */
809 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
811 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
814 if (call->pkt.ptype != call2->pkt.ptype) {
815 /* trying to play silly buggers are we? */
816 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
819 alloc_size = call->pkt.u.request.stub_and_verifier.length +
820 call2->pkt.u.request.stub_and_verifier.length;
821 if (call->pkt.u.request.alloc_hint > alloc_size) {
822 alloc_size = call->pkt.u.request.alloc_hint;
825 call->pkt.u.request.stub_and_verifier.data =
826 talloc_realloc(call, call->pkt.u.request.stub_and_verifier.data, alloc_size);
827 if (!call->pkt.u.request.stub_and_verifier.data) {
828 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
830 memcpy(call->pkt.u.request.stub_and_verifier.data +
831 call->pkt.u.request.stub_and_verifier.length,
832 call2->pkt.u.request.stub_and_verifier.data,
833 call2->pkt.u.request.stub_and_verifier.length);
834 call->pkt.u.request.stub_and_verifier.length +=
835 call2->pkt.u.request.stub_and_verifier.length;
837 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
842 /* this may not be the last pdu in the chain - if its isn't then
843 just put it on the call_list and wait for the rest */
844 if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
845 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
849 switch (call->pkt.ptype) {
850 case DCERPC_PKT_BIND:
851 status = dcesrv_bind(call);
853 case DCERPC_PKT_AUTH3:
854 status = dcesrv_auth3(call);
856 case DCERPC_PKT_REQUEST:
857 status = dcesrv_request(call);
860 status = NT_STATUS_INVALID_PARAMETER;
864 /* if we are going to be sending a reply then add
865 it to the list of pending calls. We add it to the end to keep the call
866 list in the order we will answer */
867 if (!NT_STATUS_IS_OK(status)) {
876 provide some input to a dcerpc endpoint server. This passes data
877 from a dcerpc client into the server
879 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
883 dce_conn->partial_input.data = talloc_realloc(dce_conn,
884 dce_conn->partial_input.data,
885 dce_conn->partial_input.length + data->length);
886 if (!dce_conn->partial_input.data) {
887 return NT_STATUS_NO_MEMORY;
889 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
890 data->data, data->length);
891 dce_conn->partial_input.length += data->length;
893 while (dce_full_packet(&dce_conn->partial_input)) {
894 status = dcesrv_input_process(dce_conn);
895 if (!NT_STATUS_IS_OK(status)) {
904 retrieve some output from a dcerpc server
905 The caller supplies a function that will be called to do the
908 The first argument to write_fn() will be 'private', the second will
909 be a pointer to a buffer containing the data to be sent and the 3rd
910 will be the number of bytes to be sent.
912 write_fn() should return the number of bytes successfully written.
914 this will return STATUS_BUFFER_OVERFLOW if there is more to be read
915 from the current fragment
917 NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
919 ssize_t (*write_fn)(void *, DATA_BLOB *))
921 struct dcesrv_call_state *call;
922 struct dcesrv_call_reply *rep;
924 NTSTATUS status = NT_STATUS_OK;
926 call = dce_conn->call_list;
927 if (!call || !call->replies) {
928 return NT_STATUS_FOOBAR;
932 nwritten = write_fn(private, &rep->data);
933 if (nwritten == -1) {
934 /* TODO: hmm, how do we cope with this? destroy the
935 connection perhaps? */
936 return NT_STATUS_UNSUCCESSFUL;
939 rep->data.length -= nwritten;
940 rep->data.data += nwritten;
942 if (rep->data.length == 0) {
943 /* we're done with this section of the call */
944 DLIST_REMOVE(call->replies, rep);
946 status = STATUS_BUFFER_OVERFLOW;
949 if (call->replies == NULL) {
950 /* we're done with the whole call */
951 DLIST_REMOVE(dce_conn->call_list, call);
960 write_fn() for dcesrv_output_blob()
962 static ssize_t dcesrv_output_blob_write_fn(void *private, DATA_BLOB *out)
964 DATA_BLOB *blob = private;
965 if (out->length < blob->length) {
966 blob->length = out->length;
968 memcpy(blob->data, out->data, blob->length);
973 a simple wrapper for dcesrv_output() for when we want to output
976 NTSTATUS dcesrv_output_blob(struct dcesrv_connection *dce_conn,
979 return dcesrv_output(dce_conn, blob, dcesrv_output_blob_write_fn);
983 initialise the dcerpc server context
985 NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **dce_ctx)
988 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
990 (*dce_ctx) = talloc_p(mem_ctx, struct dcesrv_context);
992 return NT_STATUS_NO_MEMORY;
995 (*dce_ctx)->endpoint_list = NULL;
997 if (!endpoint_servers) {
998 DEBUG(3,("dcesrv_init_context: no endpoint servers configured\n"));
1002 for (i=0;endpoint_servers[i];i++) {
1004 const struct dcesrv_endpoint_server *ep_server;
1006 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1008 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1009 return NT_STATUS_UNSUCCESSFUL;
1012 ret = ep_server->init_server(*dce_ctx, ep_server);
1013 if (!NT_STATUS_IS_OK(ret)) {
1014 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1019 return NT_STATUS_OK;
1022 static void dcesrv_init(struct server_service *service, const struct model_ops *model_ops)
1024 struct dcesrv_context *dce_ctx;
1026 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
1028 DEBUG(1,("dcesrv_init\n"));
1030 if (!endpoint_servers) {
1031 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1035 dce_ctx = talloc_p(service, struct dcesrv_context);
1037 DEBUG(0,("talloc_p(mem_ctx, struct dcesrv_context) failed\n"));
1041 ZERO_STRUCTP(dce_ctx);
1042 dce_ctx->endpoint_list = NULL;
1044 for (i=0;endpoint_servers[i];i++) {
1046 const struct dcesrv_endpoint_server *ep_server;
1048 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1050 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1054 ret = ep_server->init_server(dce_ctx, ep_server);
1055 if (!NT_STATUS_IS_OK(ret)) {
1056 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1061 dcesrv_tcp_init(service, model_ops, dce_ctx);
1066 static void dcesrv_accept(struct server_connection *srv_conn)
1068 dcesrv_tcp_accept(srv_conn);
1071 static void dcesrv_recv(struct server_connection *srv_conn, time_t t, uint16_t flags)
1073 dcesrv_tcp_recv(srv_conn, t, flags);
1076 static void dcesrv_send(struct server_connection *srv_conn, time_t t, uint16_t flags)
1078 dcesrv_tcp_send(srv_conn, t, flags);
1081 static void dcesrv_idle(struct server_connection *srv_conn, time_t t)
1083 dcesrv_tcp_idle(srv_conn, t);
1086 static void dcesrv_close(struct server_connection *srv_conn, const char *reason)
1088 dcesrv_tcp_close(srv_conn, reason);
1092 static void dcesrv_exit(struct server_service *service, const char *reason)
1094 dcesrv_tcp_exit(service, reason);
1098 /* the list of currently registered DCERPC endpoint servers.
1101 struct dcesrv_endpoint_server *ep_server;
1102 } *ep_servers = NULL;
1103 static int num_ep_servers;
1106 register a DCERPC endpoint server.
1108 The 'name' can be later used by other backends to find the operations
1109 structure for this backend.
1111 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1113 static NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1115 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1117 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1118 /* its already registered! */
1119 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1121 return NT_STATUS_OBJECT_NAME_COLLISION;
1124 ep_servers = Realloc(ep_servers, sizeof(ep_servers[0]) * (num_ep_servers+1));
1126 smb_panic("out of memory in dcerpc_register");
1129 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1130 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1134 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1137 return NT_STATUS_OK;
1141 return the operations structure for a named backend of the specified type
1143 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1147 for (i=0;i<num_ep_servers;i++) {
1148 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1149 return ep_servers[i].ep_server;
1157 return the DCERPC module version, and the size of some critical types
1158 This can be used by endpoint server modules to either detect compilation errors, or provide
1159 multiple implementations for different smbd compilation options in one module
1161 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1163 static const struct dcesrv_critical_sizes critical_sizes = {
1164 DCERPC_MODULE_VERSION,
1165 sizeof(struct dcesrv_context),
1166 sizeof(struct dcesrv_endpoint),
1167 sizeof(struct dcesrv_endpoint_server),
1168 sizeof(struct dcesrv_ep_description),
1169 sizeof(struct dcesrv_interface),
1170 sizeof(struct dcesrv_if_list),
1171 sizeof(struct dcesrv_connection),
1172 sizeof(struct dcesrv_call_state),
1173 sizeof(struct dcesrv_auth),
1174 sizeof(struct dcesrv_handle)
1177 return &critical_sizes;
1181 initialise the DCERPC subsystem
1183 BOOL subsystem_dcerpc_init(void)
1187 status = register_subsystem("dcerpc", dcerpc_register_ep_server);
1188 if (!NT_STATUS_IS_OK(status)) {
1192 /* FIXME: Perhaps panic if a basic endpoint server, such as EPMAPER, fails to initialise? */
1195 DEBUG(3,("DCERPC subsystem version %d initialised\n", DCERPC_MODULE_VERSION));
1199 static const struct server_service_ops dcesrv_ops = {
1201 .service_init = dcesrv_init,
1202 .accept_connection = dcesrv_accept,
1203 .recv_handler = dcesrv_recv,
1204 .send_handler = dcesrv_send,
1205 .idle_handler = dcesrv_idle,
1206 .close_connection = dcesrv_close,
1207 .service_exit = dcesrv_exit,
1210 const struct server_service_ops *dcesrv_get_ops(void)
1215 NTSTATUS server_service_rpc_init(void)
1217 return NT_STATUS_OK;