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_oxidresolver.h"
27 #include "auth/auth.h"
28 #include "dlinklist.h"
29 #include "rpc_server/dcerpc_server.h"
32 see if two endpoints match
34 static BOOL endpoints_match(const struct dcerpc_binding *ep1,
35 const struct dcerpc_binding *ep2)
37 if (ep1->transport != ep2->transport) {
41 if (!ep1->endpoint || !ep2->endpoint) {
42 return ep1->endpoint == ep2->endpoint;
45 if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
52 find an endpoint in the dcesrv_context
54 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
55 const struct dcerpc_binding *ep_description)
57 struct dcesrv_endpoint *ep;
58 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
59 if (endpoints_match(&ep->ep_description, ep_description)) {
67 see if a uuid and if_version match to an interface
69 static BOOL interface_match(const struct dcesrv_interface *if1,
70 const struct dcesrv_interface *if2)
72 if (if1->ndr->if_version != if2->ndr->if_version) {
76 if (strcmp(if1->ndr->uuid, if2->ndr->uuid)==0) {
84 find the interface operations on an endpoint
86 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
87 const struct dcesrv_interface *iface)
89 struct dcesrv_if_list *ifl;
90 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
91 if (interface_match(&(ifl->iface), iface)) {
99 see if a uuid and if_version match to an interface
101 static BOOL interface_match_by_uuid(const struct dcesrv_interface *iface,
102 const char *uuid, uint32_t if_version)
104 if (iface->ndr->if_version != if_version) {
108 if (strcmp(iface->ndr->uuid, uuid)==0) {
116 find the interface operations on an endpoint by uuid
118 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
119 const char *uuid, uint32_t if_version)
121 struct dcesrv_if_list *ifl;
122 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
123 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
124 return &(ifl->iface);
131 find a call that is pending in our call list
133 static struct dcesrv_call_state *dcesrv_find_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
135 struct dcesrv_call_state *c;
136 for (c=dce_conn->call_list;c;c=c->next) {
137 if (c->pkt.call_id == call_id) {
145 register an interface on an endpoint
147 NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
149 const struct dcesrv_interface *iface,
150 const struct security_descriptor *sd)
152 struct dcesrv_endpoint *ep;
153 struct dcesrv_if_list *ifl;
154 struct dcerpc_binding binding;
158 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
160 if (NT_STATUS_IS_ERR(status)) {
161 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
165 /* check if this endpoint exists
167 if ((ep=find_endpoint(dce_ctx, &binding))==NULL) {
168 ep = talloc_p(dce_ctx, struct dcesrv_endpoint);
170 return NT_STATUS_NO_MEMORY;
173 ep->ep_description = binding;
177 /* see if the interface is already registered on te endpoint */
178 if (find_interface(ep, iface)!=NULL) {
179 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
180 iface->ndr->name, ep_name));
181 return NT_STATUS_OBJECT_NAME_COLLISION;
184 /* talloc a new interface list element */
185 ifl = talloc_p(dce_ctx, struct dcesrv_if_list);
187 return NT_STATUS_NO_MEMORY;
190 /* copy the given interface struct to the one on the endpoints interface list */
191 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
193 /* if we have a security descriptor given,
194 * we should see if we can set it up on the endpoint
197 /* if there's currently no security descriptor given on the endpoint
200 if (ep->sd == NULL) {
201 ep->sd = copy_security_descriptor(dce_ctx, sd);
204 /* if now there's no security descriptor given on the endpoint
205 * something goes wrong, either we failed to copy the security descriptor
206 * or there was already one on the endpoint
208 if (ep->sd != NULL) {
209 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
210 " on endpoint '%s'\n",
211 iface->ndr->name, ep_name));
212 if (add_ep) free(ep);
214 return NT_STATUS_OBJECT_NAME_COLLISION;
218 /* finally add the interface on the endpoint */
219 DLIST_ADD(ep->interface_list, ifl);
221 /* if it's a new endpoint add it to the dcesrv_context */
223 DLIST_ADD(dce_ctx->endpoint_list, ep);
226 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
227 iface->ndr->name, ep_name));
232 static NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
233 DATA_BLOB *session_key)
235 if (p->auth_state.session_info->session_key.length) {
236 *session_key = p->auth_state.session_info->session_key;
239 return NT_STATUS_NO_USER_SESSION_KEY;
242 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
243 DATA_BLOB *session_key)
245 /* this took quite a few CPU cycles to find ... */
246 session_key->data = discard_const_p(char, "SystemLibraryDTC");
247 session_key->length = 16;
252 fetch the user session key - may be default (above) or the SMB session key
254 NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
255 DATA_BLOB *session_key)
257 return p->auth_state.session_key(p, session_key);
262 destroy a link to an endpoint
264 static int dcesrv_endpoint_destructor(void *ptr)
266 struct dcesrv_connection *p = ptr;
268 p->iface->unbind(p, p->iface);
271 /* destroy any handles */
273 dcesrv_handle_destroy(p, p->handles);
276 if (p->auth_state.gensec_security) {
277 gensec_end(&p->auth_state.gensec_security);
285 connect to a dcerpc endpoint
287 NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
288 const struct dcesrv_endpoint *ep,
289 struct dcesrv_connection **p)
291 *p = talloc_p(dce_ctx, struct dcesrv_connection);
293 return NT_STATUS_NO_MEMORY;
296 (*p)->dce_ctx = dce_ctx;
299 (*p)->private = NULL;
300 (*p)->call_list = NULL;
301 (*p)->cli_max_recv_frag = 0;
302 (*p)->handles = NULL;
303 (*p)->partial_input = data_blob(NULL, 0);
304 (*p)->auth_state.auth_info = NULL;
305 (*p)->auth_state.gensec_security = NULL;
306 (*p)->auth_state.session_info = NULL;
307 (*p)->auth_state.session_key = dcesrv_generic_session_key;
308 (*p)->srv_conn = NULL;
310 talloc_set_destructor(*p, dcesrv_endpoint_destructor);
316 search and connect to a dcerpc endpoint
318 NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
319 const struct dcerpc_binding *ep_description,
320 struct auth_session_info *session_info,
321 struct dcesrv_connection **dce_conn_p)
324 const struct dcesrv_endpoint *ep;
326 /* make sure this endpoint exists */
327 ep = find_endpoint(dce_ctx, ep_description);
329 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
332 status = dcesrv_endpoint_connect(dce_ctx, ep, dce_conn_p);
333 if (!NT_STATUS_IS_OK(status)) {
337 session_info->refcount++;
338 (*dce_conn_p)->auth_state.session_info = session_info;
339 (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
341 /* TODO: check security descriptor of the endpoint here
342 * if it's a smb named pipe
343 * if it's failed free dce_conn_p
350 static void dcesrv_init_hdr(struct dcerpc_packet *pkt)
353 pkt->rpc_vers_minor = 0;
354 if (lp_rpc_big_endian()) {
357 pkt->drep[0] = DCERPC_DREP_LE;
365 return a dcerpc fault
367 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
369 struct dcerpc_packet pkt;
370 struct dcesrv_call_reply *rep;
373 /* setup a bind_ack */
374 dcesrv_init_hdr(&pkt);
376 pkt.call_id = call->pkt.call_id;
377 pkt.ptype = DCERPC_PKT_FAULT;
378 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
379 pkt.u.fault.alloc_hint = 0;
380 pkt.u.fault.context_id = 0;
381 pkt.u.fault.cancel_count = 0;
382 pkt.u.fault.status = fault_code;
384 rep = talloc_p(call, struct dcesrv_call_reply);
386 return NT_STATUS_NO_MEMORY;
389 status = dcerpc_push_auth(&rep->data, call, &pkt, NULL);
390 if (!NT_STATUS_IS_OK(status)) {
394 dcerpc_set_frag_length(&rep->data, rep->data.length);
396 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
397 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
404 return a dcerpc bind_nak
406 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
408 struct dcerpc_packet pkt;
409 struct dcesrv_call_reply *rep;
412 /* setup a bind_nak */
413 dcesrv_init_hdr(&pkt);
415 pkt.call_id = call->pkt.call_id;
416 pkt.ptype = DCERPC_PKT_BIND_NAK;
417 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
418 pkt.u.bind_nak.reject_reason = reason;
419 pkt.u.bind_nak.num_versions = 0;
421 rep = talloc_p(call, struct dcesrv_call_reply);
423 return NT_STATUS_NO_MEMORY;
426 status = dcerpc_push_auth(&rep->data, call, &pkt, NULL);
427 if (!NT_STATUS_IS_OK(status)) {
431 dcerpc_set_frag_length(&rep->data, rep->data.length);
433 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
434 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
441 handle a bind request
443 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
445 const char *uuid, *transfer_syntax;
446 uint32_t if_version, transfer_syntax_version;
447 struct dcerpc_packet pkt;
448 struct dcesrv_call_reply *rep;
450 uint32_t result=0, reason=0;
452 if (call->pkt.u.bind.num_contexts != 1 ||
453 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
454 return dcesrv_bind_nak(call, 0);
457 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
458 uuid = GUID_string(call, &call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid);
460 return dcesrv_bind_nak(call, 0);
463 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
464 transfer_syntax = GUID_string(call,
465 &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid);
466 if (!transfer_syntax ||
467 strcasecmp(NDR_GUID, transfer_syntax) != 0 ||
468 NDR_GUID_VERSION != transfer_syntax_version) {
469 /* we only do NDR encoded dcerpc */
470 return dcesrv_bind_nak(call, 0);
473 call->conn->iface = find_interface_by_uuid(call->conn->endpoint, uuid, if_version);
474 if (!call->conn->iface) {
475 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
476 /* we don't know about that interface */
477 result = DCERPC_BIND_PROVIDER_REJECT;
478 reason = DCERPC_BIND_REASON_ASYNTAX;
481 if (call->conn->cli_max_recv_frag == 0) {
482 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
485 /* handle any authentication that is being requested */
486 if (!dcesrv_auth_bind(call)) {
487 /* TODO: work out the right reject code */
488 return dcesrv_bind_nak(call, 0);
491 /* setup a bind_ack */
492 dcesrv_init_hdr(&pkt);
494 pkt.call_id = call->pkt.call_id;
495 pkt.ptype = DCERPC_PKT_BIND_ACK;
496 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
497 pkt.u.bind_ack.max_xmit_frag = 0x2000;
498 pkt.u.bind_ack.max_recv_frag = 0x2000;
499 pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
500 if (call->conn->iface && call->conn->iface->ndr) {
501 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
502 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s",
503 call->conn->iface->ndr->name);
505 pkt.u.bind_ack.secondary_address = "";
507 pkt.u.bind_ack.num_results = 1;
508 pkt.u.bind_ack.ctx_list = talloc_p(call, struct dcerpc_ack_ctx);
509 if (!pkt.u.bind_ack.ctx_list) {
510 return NT_STATUS_NO_MEMORY;
512 pkt.u.bind_ack.ctx_list[0].result = result;
513 pkt.u.bind_ack.ctx_list[0].reason = reason;
514 GUID_from_string(NDR_GUID, &pkt.u.bind_ack.ctx_list[0].syntax.uuid);
515 pkt.u.bind_ack.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
516 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
518 if (!dcesrv_auth_bind_ack(call, &pkt)) {
519 return dcesrv_bind_nak(call, 0);
522 if (call->conn->iface) {
523 status = call->conn->iface->bind(call, call->conn->iface);
524 if (!NT_STATUS_IS_OK(status)) {
525 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n", uuid, if_version, nt_errstr(status)));
526 return dcesrv_bind_nak(call, 0);
530 rep = talloc_p(call, struct dcesrv_call_reply);
532 return NT_STATUS_NO_MEMORY;
535 status = dcerpc_push_auth(&rep->data, call, &pkt,
536 call->conn->auth_state.auth_info);
537 if (!NT_STATUS_IS_OK(status)) {
541 dcerpc_set_frag_length(&rep->data, rep->data.length);
543 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
544 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
551 handle a auth3 request
553 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
555 /* handle the auth3 in the auth code */
556 if (!dcesrv_auth_auth3(call)) {
557 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
562 /* we don't send a reply to a auth3 request, except by a
569 handle a dcerpc request packet
571 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
573 struct ndr_pull *pull;
574 struct ndr_push *push;
579 uint32_t total_length;
582 if (!call->conn->iface) {
583 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
586 opnum = call->pkt.u.request.opnum;
588 if (opnum >= call->conn->iface->ndr->num_calls) {
589 return dcesrv_fault(call, DCERPC_FAULT_OP_RNG_ERROR);
592 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
594 return NT_STATUS_NO_MEMORY;
597 r = talloc(call, call->conn->iface->ndr->calls[opnum].struct_size);
599 return NT_STATUS_NO_MEMORY;
602 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
603 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
606 /* unravel the NDR for the packet */
607 status = call->conn->iface->ndr->calls[opnum].ndr_pull(pull, NDR_IN, r);
608 if (!NT_STATUS_IS_OK(status)) {
609 dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN,
610 &call->pkt.u.request.stub_and_verifier);
611 return dcesrv_fault(call, DCERPC_FAULT_NDR);
614 if (pull->offset != pull->data_size) {
615 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
616 pull->data_size - pull->offset));
617 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
620 call->fault_code = 0;
622 /* call the dispatch function */
623 status = call->conn->iface->dispatch(call, call, r);
624 if (!NT_STATUS_IS_OK(status)) {
625 dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN,
626 &call->pkt.u.request.stub_and_verifier);
627 return dcesrv_fault(call, call->fault_code);
630 /* form the reply NDR */
631 push = ndr_push_init_ctx(call);
633 return NT_STATUS_NO_MEMORY;
636 /* carry over the pointer count to the reply in case we are
637 using full pointer. See NDR specification for full
639 push->ptr_count = pull->ptr_count;
641 if (lp_rpc_big_endian()) {
642 push->flags |= LIBNDR_FLAG_BIGENDIAN;
645 status = call->conn->iface->ndr->calls[opnum].ndr_push(push, NDR_OUT, r);
646 if (!NT_STATUS_IS_OK(status)) {
647 return dcesrv_fault(call, DCERPC_FAULT_NDR);
650 stub = ndr_push_blob(push);
652 total_length = stub.length;
656 struct dcesrv_call_reply *rep;
657 struct dcerpc_packet pkt;
659 rep = talloc_p(call, struct dcesrv_call_reply);
661 return NT_STATUS_NO_MEMORY;
664 length = stub.length;
665 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
666 /* the 32 is to cope with signing data */
667 length = call->conn->cli_max_recv_frag -
668 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
671 /* form the dcerpc response packet */
672 dcesrv_init_hdr(&pkt);
674 pkt.call_id = call->pkt.call_id;
675 pkt.ptype = DCERPC_PKT_RESPONSE;
677 if (stub.length == total_length) {
678 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
680 if (length == stub.length) {
681 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
683 pkt.u.response.alloc_hint = stub.length;
684 pkt.u.response.context_id = call->pkt.u.request.context_id;
685 pkt.u.response.cancel_count = 0;
686 pkt.u.response.stub_and_verifier.data = stub.data;
687 pkt.u.response.stub_and_verifier.length = length;
689 if (!dcesrv_auth_response(call, &rep->data, &pkt)) {
690 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
693 dcerpc_set_frag_length(&rep->data, rep->data.length);
695 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
698 stub.length -= length;
699 } while (stub.length != 0);
701 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
708 work out if we have a full packet yet
710 static BOOL dce_full_packet(const DATA_BLOB *data)
712 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
715 if (dcerpc_get_frag_length(data) > data->length) {
722 we might have consumed only part of our input - advance past that part
724 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
728 if (dce_conn->partial_input.length == offset) {
729 data_blob_free(&dce_conn->partial_input);
733 blob = dce_conn->partial_input;
734 dce_conn->partial_input = data_blob(blob.data + offset,
735 blob.length - offset);
736 data_blob_free(&blob);
740 process some input to a dcerpc endpoint server.
742 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
744 struct ndr_pull *ndr;
746 struct dcesrv_call_state *call;
749 call = talloc_p(dce_conn, struct dcesrv_call_state);
751 talloc_free(dce_conn->partial_input.data);
752 return NT_STATUS_NO_MEMORY;
754 call->conn = dce_conn;
755 call->replies = NULL;
757 blob = dce_conn->partial_input;
758 blob.length = dcerpc_get_frag_length(&blob);
760 ndr = ndr_pull_init_blob(&blob, call);
762 talloc_free(dce_conn->partial_input.data);
764 return NT_STATUS_NO_MEMORY;
767 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
768 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
771 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
772 if (!NT_STATUS_IS_OK(status)) {
773 talloc_free(dce_conn->partial_input.data);
778 /* we have to check the signing here, before combining the
780 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
781 !dcesrv_auth_request(call, &blob)) {
782 dce_partial_advance(dce_conn, blob.length);
783 return dcesrv_fault(call, DCERPC_FAULT_LOGON_FAILURE);
786 dce_partial_advance(dce_conn, blob.length);
788 /* see if this is a continued packet */
789 if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
790 struct dcesrv_call_state *call2 = call;
793 /* we only allow fragmented requests, no other packet types */
794 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
795 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
798 /* this is a continuation of an existing call - find the call then
799 tack it on the end */
800 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
802 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
805 if (call->pkt.ptype != call2->pkt.ptype) {
806 /* trying to play silly buggers are we? */
807 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
810 alloc_size = call->pkt.u.request.stub_and_verifier.length +
811 call2->pkt.u.request.stub_and_verifier.length;
812 if (call->pkt.u.request.alloc_hint > alloc_size) {
813 alloc_size = call->pkt.u.request.alloc_hint;
816 call->pkt.u.request.stub_and_verifier.data =
817 talloc_realloc(call, call->pkt.u.request.stub_and_verifier.data, alloc_size);
818 if (!call->pkt.u.request.stub_and_verifier.data) {
819 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
821 memcpy(call->pkt.u.request.stub_and_verifier.data +
822 call->pkt.u.request.stub_and_verifier.length,
823 call2->pkt.u.request.stub_and_verifier.data,
824 call2->pkt.u.request.stub_and_verifier.length);
825 call->pkt.u.request.stub_and_verifier.length +=
826 call2->pkt.u.request.stub_and_verifier.length;
828 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
833 /* this may not be the last pdu in the chain - if its isn't then
834 just put it on the call_list and wait for the rest */
835 if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
836 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
840 switch (call->pkt.ptype) {
841 case DCERPC_PKT_BIND:
842 status = dcesrv_bind(call);
844 case DCERPC_PKT_AUTH3:
845 status = dcesrv_auth3(call);
847 case DCERPC_PKT_REQUEST:
848 status = dcesrv_request(call);
851 status = NT_STATUS_INVALID_PARAMETER;
855 /* if we are going to be sending a reply then add
856 it to the list of pending calls. We add it to the end to keep the call
857 list in the order we will answer */
858 if (!NT_STATUS_IS_OK(status)) {
867 provide some input to a dcerpc endpoint server. This passes data
868 from a dcerpc client into the server
870 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
874 dce_conn->partial_input.data = talloc_realloc(dce_conn,
875 dce_conn->partial_input.data,
876 dce_conn->partial_input.length + data->length);
877 if (!dce_conn->partial_input.data) {
878 return NT_STATUS_NO_MEMORY;
880 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
881 data->data, data->length);
882 dce_conn->partial_input.length += data->length;
884 while (dce_full_packet(&dce_conn->partial_input)) {
885 status = dcesrv_input_process(dce_conn);
886 if (!NT_STATUS_IS_OK(status)) {
895 retrieve some output from a dcerpc server
896 The caller supplies a function that will be called to do the
899 The first argument to write_fn() will be 'private', the second will
900 be a pointer to a buffer containing the data to be sent and the 3rd
901 will be the number of bytes to be sent.
903 write_fn() should return the number of bytes successfully written.
905 this will return STATUS_BUFFER_OVERFLOW if there is more to be read
906 from the current fragment
908 NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
910 ssize_t (*write_fn)(void *, DATA_BLOB *))
912 struct dcesrv_call_state *call;
913 struct dcesrv_call_reply *rep;
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);
937 if (call->replies == NULL) {
938 /* we're done with the whole call */
939 DLIST_REMOVE(dce_conn->call_list, call);
948 write_fn() for dcesrv_output_blob()
950 static ssize_t dcesrv_output_blob_write_fn(void *private, DATA_BLOB *out)
952 DATA_BLOB *blob = private;
953 if (out->length < blob->length) {
954 blob->length = out->length;
956 memcpy(blob->data, out->data, blob->length);
961 a simple wrapper for dcesrv_output() for when we want to output
964 NTSTATUS dcesrv_output_blob(struct dcesrv_connection *dce_conn,
967 return dcesrv_output(dce_conn, blob, dcesrv_output_blob_write_fn);
971 initialise the dcerpc server context
973 NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **dce_ctx)
976 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
978 (*dce_ctx) = talloc_p(mem_ctx, struct dcesrv_context);
980 return NT_STATUS_NO_MEMORY;
983 (*dce_ctx)->endpoint_list = NULL;
985 if (!endpoint_servers) {
986 DEBUG(3,("dcesrv_init_context: no endpoint servers configured\n"));
990 for (i=0;endpoint_servers[i];i++) {
992 const struct dcesrv_endpoint_server *ep_server;
994 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
996 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
997 return NT_STATUS_UNSUCCESSFUL;
1000 ret = ep_server->init_server(*dce_ctx, ep_server);
1001 if (!NT_STATUS_IS_OK(ret)) {
1002 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1007 return NT_STATUS_OK;
1010 static void dcesrv_init(struct server_service *service, const struct model_ops *model_ops)
1012 struct dcesrv_context *dce_ctx;
1014 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
1016 DEBUG(1,("dcesrv_init\n"));
1018 if (!endpoint_servers) {
1019 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1023 dce_ctx = talloc_p(service, struct dcesrv_context);
1025 DEBUG(0,("talloc_p(mem_ctx, struct dcesrv_context) failed\n"));
1029 ZERO_STRUCTP(dce_ctx);
1030 dce_ctx->endpoint_list = NULL;
1032 for (i=0;endpoint_servers[i];i++) {
1034 const struct dcesrv_endpoint_server *ep_server;
1036 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1038 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1042 ret = ep_server->init_server(dce_ctx, ep_server);
1043 if (!NT_STATUS_IS_OK(ret)) {
1044 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1049 dcesrv_sock_init(service, model_ops, dce_ctx);
1054 static void dcesrv_accept(struct server_connection *srv_conn)
1056 dcesrv_sock_accept(srv_conn);
1059 static void dcesrv_recv(struct server_connection *srv_conn, time_t t, uint16_t flags)
1061 dcesrv_sock_recv(srv_conn, t, flags);
1064 static void dcesrv_send(struct server_connection *srv_conn, time_t t, uint16_t flags)
1066 dcesrv_sock_send(srv_conn, t, flags);
1069 static void dcesrv_idle(struct server_connection *srv_conn, time_t t)
1071 dcesrv_sock_idle(srv_conn, t);
1074 static void dcesrv_close(struct server_connection *srv_conn, const char *reason)
1076 dcesrv_sock_close(srv_conn, reason);
1080 static void dcesrv_exit(struct server_service *service, const char *reason)
1082 dcesrv_sock_exit(service, reason);
1086 /* the list of currently registered DCERPC endpoint servers.
1089 struct dcesrv_endpoint_server *ep_server;
1090 } *ep_servers = NULL;
1091 static int num_ep_servers;
1094 register a DCERPC endpoint server.
1096 The 'name' can be later used by other backends to find the operations
1097 structure for this backend.
1099 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1101 static NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1103 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1105 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1106 /* its already registered! */
1107 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1109 return NT_STATUS_OBJECT_NAME_COLLISION;
1112 ep_servers = Realloc(ep_servers, sizeof(ep_servers[0]) * (num_ep_servers+1));
1114 smb_panic("out of memory in dcerpc_register");
1117 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1118 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1122 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1125 return NT_STATUS_OK;
1129 return the operations structure for a named backend of the specified type
1131 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1135 for (i=0;i<num_ep_servers;i++) {
1136 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1137 return ep_servers[i].ep_server;
1145 return the DCERPC module version, and the size of some critical types
1146 This can be used by endpoint server modules to either detect compilation errors, or provide
1147 multiple implementations for different smbd compilation options in one module
1149 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1151 static const struct dcesrv_critical_sizes critical_sizes = {
1152 DCERPC_MODULE_VERSION,
1153 sizeof(struct dcesrv_context),
1154 sizeof(struct dcesrv_endpoint),
1155 sizeof(struct dcesrv_endpoint_server),
1156 sizeof(struct dcesrv_interface),
1157 sizeof(struct dcesrv_if_list),
1158 sizeof(struct dcesrv_connection),
1159 sizeof(struct dcesrv_call_state),
1160 sizeof(struct dcesrv_auth),
1161 sizeof(struct dcesrv_handle)
1164 return &critical_sizes;
1168 initialise the DCERPC subsystem
1170 BOOL subsystem_dcerpc_init(void)
1174 status = register_subsystem("dcerpc", dcerpc_register_ep_server);
1175 if (!NT_STATUS_IS_OK(status)) {
1179 /* FIXME: Perhaps panic if a basic endpoint server, such as EPMAPPER, fails to initialise? */
1182 DEBUG(3,("DCERPC subsystem version %d initialised\n", DCERPC_MODULE_VERSION));
1186 static const struct server_service_ops dcesrv_ops = {
1188 .service_init = dcesrv_init,
1189 .accept_connection = dcesrv_accept,
1190 .recv_handler = dcesrv_recv,
1191 .send_handler = dcesrv_send,
1192 .idle_handler = dcesrv_idle,
1193 .close_connection = dcesrv_close,
1194 .service_exit = dcesrv_exit,
1197 const struct server_service_ops *dcesrv_get_ops(void)
1202 NTSTATUS server_service_rpc_init(void)
1204 return NT_STATUS_OK;