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 = security_descriptor_copy(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(void, "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 if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_ORPC) {
598 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
601 r = talloc(call, call->conn->iface->ndr->calls[opnum].struct_size);
603 return NT_STATUS_NO_MEMORY;
606 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
607 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
610 /* unravel the NDR for the packet */
611 status = call->conn->iface->ndr->calls[opnum].ndr_pull(pull, NDR_IN, r);
612 if (!NT_STATUS_IS_OK(status)) {
613 dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN,
614 &call->pkt.u.request.stub_and_verifier);
615 return dcesrv_fault(call, DCERPC_FAULT_NDR);
618 if (pull->offset != pull->data_size) {
619 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
620 pull->data_size - pull->offset));
621 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
624 call->fault_code = 0;
626 /* call the dispatch function */
627 status = call->conn->iface->dispatch(call, call, r);
628 if (!NT_STATUS_IS_OK(status)) {
629 dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN,
630 &call->pkt.u.request.stub_and_verifier);
631 return dcesrv_fault(call, call->fault_code);
634 /* form the reply NDR */
635 push = ndr_push_init_ctx(call);
637 return NT_STATUS_NO_MEMORY;
640 /* carry over the pointer count to the reply in case we are
641 using full pointer. See NDR specification for full
643 push->ptr_count = pull->ptr_count;
645 if (lp_rpc_big_endian()) {
646 push->flags |= LIBNDR_FLAG_BIGENDIAN;
649 status = call->conn->iface->ndr->calls[opnum].ndr_push(push, NDR_OUT, r);
650 if (!NT_STATUS_IS_OK(status)) {
651 return dcesrv_fault(call, DCERPC_FAULT_NDR);
654 stub = ndr_push_blob(push);
656 total_length = stub.length;
660 struct dcesrv_call_reply *rep;
661 struct dcerpc_packet pkt;
663 rep = talloc_p(call, struct dcesrv_call_reply);
665 return NT_STATUS_NO_MEMORY;
668 length = stub.length;
669 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
670 /* the 32 is to cope with signing data */
671 length = call->conn->cli_max_recv_frag -
672 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
675 /* form the dcerpc response packet */
676 dcesrv_init_hdr(&pkt);
678 pkt.call_id = call->pkt.call_id;
679 pkt.ptype = DCERPC_PKT_RESPONSE;
681 if (stub.length == total_length) {
682 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
684 if (length == stub.length) {
685 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
687 pkt.u.response.alloc_hint = stub.length;
688 pkt.u.response.context_id = call->pkt.u.request.context_id;
689 pkt.u.response.cancel_count = 0;
690 pkt.u.response.stub_and_verifier.data = stub.data;
691 pkt.u.response.stub_and_verifier.length = length;
693 if (!dcesrv_auth_response(call, &rep->data, &pkt)) {
694 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
697 dcerpc_set_frag_length(&rep->data, rep->data.length);
699 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
702 stub.length -= length;
703 } while (stub.length != 0);
705 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
712 work out if we have a full packet yet
714 static BOOL dce_full_packet(const DATA_BLOB *data)
716 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
719 if (dcerpc_get_frag_length(data) > data->length) {
726 we might have consumed only part of our input - advance past that part
728 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
732 if (dce_conn->partial_input.length == offset) {
733 data_blob_free(&dce_conn->partial_input);
737 blob = dce_conn->partial_input;
738 dce_conn->partial_input = data_blob(blob.data + offset,
739 blob.length - offset);
740 data_blob_free(&blob);
744 process some input to a dcerpc endpoint server.
746 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
748 struct ndr_pull *ndr;
750 struct dcesrv_call_state *call;
753 call = talloc_p(dce_conn, struct dcesrv_call_state);
755 talloc_free(dce_conn->partial_input.data);
756 return NT_STATUS_NO_MEMORY;
758 call->conn = dce_conn;
759 call->replies = NULL;
761 blob = dce_conn->partial_input;
762 blob.length = dcerpc_get_frag_length(&blob);
764 ndr = ndr_pull_init_blob(&blob, call);
766 talloc_free(dce_conn->partial_input.data);
768 return NT_STATUS_NO_MEMORY;
771 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
772 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
775 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
776 if (!NT_STATUS_IS_OK(status)) {
777 talloc_free(dce_conn->partial_input.data);
782 /* we have to check the signing here, before combining the
784 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
785 !dcesrv_auth_request(call, &blob)) {
786 dce_partial_advance(dce_conn, blob.length);
787 return dcesrv_fault(call, DCERPC_FAULT_LOGON_FAILURE);
790 dce_partial_advance(dce_conn, blob.length);
792 /* see if this is a continued packet */
793 if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
794 struct dcesrv_call_state *call2 = call;
797 /* we only allow fragmented requests, no other packet types */
798 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
799 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
802 /* this is a continuation of an existing call - find the call then
803 tack it on the end */
804 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
806 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
809 if (call->pkt.ptype != call2->pkt.ptype) {
810 /* trying to play silly buggers are we? */
811 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
814 alloc_size = call->pkt.u.request.stub_and_verifier.length +
815 call2->pkt.u.request.stub_and_verifier.length;
816 if (call->pkt.u.request.alloc_hint > alloc_size) {
817 alloc_size = call->pkt.u.request.alloc_hint;
820 call->pkt.u.request.stub_and_verifier.data =
821 talloc_realloc(call, call->pkt.u.request.stub_and_verifier.data, alloc_size);
822 if (!call->pkt.u.request.stub_and_verifier.data) {
823 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
825 memcpy(call->pkt.u.request.stub_and_verifier.data +
826 call->pkt.u.request.stub_and_verifier.length,
827 call2->pkt.u.request.stub_and_verifier.data,
828 call2->pkt.u.request.stub_and_verifier.length);
829 call->pkt.u.request.stub_and_verifier.length +=
830 call2->pkt.u.request.stub_and_verifier.length;
832 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
837 /* this may not be the last pdu in the chain - if its isn't then
838 just put it on the call_list and wait for the rest */
839 if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
840 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
844 switch (call->pkt.ptype) {
845 case DCERPC_PKT_BIND:
846 status = dcesrv_bind(call);
848 case DCERPC_PKT_AUTH3:
849 status = dcesrv_auth3(call);
851 case DCERPC_PKT_REQUEST:
852 status = dcesrv_request(call);
855 status = NT_STATUS_INVALID_PARAMETER;
859 /* if we are going to be sending a reply then add
860 it to the list of pending calls. We add it to the end to keep the call
861 list in the order we will answer */
862 if (!NT_STATUS_IS_OK(status)) {
871 provide some input to a dcerpc endpoint server. This passes data
872 from a dcerpc client into the server
874 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
878 dce_conn->partial_input.data = talloc_realloc(dce_conn,
879 dce_conn->partial_input.data,
880 dce_conn->partial_input.length + data->length);
881 if (!dce_conn->partial_input.data) {
882 return NT_STATUS_NO_MEMORY;
884 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
885 data->data, data->length);
886 dce_conn->partial_input.length += data->length;
888 while (dce_full_packet(&dce_conn->partial_input)) {
889 status = dcesrv_input_process(dce_conn);
890 if (!NT_STATUS_IS_OK(status)) {
899 retrieve some output from a dcerpc server
900 The caller supplies a function that will be called to do the
903 The first argument to write_fn() will be 'private', the second will
904 be a pointer to a buffer containing the data to be sent and the 3rd
905 will be the number of bytes to be sent.
907 write_fn() should return the number of bytes successfully written.
909 this will return STATUS_BUFFER_OVERFLOW if there is more to be read
910 from the current fragment
912 NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
914 ssize_t (*write_fn)(void *, DATA_BLOB *))
916 struct dcesrv_call_state *call;
917 struct dcesrv_call_reply *rep;
920 call = dce_conn->call_list;
921 if (!call || !call->replies) {
922 return NT_STATUS_FOOBAR;
926 nwritten = write_fn(private, &rep->data);
927 if (nwritten == -1) {
928 /* TODO: hmm, how do we cope with this? destroy the
929 connection perhaps? */
930 return NT_STATUS_UNSUCCESSFUL;
933 rep->data.length -= nwritten;
934 rep->data.data += nwritten;
936 if (rep->data.length == 0) {
937 /* we're done with this section of the call */
938 DLIST_REMOVE(call->replies, rep);
941 if (call->replies == NULL) {
942 /* we're done with the whole call */
943 DLIST_REMOVE(dce_conn->call_list, call);
952 write_fn() for dcesrv_output_blob()
954 static ssize_t dcesrv_output_blob_write_fn(void *private, DATA_BLOB *out)
956 DATA_BLOB *blob = private;
957 if (out->length < blob->length) {
958 blob->length = out->length;
960 memcpy(blob->data, out->data, blob->length);
965 a simple wrapper for dcesrv_output() for when we want to output
968 NTSTATUS dcesrv_output_blob(struct dcesrv_connection *dce_conn,
971 return dcesrv_output(dce_conn, blob, dcesrv_output_blob_write_fn);
975 initialise the dcerpc server context
977 NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **dce_ctx)
980 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
982 (*dce_ctx) = talloc_p(mem_ctx, struct dcesrv_context);
984 return NT_STATUS_NO_MEMORY;
987 (*dce_ctx)->endpoint_list = NULL;
989 if (!endpoint_servers) {
990 DEBUG(3,("dcesrv_init_context: no endpoint servers configured\n"));
994 for (i=0;endpoint_servers[i];i++) {
996 const struct dcesrv_endpoint_server *ep_server;
998 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1000 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1001 return NT_STATUS_UNSUCCESSFUL;
1004 ret = ep_server->init_server(*dce_ctx, ep_server);
1005 if (!NT_STATUS_IS_OK(ret)) {
1006 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1011 return NT_STATUS_OK;
1014 static void dcesrv_init(struct server_service *service, const struct model_ops *model_ops)
1016 struct dcesrv_context *dce_ctx;
1018 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
1020 DEBUG(1,("dcesrv_init\n"));
1022 if (!endpoint_servers) {
1023 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1027 dce_ctx = talloc_p(service, struct dcesrv_context);
1029 DEBUG(0,("talloc_p(mem_ctx, struct dcesrv_context) failed\n"));
1033 ZERO_STRUCTP(dce_ctx);
1034 dce_ctx->endpoint_list = NULL;
1036 for (i=0;endpoint_servers[i];i++) {
1038 const struct dcesrv_endpoint_server *ep_server;
1040 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1042 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1046 ret = ep_server->init_server(dce_ctx, ep_server);
1047 if (!NT_STATUS_IS_OK(ret)) {
1048 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1053 dcesrv_sock_init(service, model_ops, dce_ctx);
1058 static void dcesrv_accept(struct server_connection *srv_conn)
1060 dcesrv_sock_accept(srv_conn);
1063 static void dcesrv_recv(struct server_connection *srv_conn,
1064 struct timeval t, uint16_t flags)
1066 dcesrv_sock_recv(srv_conn, t, flags);
1069 static void dcesrv_send(struct server_connection *srv_conn,
1070 struct timeval t, uint16_t flags)
1072 dcesrv_sock_send(srv_conn, t, flags);
1075 static void dcesrv_close(struct server_connection *srv_conn, const char *reason)
1077 dcesrv_sock_close(srv_conn, reason);
1081 static void dcesrv_exit(struct server_service *service, const char *reason)
1083 dcesrv_sock_exit(service, reason);
1087 /* the list of currently registered DCERPC endpoint servers.
1090 struct dcesrv_endpoint_server *ep_server;
1091 } *ep_servers = NULL;
1092 static int num_ep_servers;
1095 register a DCERPC endpoint server.
1097 The 'name' can be later used by other backends to find the operations
1098 structure for this backend.
1100 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1102 NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1104 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1106 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1107 /* its already registered! */
1108 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1110 return NT_STATUS_OBJECT_NAME_COLLISION;
1113 ep_servers = Realloc(ep_servers, sizeof(ep_servers[0]) * (num_ep_servers+1));
1115 smb_panic("out of memory in dcerpc_register");
1118 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1119 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1123 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1126 return NT_STATUS_OK;
1130 return the operations structure for a named backend of the specified type
1132 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1136 for (i=0;i<num_ep_servers;i++) {
1137 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1138 return ep_servers[i].ep_server;
1146 return the DCERPC module version, and the size of some critical types
1147 This can be used by endpoint server modules to either detect compilation errors, or provide
1148 multiple implementations for different smbd compilation options in one module
1150 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1152 static const struct dcesrv_critical_sizes critical_sizes = {
1153 DCERPC_MODULE_VERSION,
1154 sizeof(struct dcesrv_context),
1155 sizeof(struct dcesrv_endpoint),
1156 sizeof(struct dcesrv_endpoint_server),
1157 sizeof(struct dcesrv_interface),
1158 sizeof(struct dcesrv_if_list),
1159 sizeof(struct dcesrv_connection),
1160 sizeof(struct dcesrv_call_state),
1161 sizeof(struct dcesrv_auth),
1162 sizeof(struct dcesrv_handle)
1165 return &critical_sizes;
1168 static const struct server_service_ops dcesrv_ops = {
1170 .service_init = dcesrv_init,
1171 .accept_connection = dcesrv_accept,
1172 .recv_handler = dcesrv_recv,
1173 .send_handler = dcesrv_send,
1174 .idle_handler = NULL,
1175 .close_connection = dcesrv_close,
1176 .service_exit = dcesrv_exit,
1179 const struct server_service_ops *dcesrv_get_ops(void)
1184 NTSTATUS server_service_rpc_init(void)
1186 return NT_STATUS_OK;