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 dcerpc_binding *ep1,
30 const struct dcerpc_binding *ep2)
32 if (ep1->transport != ep2->transport) {
36 if (!ep1->options || !ep2->options) {
37 return ep1->options == ep2->options;
40 if (!ep1->options[0] || !ep2->options[0]) {
41 return ep1->options[0] == ep2->options[0];
44 if (strcasecmp(ep1->options[0], ep2->options[0]) != 0)
51 find an endpoint in the dcesrv_context
53 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
54 const struct dcerpc_binding *ep_description)
56 struct dcesrv_endpoint *ep;
57 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
58 if (endpoints_match(&ep->ep_description, ep_description)) {
66 see if a uuid and if_version match to an interface
68 static BOOL interface_match(const struct dcesrv_interface *if1,
69 const struct dcesrv_interface *if2)
71 if (if1->ndr->if_version != if2->ndr->if_version) {
75 if (strcmp(if1->ndr->uuid, if2->ndr->uuid)==0) {
83 find the interface operations on an endpoint
85 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
86 const struct dcesrv_interface *iface)
88 struct dcesrv_if_list *ifl;
89 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
90 if (interface_match(&(ifl->iface), iface)) {
98 see if a uuid and if_version match to an interface
100 static BOOL interface_match_by_uuid(const struct dcesrv_interface *iface,
101 const char *uuid, uint32_t if_version)
103 if (iface->ndr->if_version != if_version) {
107 if (strcmp(iface->ndr->uuid, uuid)==0) {
115 find the interface operations on an endpoint by uuid
117 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
118 const char *uuid, uint32_t if_version)
120 struct dcesrv_if_list *ifl;
121 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
122 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
123 return &(ifl->iface);
130 find a call that is pending in our call list
132 static struct dcesrv_call_state *dcesrv_find_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
134 struct dcesrv_call_state *c;
135 for (c=dce_conn->call_list;c;c=c->next) {
136 if (c->pkt.call_id == call_id) {
144 register an interface on an endpoint
146 NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
148 const struct dcesrv_interface *iface,
149 const struct security_descriptor *sd)
151 struct dcesrv_endpoint *ep;
152 struct dcesrv_if_list *ifl;
153 struct dcerpc_binding binding;
157 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
159 if (NT_STATUS_IS_ERR(status)) {
160 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
164 /* check if this endpoint exists
166 if ((ep=find_endpoint(dce_ctx, &binding))==NULL) {
167 ep = talloc_p(dce_ctx, struct dcesrv_endpoint);
169 return NT_STATUS_NO_MEMORY;
172 ep->ep_description = binding;
176 /* see if the interface is already registered on te endpoint */
177 if (find_interface(ep, iface)!=NULL) {
178 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
179 iface->ndr->name, ep_name));
180 return NT_STATUS_OBJECT_NAME_COLLISION;
183 /* talloc a new interface list element */
184 ifl = talloc_p(dce_ctx, struct dcesrv_if_list);
186 return NT_STATUS_NO_MEMORY;
189 /* copy the given interface struct to the one on the endpoints interface list */
190 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
192 /* if we have a security descriptor given,
193 * we should see if we can set it up on the endpoint
196 /* if there's currently no security descriptor given on the endpoint
199 if (ep->sd == NULL) {
200 ep->sd = copy_security_descriptor(dce_ctx, sd);
203 /* if now there's no security descriptor given on the endpoint
204 * something goes wrong, either we failed to copy the security descriptor
205 * or there was already one on the endpoint
207 if (ep->sd != NULL) {
208 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
209 " on endpoint '%s'\n",
210 iface->ndr->name, ep_name));
211 if (add_ep) free(ep);
213 return NT_STATUS_OBJECT_NAME_COLLISION;
217 /* finally add the interface on the endpoint */
218 DLIST_ADD(ep->interface_list, ifl);
220 /* if it's a new endpoint add it to the dcesrv_context */
222 DLIST_ADD(dce_ctx->endpoint_list, ep);
225 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
226 iface->ndr->name, ep_name));
231 static NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
232 DATA_BLOB *session_key)
234 if (p->auth_state.session_info->session_key.length) {
235 *session_key = p->auth_state.session_info->session_key;
238 return NT_STATUS_NO_USER_SESSION_KEY;
241 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
242 DATA_BLOB *session_key)
244 /* this took quite a few CPU cycles to find ... */
245 session_key->data = "SystemLibraryDTC";
246 session_key->length = 16;
251 fetch the user session key - may be default (above) or the SMB session key
253 NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
254 DATA_BLOB *session_key)
256 return p->auth_state.session_key(p, session_key);
261 destroy a link to an endpoint
263 static int dcesrv_endpoint_destructor(void *ptr)
265 struct dcesrv_connection *p = ptr;
267 p->iface->unbind(p, p->iface);
270 /* destroy any handles */
272 dcesrv_handle_destroy(p, p->handles);
275 if (p->auth_state.gensec_security) {
276 gensec_end(&p->auth_state.gensec_security);
284 connect to a dcerpc endpoint
286 NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
287 const struct dcesrv_endpoint *ep,
288 struct dcesrv_connection **p)
290 *p = talloc_p(dce_ctx, struct dcesrv_connection);
292 return NT_STATUS_NO_MEMORY;
295 (*p)->dce_ctx = dce_ctx;
298 (*p)->private = NULL;
299 (*p)->call_list = NULL;
300 (*p)->cli_max_recv_frag = 0;
301 (*p)->handles = NULL;
302 (*p)->partial_input = data_blob(NULL, 0);
303 (*p)->auth_state.auth_info = NULL;
304 (*p)->auth_state.gensec_security = NULL;
305 (*p)->auth_state.session_info = NULL;
306 (*p)->auth_state.session_key = dcesrv_generic_session_key;
307 (*p)->srv_conn = NULL;
309 talloc_set_destructor(*p, dcesrv_endpoint_destructor);
315 search and connect to a dcerpc endpoint
317 NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
318 const struct dcerpc_binding *ep_description,
319 struct auth_session_info *session_info,
320 struct dcesrv_connection **dce_conn_p)
323 const struct dcesrv_endpoint *ep;
325 /* make sure this endpoint exists */
326 ep = find_endpoint(dce_ctx, ep_description);
328 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
331 status = dcesrv_endpoint_connect(dce_ctx, ep, dce_conn_p);
332 if (!NT_STATUS_IS_OK(status)) {
336 session_info->refcount++;
337 (*dce_conn_p)->auth_state.session_info = session_info;
338 (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
340 /* TODO: check security descriptor of the endpoint here
341 * if it's a smb named pipe
342 * if it's failed free dce_conn_p
349 static void dcesrv_init_hdr(struct dcerpc_packet *pkt)
352 pkt->rpc_vers_minor = 0;
353 if (lp_rpc_big_endian()) {
356 pkt->drep[0] = DCERPC_DREP_LE;
364 return a dcerpc fault
366 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
368 struct dcerpc_packet pkt;
369 struct dcesrv_call_reply *rep;
372 /* setup a bind_ack */
373 dcesrv_init_hdr(&pkt);
375 pkt.call_id = call->pkt.call_id;
376 pkt.ptype = DCERPC_PKT_FAULT;
377 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
378 pkt.u.fault.alloc_hint = 0;
379 pkt.u.fault.context_id = 0;
380 pkt.u.fault.cancel_count = 0;
381 pkt.u.fault.status = fault_code;
383 rep = talloc_p(call, struct dcesrv_call_reply);
385 return NT_STATUS_NO_MEMORY;
388 status = dcerpc_push_auth(&rep->data, call, &pkt, NULL);
389 if (!NT_STATUS_IS_OK(status)) {
393 dcerpc_set_frag_length(&rep->data, rep->data.length);
395 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
396 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
403 return a dcerpc bind_nak
405 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
407 struct dcerpc_packet pkt;
408 struct dcesrv_call_reply *rep;
411 /* setup a bind_nak */
412 dcesrv_init_hdr(&pkt);
414 pkt.call_id = call->pkt.call_id;
415 pkt.ptype = DCERPC_PKT_BIND_NAK;
416 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
417 pkt.u.bind_nak.reject_reason = reason;
418 pkt.u.bind_nak.num_versions = 0;
420 rep = talloc_p(call, struct dcesrv_call_reply);
422 return NT_STATUS_NO_MEMORY;
425 status = dcerpc_push_auth(&rep->data, call, &pkt, NULL);
426 if (!NT_STATUS_IS_OK(status)) {
430 dcerpc_set_frag_length(&rep->data, rep->data.length);
432 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
433 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
440 handle a bind request
442 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
444 const char *uuid, *transfer_syntax;
445 uint32_t if_version, transfer_syntax_version;
446 struct dcerpc_packet pkt;
447 struct dcesrv_call_reply *rep;
449 uint32_t result=0, reason=0;
451 if (call->pkt.u.bind.num_contexts != 1 ||
452 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
453 return dcesrv_bind_nak(call, 0);
456 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
457 uuid = GUID_string(call, &call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid);
459 return dcesrv_bind_nak(call, 0);
462 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
463 transfer_syntax = GUID_string(call,
464 &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid);
465 if (!transfer_syntax ||
466 strcasecmp(NDR_GUID, transfer_syntax) != 0 ||
467 NDR_GUID_VERSION != transfer_syntax_version) {
468 /* we only do NDR encoded dcerpc */
469 return dcesrv_bind_nak(call, 0);
472 call->conn->iface = find_interface_by_uuid(call->conn->endpoint, uuid, if_version);
473 if (!call->conn->iface) {
474 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
475 /* we don't know about that interface */
476 result = DCERPC_BIND_PROVIDER_REJECT;
477 reason = DCERPC_BIND_REASON_ASYNTAX;
480 if (call->conn->cli_max_recv_frag == 0) {
481 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
484 /* handle any authentication that is being requested */
485 if (!dcesrv_auth_bind(call)) {
486 /* TODO: work out the right reject code */
487 return dcesrv_bind_nak(call, 0);
490 /* setup a bind_ack */
491 dcesrv_init_hdr(&pkt);
493 pkt.call_id = call->pkt.call_id;
494 pkt.ptype = DCERPC_PKT_BIND_ACK;
495 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
496 pkt.u.bind_ack.max_xmit_frag = 0x2000;
497 pkt.u.bind_ack.max_recv_frag = 0x2000;
498 pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
499 if (call->conn->iface && call->conn->iface->ndr) {
500 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
501 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s",
502 call->conn->iface->ndr->name);
504 pkt.u.bind_ack.secondary_address = "";
506 pkt.u.bind_ack.num_results = 1;
507 pkt.u.bind_ack.ctx_list = talloc_p(call, struct dcerpc_ack_ctx);
508 if (!pkt.u.bind_ack.ctx_list) {
509 return NT_STATUS_NO_MEMORY;
511 pkt.u.bind_ack.ctx_list[0].result = result;
512 pkt.u.bind_ack.ctx_list[0].reason = reason;
513 GUID_from_string(NDR_GUID, &pkt.u.bind_ack.ctx_list[0].syntax.uuid);
514 pkt.u.bind_ack.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
515 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
517 if (!dcesrv_auth_bind_ack(call, &pkt)) {
518 return dcesrv_bind_nak(call, 0);
521 if (call->conn->iface) {
522 status = call->conn->iface->bind(call, call->conn->iface);
523 if (!NT_STATUS_IS_OK(status)) {
524 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n", uuid, if_version, nt_errstr(status)));
525 return dcesrv_bind_nak(call, 0);
529 rep = talloc_p(call, struct dcesrv_call_reply);
531 return NT_STATUS_NO_MEMORY;
534 status = dcerpc_push_auth(&rep->data, call, &pkt,
535 call->conn->auth_state.auth_info);
536 if (!NT_STATUS_IS_OK(status)) {
540 dcerpc_set_frag_length(&rep->data, rep->data.length);
542 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
543 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
550 handle a auth3 request
552 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
554 /* handle the auth3 in the auth code */
555 if (!dcesrv_auth_auth3(call)) {
556 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
561 /* we don't send a reply to a auth3 request, except by a
568 handle a dcerpc request packet
570 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
572 struct ndr_pull *pull;
573 struct ndr_push *push;
578 uint32_t total_length;
581 if (!call->conn->iface) {
582 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
585 opnum = call->pkt.u.request.opnum;
587 if (opnum >= call->conn->iface->ndr->num_calls) {
588 return dcesrv_fault(call, DCERPC_FAULT_OP_RNG_ERROR);
591 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
593 return NT_STATUS_NO_MEMORY;
596 r = talloc(call, call->conn->iface->ndr->calls[opnum].struct_size);
598 return NT_STATUS_NO_MEMORY;
601 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
602 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
605 /* unravel the NDR for the packet */
606 status = call->conn->iface->ndr->calls[opnum].ndr_pull(pull, NDR_IN, r);
607 if (!NT_STATUS_IS_OK(status)) {
608 dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN,
609 &call->pkt.u.request.stub_and_verifier);
610 return dcesrv_fault(call, DCERPC_FAULT_NDR);
613 if (pull->offset != pull->data_size) {
614 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
615 pull->data_size - pull->offset));
616 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
619 call->fault_code = 0;
621 /* call the dispatch function */
622 status = call->conn->iface->dispatch(call, call, r);
623 if (!NT_STATUS_IS_OK(status)) {
624 dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN,
625 &call->pkt.u.request.stub_and_verifier);
626 return dcesrv_fault(call, call->fault_code);
629 /* form the reply NDR */
630 push = ndr_push_init_ctx(call);
632 return NT_STATUS_NO_MEMORY;
635 /* carry over the pointer count to the reply in case we are
636 using full pointer. See NDR specification for full
638 push->ptr_count = pull->ptr_count;
640 if (lp_rpc_big_endian()) {
641 push->flags |= LIBNDR_FLAG_BIGENDIAN;
644 status = call->conn->iface->ndr->calls[opnum].ndr_push(push, NDR_OUT, r);
645 if (!NT_STATUS_IS_OK(status)) {
646 return dcesrv_fault(call, DCERPC_FAULT_NDR);
649 stub = ndr_push_blob(push);
651 total_length = stub.length;
655 struct dcesrv_call_reply *rep;
656 struct dcerpc_packet pkt;
658 rep = talloc_p(call, struct dcesrv_call_reply);
660 return NT_STATUS_NO_MEMORY;
663 length = stub.length;
664 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
665 /* the 32 is to cope with signing data */
666 length = call->conn->cli_max_recv_frag -
667 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
670 /* form the dcerpc response packet */
671 dcesrv_init_hdr(&pkt);
673 pkt.call_id = call->pkt.call_id;
674 pkt.ptype = DCERPC_PKT_RESPONSE;
676 if (stub.length == total_length) {
677 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
679 if (length == stub.length) {
680 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
682 pkt.u.response.alloc_hint = stub.length;
683 pkt.u.response.context_id = call->pkt.u.request.context_id;
684 pkt.u.response.cancel_count = 0;
685 pkt.u.response.stub_and_verifier.data = stub.data;
686 pkt.u.response.stub_and_verifier.length = length;
688 if (!dcesrv_auth_response(call, &rep->data, &pkt)) {
689 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
692 dcerpc_set_frag_length(&rep->data, rep->data.length);
694 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
697 stub.length -= length;
698 } while (stub.length != 0);
700 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
707 work out if we have a full packet yet
709 static BOOL dce_full_packet(const DATA_BLOB *data)
711 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
714 if (dcerpc_get_frag_length(data) > data->length) {
721 we might have consumed only part of our input - advance past that part
723 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
727 if (dce_conn->partial_input.length == offset) {
728 data_blob_free(&dce_conn->partial_input);
732 blob = dce_conn->partial_input;
733 dce_conn->partial_input = data_blob(blob.data + offset,
734 blob.length - offset);
735 data_blob_free(&blob);
739 process some input to a dcerpc endpoint server.
741 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
743 struct ndr_pull *ndr;
745 struct dcesrv_call_state *call;
748 call = talloc_p(dce_conn, struct dcesrv_call_state);
750 talloc_free(dce_conn->partial_input.data);
751 return NT_STATUS_NO_MEMORY;
753 call->conn = dce_conn;
754 call->replies = NULL;
756 blob = dce_conn->partial_input;
757 blob.length = dcerpc_get_frag_length(&blob);
759 ndr = ndr_pull_init_blob(&blob, call);
761 talloc_free(dce_conn->partial_input.data);
763 return NT_STATUS_NO_MEMORY;
766 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
767 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
770 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
771 if (!NT_STATUS_IS_OK(status)) {
772 talloc_free(dce_conn->partial_input.data);
777 /* we have to check the signing here, before combining the
779 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
780 !dcesrv_auth_request(call, &blob)) {
781 dce_partial_advance(dce_conn, blob.length);
782 return dcesrv_fault(call, DCERPC_FAULT_LOGON_FAILURE);
785 dce_partial_advance(dce_conn, blob.length);
787 /* see if this is a continued packet */
788 if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
789 struct dcesrv_call_state *call2 = call;
792 /* we only allow fragmented requests, no other packet types */
793 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
794 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
797 /* this is a continuation of an existing call - find the call then
798 tack it on the end */
799 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
801 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
804 if (call->pkt.ptype != call2->pkt.ptype) {
805 /* trying to play silly buggers are we? */
806 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
809 alloc_size = call->pkt.u.request.stub_and_verifier.length +
810 call2->pkt.u.request.stub_and_verifier.length;
811 if (call->pkt.u.request.alloc_hint > alloc_size) {
812 alloc_size = call->pkt.u.request.alloc_hint;
815 call->pkt.u.request.stub_and_verifier.data =
816 talloc_realloc(call, call->pkt.u.request.stub_and_verifier.data, alloc_size);
817 if (!call->pkt.u.request.stub_and_verifier.data) {
818 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
820 memcpy(call->pkt.u.request.stub_and_verifier.data +
821 call->pkt.u.request.stub_and_verifier.length,
822 call2->pkt.u.request.stub_and_verifier.data,
823 call2->pkt.u.request.stub_and_verifier.length);
824 call->pkt.u.request.stub_and_verifier.length +=
825 call2->pkt.u.request.stub_and_verifier.length;
827 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
832 /* this may not be the last pdu in the chain - if its isn't then
833 just put it on the call_list and wait for the rest */
834 if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
835 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
839 switch (call->pkt.ptype) {
840 case DCERPC_PKT_BIND:
841 status = dcesrv_bind(call);
843 case DCERPC_PKT_AUTH3:
844 status = dcesrv_auth3(call);
846 case DCERPC_PKT_REQUEST:
847 status = dcesrv_request(call);
850 status = NT_STATUS_INVALID_PARAMETER;
854 /* if we are going to be sending a reply then add
855 it to the list of pending calls. We add it to the end to keep the call
856 list in the order we will answer */
857 if (!NT_STATUS_IS_OK(status)) {
866 provide some input to a dcerpc endpoint server. This passes data
867 from a dcerpc client into the server
869 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
873 dce_conn->partial_input.data = talloc_realloc(dce_conn,
874 dce_conn->partial_input.data,
875 dce_conn->partial_input.length + data->length);
876 if (!dce_conn->partial_input.data) {
877 return NT_STATUS_NO_MEMORY;
879 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
880 data->data, data->length);
881 dce_conn->partial_input.length += data->length;
883 while (dce_full_packet(&dce_conn->partial_input)) {
884 status = dcesrv_input_process(dce_conn);
885 if (!NT_STATUS_IS_OK(status)) {
894 retrieve some output from a dcerpc server
895 The caller supplies a function that will be called to do the
898 The first argument to write_fn() will be 'private', the second will
899 be a pointer to a buffer containing the data to be sent and the 3rd
900 will be the number of bytes to be sent.
902 write_fn() should return the number of bytes successfully written.
904 this will return STATUS_BUFFER_OVERFLOW if there is more to be read
905 from the current fragment
907 NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
909 ssize_t (*write_fn)(void *, DATA_BLOB *))
911 struct dcesrv_call_state *call;
912 struct dcesrv_call_reply *rep;
914 NTSTATUS status = NT_STATUS_OK;
916 call = dce_conn->call_list;
917 if (!call || !call->replies) {
918 return NT_STATUS_FOOBAR;
922 nwritten = write_fn(private, &rep->data);
923 if (nwritten == -1) {
924 /* TODO: hmm, how do we cope with this? destroy the
925 connection perhaps? */
926 return NT_STATUS_UNSUCCESSFUL;
929 rep->data.length -= nwritten;
930 rep->data.data += nwritten;
932 if (rep->data.length == 0) {
933 /* we're done with this section of the call */
934 DLIST_REMOVE(call->replies, rep);
936 status = STATUS_BUFFER_OVERFLOW;
939 if (call->replies == NULL) {
940 /* we're done with the whole call */
941 DLIST_REMOVE(dce_conn->call_list, call);
950 write_fn() for dcesrv_output_blob()
952 static ssize_t dcesrv_output_blob_write_fn(void *private, DATA_BLOB *out)
954 DATA_BLOB *blob = private;
955 if (out->length < blob->length) {
956 blob->length = out->length;
958 memcpy(blob->data, out->data, blob->length);
963 a simple wrapper for dcesrv_output() for when we want to output
966 NTSTATUS dcesrv_output_blob(struct dcesrv_connection *dce_conn,
969 return dcesrv_output(dce_conn, blob, dcesrv_output_blob_write_fn);
973 initialise the dcerpc server context
975 NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **dce_ctx)
978 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
980 (*dce_ctx) = talloc_p(mem_ctx, struct dcesrv_context);
982 return NT_STATUS_NO_MEMORY;
985 (*dce_ctx)->endpoint_list = NULL;
987 if (!endpoint_servers) {
988 DEBUG(3,("dcesrv_init_context: no endpoint servers configured\n"));
992 for (i=0;endpoint_servers[i];i++) {
994 const struct dcesrv_endpoint_server *ep_server;
996 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
998 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
999 return NT_STATUS_UNSUCCESSFUL;
1002 ret = ep_server->init_server(*dce_ctx, ep_server);
1003 if (!NT_STATUS_IS_OK(ret)) {
1004 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1009 return NT_STATUS_OK;
1012 static void dcesrv_init(struct server_service *service, const struct model_ops *model_ops)
1014 struct dcesrv_context *dce_ctx;
1016 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
1018 DEBUG(1,("dcesrv_init\n"));
1020 if (!endpoint_servers) {
1021 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1025 dce_ctx = talloc_p(service, struct dcesrv_context);
1027 DEBUG(0,("talloc_p(mem_ctx, struct dcesrv_context) failed\n"));
1031 ZERO_STRUCTP(dce_ctx);
1032 dce_ctx->endpoint_list = NULL;
1034 for (i=0;endpoint_servers[i];i++) {
1036 const struct dcesrv_endpoint_server *ep_server;
1038 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1040 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1044 ret = ep_server->init_server(dce_ctx, ep_server);
1045 if (!NT_STATUS_IS_OK(ret)) {
1046 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1051 dcesrv_tcp_init(service, model_ops, dce_ctx);
1056 static void dcesrv_accept(struct server_connection *srv_conn)
1058 dcesrv_tcp_accept(srv_conn);
1061 static void dcesrv_recv(struct server_connection *srv_conn, time_t t, uint16_t flags)
1063 dcesrv_tcp_recv(srv_conn, t, flags);
1066 static void dcesrv_send(struct server_connection *srv_conn, time_t t, uint16_t flags)
1068 dcesrv_tcp_send(srv_conn, t, flags);
1071 static void dcesrv_idle(struct server_connection *srv_conn, time_t t)
1073 dcesrv_tcp_idle(srv_conn, t);
1076 static void dcesrv_close(struct server_connection *srv_conn, const char *reason)
1078 dcesrv_tcp_close(srv_conn, reason);
1082 static void dcesrv_exit(struct server_service *service, const char *reason)
1084 dcesrv_tcp_exit(service, reason);
1088 /* the list of currently registered DCERPC endpoint servers.
1091 struct dcesrv_endpoint_server *ep_server;
1092 } *ep_servers = NULL;
1093 static int num_ep_servers;
1096 register a DCERPC endpoint server.
1098 The 'name' can be later used by other backends to find the operations
1099 structure for this backend.
1101 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1103 static NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1105 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1107 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1108 /* its already registered! */
1109 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1111 return NT_STATUS_OBJECT_NAME_COLLISION;
1114 ep_servers = Realloc(ep_servers, sizeof(ep_servers[0]) * (num_ep_servers+1));
1116 smb_panic("out of memory in dcerpc_register");
1119 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1120 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1124 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1127 return NT_STATUS_OK;
1131 return the operations structure for a named backend of the specified type
1133 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1137 for (i=0;i<num_ep_servers;i++) {
1138 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1139 return ep_servers[i].ep_server;
1147 return the DCERPC module version, and the size of some critical types
1148 This can be used by endpoint server modules to either detect compilation errors, or provide
1149 multiple implementations for different smbd compilation options in one module
1151 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1153 static const struct dcesrv_critical_sizes critical_sizes = {
1154 DCERPC_MODULE_VERSION,
1155 sizeof(struct dcesrv_context),
1156 sizeof(struct dcesrv_endpoint),
1157 sizeof(struct dcesrv_endpoint_server),
1158 sizeof(struct dcesrv_interface),
1159 sizeof(struct dcesrv_if_list),
1160 sizeof(struct dcesrv_connection),
1161 sizeof(struct dcesrv_call_state),
1162 sizeof(struct dcesrv_auth),
1163 sizeof(struct dcesrv_handle)
1166 return &critical_sizes;
1170 initialise the DCERPC subsystem
1172 BOOL subsystem_dcerpc_init(void)
1176 status = register_subsystem("dcerpc", dcerpc_register_ep_server);
1177 if (!NT_STATUS_IS_OK(status)) {
1181 /* FIXME: Perhaps panic if a basic endpoint server, such as EPMAPER, fails to initialise? */
1184 DEBUG(3,("DCERPC subsystem version %d initialised\n", DCERPC_MODULE_VERSION));
1188 static const struct server_service_ops dcesrv_ops = {
1190 .service_init = dcesrv_init,
1191 .accept_connection = dcesrv_accept,
1192 .recv_handler = dcesrv_recv,
1193 .send_handler = dcesrv_send,
1194 .idle_handler = dcesrv_idle,
1195 .close_connection = dcesrv_close,
1196 .service_exit = dcesrv_exit,
1199 const struct server_service_ops *dcesrv_get_ops(void)
1204 NTSTATUS server_service_rpc_init(void)
1206 return NT_STATUS_OK;