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.
25 #include "librpc/gen_ndr/ndr_epmapper.h"
26 #include "librpc/gen_ndr/ndr_dcom.h"
27 #include "librpc/gen_ndr/ndr_oxidresolver.h"
30 see if two endpoints match
32 static BOOL endpoints_match(const struct dcerpc_binding *ep1,
33 const struct dcerpc_binding *ep2)
35 if (ep1->transport != ep2->transport) {
39 if (!ep1->endpoint || !ep2->endpoint) {
40 return ep1->endpoint == ep2->endpoint;
43 if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
50 find an endpoint in the dcesrv_context
52 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
53 const struct dcerpc_binding *ep_description)
55 struct dcesrv_endpoint *ep;
56 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
57 if (endpoints_match(&ep->ep_description, ep_description)) {
65 see if a uuid and if_version match to an interface
67 static BOOL interface_match(const struct dcesrv_interface *if1,
68 const struct dcesrv_interface *if2)
70 if (if1->ndr->if_version != if2->ndr->if_version) {
74 if (strcmp(if1->ndr->uuid, if2->ndr->uuid)==0) {
82 find the interface operations on an endpoint
84 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
85 const struct dcesrv_interface *iface)
87 struct dcesrv_if_list *ifl;
88 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
89 if (interface_match(&(ifl->iface), iface)) {
97 see if a uuid and if_version match to an interface
99 static BOOL interface_match_by_uuid(const struct dcesrv_interface *iface,
100 const char *uuid, uint32_t if_version)
102 if (iface->ndr->if_version != if_version) {
106 if (strcmp(iface->ndr->uuid, uuid)==0) {
114 find the interface operations on an endpoint by uuid
116 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
117 const char *uuid, uint32_t if_version)
119 struct dcesrv_if_list *ifl;
120 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
121 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
122 return &(ifl->iface);
129 find a call that is pending in our call list
131 static struct dcesrv_call_state *dcesrv_find_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
133 struct dcesrv_call_state *c;
134 for (c=dce_conn->call_list;c;c=c->next) {
135 if (c->pkt.call_id == call_id) {
143 register an interface on an endpoint
145 NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
147 const struct dcesrv_interface *iface,
148 const struct security_descriptor *sd)
150 struct dcesrv_endpoint *ep;
151 struct dcesrv_if_list *ifl;
152 struct dcerpc_binding binding;
156 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
158 if (NT_STATUS_IS_ERR(status)) {
159 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
163 /* check if this endpoint exists
165 if ((ep=find_endpoint(dce_ctx, &binding))==NULL) {
166 ep = talloc_p(dce_ctx, struct dcesrv_endpoint);
168 return NT_STATUS_NO_MEMORY;
171 ep->ep_description = binding;
175 /* see if the interface is already registered on te endpoint */
176 if (find_interface(ep, iface)!=NULL) {
177 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
178 iface->ndr->name, ep_name));
179 return NT_STATUS_OBJECT_NAME_COLLISION;
182 /* talloc a new interface list element */
183 ifl = talloc_p(dce_ctx, struct dcesrv_if_list);
185 return NT_STATUS_NO_MEMORY;
188 /* copy the given interface struct to the one on the endpoints interface list */
189 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
191 /* if we have a security descriptor given,
192 * we should see if we can set it up on the endpoint
195 /* if there's currently no security descriptor given on the endpoint
198 if (ep->sd == NULL) {
199 ep->sd = copy_security_descriptor(dce_ctx, sd);
202 /* if now there's no security descriptor given on the endpoint
203 * something goes wrong, either we failed to copy the security descriptor
204 * or there was already one on the endpoint
206 if (ep->sd != NULL) {
207 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
208 " on endpoint '%s'\n",
209 iface->ndr->name, ep_name));
210 if (add_ep) free(ep);
212 return NT_STATUS_OBJECT_NAME_COLLISION;
216 /* finally add the interface on the endpoint */
217 DLIST_ADD(ep->interface_list, ifl);
219 /* if it's a new endpoint add it to the dcesrv_context */
221 DLIST_ADD(dce_ctx->endpoint_list, ep);
224 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
225 iface->ndr->name, ep_name));
230 static NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
231 DATA_BLOB *session_key)
233 if (p->auth_state.session_info->session_key.length) {
234 *session_key = p->auth_state.session_info->session_key;
237 return NT_STATUS_NO_USER_SESSION_KEY;
240 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
241 DATA_BLOB *session_key)
243 /* this took quite a few CPU cycles to find ... */
244 session_key->data = discard_const_p(char, "SystemLibraryDTC");
245 session_key->length = 16;
250 fetch the user session key - may be default (above) or the SMB session key
252 NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
253 DATA_BLOB *session_key)
255 return p->auth_state.session_key(p, session_key);
260 destroy a link to an endpoint
262 static int dcesrv_endpoint_destructor(void *ptr)
264 struct dcesrv_connection *p = ptr;
266 p->iface->unbind(p, p->iface);
269 /* destroy any handles */
271 dcesrv_handle_destroy(p, p->handles);
274 if (p->auth_state.gensec_security) {
275 gensec_end(&p->auth_state.gensec_security);
283 connect to a dcerpc endpoint
285 NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
286 const struct dcesrv_endpoint *ep,
287 struct dcesrv_connection **p)
289 *p = talloc_p(dce_ctx, struct dcesrv_connection);
291 return NT_STATUS_NO_MEMORY;
294 (*p)->dce_ctx = dce_ctx;
297 (*p)->private = NULL;
298 (*p)->call_list = NULL;
299 (*p)->cli_max_recv_frag = 0;
300 (*p)->handles = NULL;
301 (*p)->partial_input = data_blob(NULL, 0);
302 (*p)->auth_state.auth_info = NULL;
303 (*p)->auth_state.gensec_security = NULL;
304 (*p)->auth_state.session_info = NULL;
305 (*p)->auth_state.session_key = dcesrv_generic_session_key;
306 (*p)->srv_conn = NULL;
308 talloc_set_destructor(*p, dcesrv_endpoint_destructor);
314 search and connect to a dcerpc endpoint
316 NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
317 const struct dcerpc_binding *ep_description,
318 struct auth_session_info *session_info,
319 struct dcesrv_connection **dce_conn_p)
322 const struct dcesrv_endpoint *ep;
324 /* make sure this endpoint exists */
325 ep = find_endpoint(dce_ctx, ep_description);
327 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
330 status = dcesrv_endpoint_connect(dce_ctx, ep, dce_conn_p);
331 if (!NT_STATUS_IS_OK(status)) {
335 session_info->refcount++;
336 (*dce_conn_p)->auth_state.session_info = session_info;
337 (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
339 /* TODO: check security descriptor of the endpoint here
340 * if it's a smb named pipe
341 * if it's failed free dce_conn_p
348 static void dcesrv_init_hdr(struct dcerpc_packet *pkt)
351 pkt->rpc_vers_minor = 0;
352 if (lp_rpc_big_endian()) {
355 pkt->drep[0] = DCERPC_DREP_LE;
363 return a dcerpc fault
365 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
367 struct dcerpc_packet pkt;
368 struct dcesrv_call_reply *rep;
371 /* setup a bind_ack */
372 dcesrv_init_hdr(&pkt);
374 pkt.call_id = call->pkt.call_id;
375 pkt.ptype = DCERPC_PKT_FAULT;
376 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
377 pkt.u.fault.alloc_hint = 0;
378 pkt.u.fault.context_id = 0;
379 pkt.u.fault.cancel_count = 0;
380 pkt.u.fault.status = fault_code;
382 rep = talloc_p(call, struct dcesrv_call_reply);
384 return NT_STATUS_NO_MEMORY;
387 status = dcerpc_push_auth(&rep->data, call, &pkt, NULL);
388 if (!NT_STATUS_IS_OK(status)) {
392 dcerpc_set_frag_length(&rep->data, rep->data.length);
394 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
395 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
402 return a dcerpc bind_nak
404 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
406 struct dcerpc_packet pkt;
407 struct dcesrv_call_reply *rep;
410 /* setup a bind_nak */
411 dcesrv_init_hdr(&pkt);
413 pkt.call_id = call->pkt.call_id;
414 pkt.ptype = DCERPC_PKT_BIND_NAK;
415 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
416 pkt.u.bind_nak.reject_reason = reason;
417 pkt.u.bind_nak.num_versions = 0;
419 rep = talloc_p(call, struct dcesrv_call_reply);
421 return NT_STATUS_NO_MEMORY;
424 status = dcerpc_push_auth(&rep->data, call, &pkt, NULL);
425 if (!NT_STATUS_IS_OK(status)) {
429 dcerpc_set_frag_length(&rep->data, rep->data.length);
431 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
432 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
439 handle a bind request
441 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
443 const char *uuid, *transfer_syntax;
444 uint32_t if_version, transfer_syntax_version;
445 struct dcerpc_packet pkt;
446 struct dcesrv_call_reply *rep;
448 uint32_t result=0, reason=0;
450 if (call->pkt.u.bind.num_contexts != 1 ||
451 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
452 return dcesrv_bind_nak(call, 0);
455 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
456 uuid = GUID_string(call, &call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid);
458 return dcesrv_bind_nak(call, 0);
461 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
462 transfer_syntax = GUID_string(call,
463 &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid);
464 if (!transfer_syntax ||
465 strcasecmp(NDR_GUID, transfer_syntax) != 0 ||
466 NDR_GUID_VERSION != transfer_syntax_version) {
467 /* we only do NDR encoded dcerpc */
468 return dcesrv_bind_nak(call, 0);
471 call->conn->iface = find_interface_by_uuid(call->conn->endpoint, uuid, if_version);
472 if (!call->conn->iface) {
473 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
474 /* we don't know about that interface */
475 result = DCERPC_BIND_PROVIDER_REJECT;
476 reason = DCERPC_BIND_REASON_ASYNTAX;
479 if (call->conn->cli_max_recv_frag == 0) {
480 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
483 /* handle any authentication that is being requested */
484 if (!dcesrv_auth_bind(call)) {
485 /* TODO: work out the right reject code */
486 return dcesrv_bind_nak(call, 0);
489 /* setup a bind_ack */
490 dcesrv_init_hdr(&pkt);
492 pkt.call_id = call->pkt.call_id;
493 pkt.ptype = DCERPC_PKT_BIND_ACK;
494 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
495 pkt.u.bind_ack.max_xmit_frag = 0x2000;
496 pkt.u.bind_ack.max_recv_frag = 0x2000;
497 pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
498 if (call->conn->iface && call->conn->iface->ndr) {
499 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
500 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s",
501 call->conn->iface->ndr->name);
503 pkt.u.bind_ack.secondary_address = "";
505 pkt.u.bind_ack.num_results = 1;
506 pkt.u.bind_ack.ctx_list = talloc_p(call, struct dcerpc_ack_ctx);
507 if (!pkt.u.bind_ack.ctx_list) {
508 return NT_STATUS_NO_MEMORY;
510 pkt.u.bind_ack.ctx_list[0].result = result;
511 pkt.u.bind_ack.ctx_list[0].reason = reason;
512 GUID_from_string(NDR_GUID, &pkt.u.bind_ack.ctx_list[0].syntax.uuid);
513 pkt.u.bind_ack.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
514 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
516 if (!dcesrv_auth_bind_ack(call, &pkt)) {
517 return dcesrv_bind_nak(call, 0);
520 if (call->conn->iface) {
521 status = call->conn->iface->bind(call, call->conn->iface);
522 if (!NT_STATUS_IS_OK(status)) {
523 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n", uuid, if_version, nt_errstr(status)));
524 return dcesrv_bind_nak(call, 0);
528 rep = talloc_p(call, struct dcesrv_call_reply);
530 return NT_STATUS_NO_MEMORY;
533 status = dcerpc_push_auth(&rep->data, call, &pkt,
534 call->conn->auth_state.auth_info);
535 if (!NT_STATUS_IS_OK(status)) {
539 dcerpc_set_frag_length(&rep->data, rep->data.length);
541 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
542 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
549 handle a auth3 request
551 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
553 /* handle the auth3 in the auth code */
554 if (!dcesrv_auth_auth3(call)) {
555 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
560 /* we don't send a reply to a auth3 request, except by a
567 handle a dcerpc request packet
569 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
571 struct ndr_pull *pull;
572 struct ndr_push *push;
577 uint32_t total_length;
580 if (!call->conn->iface) {
581 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
584 opnum = call->pkt.u.request.opnum;
586 if (opnum >= call->conn->iface->ndr->num_calls) {
587 return dcesrv_fault(call, DCERPC_FAULT_OP_RNG_ERROR);
590 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
592 return NT_STATUS_NO_MEMORY;
595 r = talloc(call, call->conn->iface->ndr->calls[opnum].struct_size);
597 return NT_STATUS_NO_MEMORY;
600 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
601 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
604 /* unravel the NDR for the packet */
605 status = call->conn->iface->ndr->calls[opnum].ndr_pull(pull, NDR_IN, r);
606 if (!NT_STATUS_IS_OK(status)) {
607 dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN,
608 &call->pkt.u.request.stub_and_verifier);
609 return dcesrv_fault(call, DCERPC_FAULT_NDR);
612 if (pull->offset != pull->data_size) {
613 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
614 pull->data_size - pull->offset));
615 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
618 call->fault_code = 0;
620 /* call the dispatch function */
621 status = call->conn->iface->dispatch(call, call, r);
622 if (!NT_STATUS_IS_OK(status)) {
623 dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN,
624 &call->pkt.u.request.stub_and_verifier);
625 return dcesrv_fault(call, call->fault_code);
628 /* form the reply NDR */
629 push = ndr_push_init_ctx(call);
631 return NT_STATUS_NO_MEMORY;
634 /* carry over the pointer count to the reply in case we are
635 using full pointer. See NDR specification for full
637 push->ptr_count = pull->ptr_count;
639 if (lp_rpc_big_endian()) {
640 push->flags |= LIBNDR_FLAG_BIGENDIAN;
643 status = call->conn->iface->ndr->calls[opnum].ndr_push(push, NDR_OUT, r);
644 if (!NT_STATUS_IS_OK(status)) {
645 return dcesrv_fault(call, DCERPC_FAULT_NDR);
648 stub = ndr_push_blob(push);
650 total_length = stub.length;
654 struct dcesrv_call_reply *rep;
655 struct dcerpc_packet pkt;
657 rep = talloc_p(call, struct dcesrv_call_reply);
659 return NT_STATUS_NO_MEMORY;
662 length = stub.length;
663 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
664 /* the 32 is to cope with signing data */
665 length = call->conn->cli_max_recv_frag -
666 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
669 /* form the dcerpc response packet */
670 dcesrv_init_hdr(&pkt);
672 pkt.call_id = call->pkt.call_id;
673 pkt.ptype = DCERPC_PKT_RESPONSE;
675 if (stub.length == total_length) {
676 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
678 if (length == stub.length) {
679 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
681 pkt.u.response.alloc_hint = stub.length;
682 pkt.u.response.context_id = call->pkt.u.request.context_id;
683 pkt.u.response.cancel_count = 0;
684 pkt.u.response.stub_and_verifier.data = stub.data;
685 pkt.u.response.stub_and_verifier.length = length;
687 if (!dcesrv_auth_response(call, &rep->data, &pkt)) {
688 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
691 dcerpc_set_frag_length(&rep->data, rep->data.length);
693 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
696 stub.length -= length;
697 } while (stub.length != 0);
699 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
706 work out if we have a full packet yet
708 static BOOL dce_full_packet(const DATA_BLOB *data)
710 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
713 if (dcerpc_get_frag_length(data) > data->length) {
720 we might have consumed only part of our input - advance past that part
722 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
726 if (dce_conn->partial_input.length == offset) {
727 data_blob_free(&dce_conn->partial_input);
731 blob = dce_conn->partial_input;
732 dce_conn->partial_input = data_blob(blob.data + offset,
733 blob.length - offset);
734 data_blob_free(&blob);
738 process some input to a dcerpc endpoint server.
740 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
742 struct ndr_pull *ndr;
744 struct dcesrv_call_state *call;
747 call = talloc_p(dce_conn, struct dcesrv_call_state);
749 talloc_free(dce_conn->partial_input.data);
750 return NT_STATUS_NO_MEMORY;
752 call->conn = dce_conn;
753 call->replies = NULL;
755 blob = dce_conn->partial_input;
756 blob.length = dcerpc_get_frag_length(&blob);
758 ndr = ndr_pull_init_blob(&blob, call);
760 talloc_free(dce_conn->partial_input.data);
762 return NT_STATUS_NO_MEMORY;
765 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
766 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
769 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
770 if (!NT_STATUS_IS_OK(status)) {
771 talloc_free(dce_conn->partial_input.data);
776 /* we have to check the signing here, before combining the
778 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
779 !dcesrv_auth_request(call, &blob)) {
780 dce_partial_advance(dce_conn, blob.length);
781 return dcesrv_fault(call, DCERPC_FAULT_LOGON_FAILURE);
784 dce_partial_advance(dce_conn, blob.length);
786 /* see if this is a continued packet */
787 if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
788 struct dcesrv_call_state *call2 = call;
791 /* we only allow fragmented requests, no other packet types */
792 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
793 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
796 /* this is a continuation of an existing call - find the call then
797 tack it on the end */
798 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
800 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
803 if (call->pkt.ptype != call2->pkt.ptype) {
804 /* trying to play silly buggers are we? */
805 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
808 alloc_size = call->pkt.u.request.stub_and_verifier.length +
809 call2->pkt.u.request.stub_and_verifier.length;
810 if (call->pkt.u.request.alloc_hint > alloc_size) {
811 alloc_size = call->pkt.u.request.alloc_hint;
814 call->pkt.u.request.stub_and_verifier.data =
815 talloc_realloc(call, call->pkt.u.request.stub_and_verifier.data, alloc_size);
816 if (!call->pkt.u.request.stub_and_verifier.data) {
817 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
819 memcpy(call->pkt.u.request.stub_and_verifier.data +
820 call->pkt.u.request.stub_and_verifier.length,
821 call2->pkt.u.request.stub_and_verifier.data,
822 call2->pkt.u.request.stub_and_verifier.length);
823 call->pkt.u.request.stub_and_verifier.length +=
824 call2->pkt.u.request.stub_and_verifier.length;
826 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
831 /* this may not be the last pdu in the chain - if its isn't then
832 just put it on the call_list and wait for the rest */
833 if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
834 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
838 switch (call->pkt.ptype) {
839 case DCERPC_PKT_BIND:
840 status = dcesrv_bind(call);
842 case DCERPC_PKT_AUTH3:
843 status = dcesrv_auth3(call);
845 case DCERPC_PKT_REQUEST:
846 status = dcesrv_request(call);
849 status = NT_STATUS_INVALID_PARAMETER;
853 /* if we are going to be sending a reply then add
854 it to the list of pending calls. We add it to the end to keep the call
855 list in the order we will answer */
856 if (!NT_STATUS_IS_OK(status)) {
865 provide some input to a dcerpc endpoint server. This passes data
866 from a dcerpc client into the server
868 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
872 dce_conn->partial_input.data = talloc_realloc(dce_conn,
873 dce_conn->partial_input.data,
874 dce_conn->partial_input.length + data->length);
875 if (!dce_conn->partial_input.data) {
876 return NT_STATUS_NO_MEMORY;
878 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
879 data->data, data->length);
880 dce_conn->partial_input.length += data->length;
882 while (dce_full_packet(&dce_conn->partial_input)) {
883 status = dcesrv_input_process(dce_conn);
884 if (!NT_STATUS_IS_OK(status)) {
893 retrieve some output from a dcerpc server
894 The caller supplies a function that will be called to do the
897 The first argument to write_fn() will be 'private', the second will
898 be a pointer to a buffer containing the data to be sent and the 3rd
899 will be the number of bytes to be sent.
901 write_fn() should return the number of bytes successfully written.
903 this will return STATUS_BUFFER_OVERFLOW if there is more to be read
904 from the current fragment
906 NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
908 ssize_t (*write_fn)(void *, DATA_BLOB *))
910 struct dcesrv_call_state *call;
911 struct dcesrv_call_reply *rep;
914 call = dce_conn->call_list;
915 if (!call || !call->replies) {
916 return NT_STATUS_FOOBAR;
920 nwritten = write_fn(private, &rep->data);
921 if (nwritten == -1) {
922 /* TODO: hmm, how do we cope with this? destroy the
923 connection perhaps? */
924 return NT_STATUS_UNSUCCESSFUL;
927 rep->data.length -= nwritten;
928 rep->data.data += nwritten;
930 if (rep->data.length == 0) {
931 /* we're done with this section of the call */
932 DLIST_REMOVE(call->replies, rep);
935 if (call->replies == NULL) {
936 /* we're done with the whole call */
937 DLIST_REMOVE(dce_conn->call_list, call);
946 write_fn() for dcesrv_output_blob()
948 static ssize_t dcesrv_output_blob_write_fn(void *private, DATA_BLOB *out)
950 DATA_BLOB *blob = private;
951 if (out->length < blob->length) {
952 blob->length = out->length;
954 memcpy(blob->data, out->data, blob->length);
959 a simple wrapper for dcesrv_output() for when we want to output
962 NTSTATUS dcesrv_output_blob(struct dcesrv_connection *dce_conn,
965 return dcesrv_output(dce_conn, blob, dcesrv_output_blob_write_fn);
969 initialise the dcerpc server context
971 NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **dce_ctx)
974 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
976 (*dce_ctx) = talloc_p(mem_ctx, struct dcesrv_context);
978 return NT_STATUS_NO_MEMORY;
981 (*dce_ctx)->endpoint_list = NULL;
983 if (!endpoint_servers) {
984 DEBUG(3,("dcesrv_init_context: no endpoint servers configured\n"));
988 for (i=0;endpoint_servers[i];i++) {
990 const struct dcesrv_endpoint_server *ep_server;
992 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
994 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
995 return NT_STATUS_UNSUCCESSFUL;
998 ret = ep_server->init_server(*dce_ctx, ep_server);
999 if (!NT_STATUS_IS_OK(ret)) {
1000 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1005 return NT_STATUS_OK;
1008 static void dcesrv_init(struct server_service *service, const struct model_ops *model_ops)
1010 struct dcesrv_context *dce_ctx;
1012 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
1014 DEBUG(1,("dcesrv_init\n"));
1016 if (!endpoint_servers) {
1017 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1021 dce_ctx = talloc_p(service, struct dcesrv_context);
1023 DEBUG(0,("talloc_p(mem_ctx, struct dcesrv_context) failed\n"));
1027 ZERO_STRUCTP(dce_ctx);
1028 dce_ctx->endpoint_list = NULL;
1030 for (i=0;endpoint_servers[i];i++) {
1032 const struct dcesrv_endpoint_server *ep_server;
1034 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1036 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1040 ret = ep_server->init_server(dce_ctx, ep_server);
1041 if (!NT_STATUS_IS_OK(ret)) {
1042 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1047 dcesrv_sock_init(service, model_ops, dce_ctx);
1052 static void dcesrv_accept(struct server_connection *srv_conn)
1054 dcesrv_sock_accept(srv_conn);
1057 static void dcesrv_recv(struct server_connection *srv_conn, time_t t, uint16_t flags)
1059 dcesrv_sock_recv(srv_conn, t, flags);
1062 static void dcesrv_send(struct server_connection *srv_conn, time_t t, uint16_t flags)
1064 dcesrv_sock_send(srv_conn, t, flags);
1067 static void dcesrv_idle(struct server_connection *srv_conn, time_t t)
1069 dcesrv_sock_idle(srv_conn, t);
1072 static void dcesrv_close(struct server_connection *srv_conn, const char *reason)
1074 dcesrv_sock_close(srv_conn, reason);
1078 static void dcesrv_exit(struct server_service *service, const char *reason)
1080 dcesrv_sock_exit(service, reason);
1084 /* the list of currently registered DCERPC endpoint servers.
1087 struct dcesrv_endpoint_server *ep_server;
1088 } *ep_servers = NULL;
1089 static int num_ep_servers;
1092 register a DCERPC endpoint server.
1094 The 'name' can be later used by other backends to find the operations
1095 structure for this backend.
1097 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1099 static NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1101 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1103 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1104 /* its already registered! */
1105 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1107 return NT_STATUS_OBJECT_NAME_COLLISION;
1110 ep_servers = Realloc(ep_servers, sizeof(ep_servers[0]) * (num_ep_servers+1));
1112 smb_panic("out of memory in dcerpc_register");
1115 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1116 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1120 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1123 return NT_STATUS_OK;
1127 return the operations structure for a named backend of the specified type
1129 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1133 for (i=0;i<num_ep_servers;i++) {
1134 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1135 return ep_servers[i].ep_server;
1143 return the DCERPC module version, and the size of some critical types
1144 This can be used by endpoint server modules to either detect compilation errors, or provide
1145 multiple implementations for different smbd compilation options in one module
1147 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1149 static const struct dcesrv_critical_sizes critical_sizes = {
1150 DCERPC_MODULE_VERSION,
1151 sizeof(struct dcesrv_context),
1152 sizeof(struct dcesrv_endpoint),
1153 sizeof(struct dcesrv_endpoint_server),
1154 sizeof(struct dcesrv_interface),
1155 sizeof(struct dcesrv_if_list),
1156 sizeof(struct dcesrv_connection),
1157 sizeof(struct dcesrv_call_state),
1158 sizeof(struct dcesrv_auth),
1159 sizeof(struct dcesrv_handle)
1162 return &critical_sizes;
1166 initialise the DCERPC subsystem
1168 BOOL subsystem_dcerpc_init(void)
1172 status = register_subsystem("dcerpc", dcerpc_register_ep_server);
1173 if (!NT_STATUS_IS_OK(status)) {
1177 /* FIXME: Perhaps panic if a basic endpoint server, such as EPMAPPER, fails to initialise? */
1180 DEBUG(3,("DCERPC subsystem version %d initialised\n", DCERPC_MODULE_VERSION));
1184 static const struct server_service_ops dcesrv_ops = {
1186 .service_init = dcesrv_init,
1187 .accept_connection = dcesrv_accept,
1188 .recv_handler = dcesrv_recv,
1189 .send_handler = dcesrv_send,
1190 .idle_handler = dcesrv_idle,
1191 .close_connection = dcesrv_close,
1192 .service_exit = dcesrv_exit,
1195 const struct server_service_ops *dcesrv_get_ops(void)
1200 NTSTATUS server_service_rpc_init(void)
1202 return NT_STATUS_OK;