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->endpoint || !ep2->endpoint) {
37 return ep1->endpoint == ep2->endpoint;
40 if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
47 find an endpoint in the dcesrv_context
49 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
50 const struct dcerpc_binding *ep_description)
52 struct dcesrv_endpoint *ep;
53 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
54 if (endpoints_match(&ep->ep_description, ep_description)) {
62 see if a uuid and if_version match to an interface
64 static BOOL interface_match(const struct dcesrv_interface *if1,
65 const struct dcesrv_interface *if2)
67 if (if1->ndr->if_version != if2->ndr->if_version) {
71 if (strcmp(if1->ndr->uuid, if2->ndr->uuid)==0) {
79 find the interface operations on an endpoint
81 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
82 const struct dcesrv_interface *iface)
84 struct dcesrv_if_list *ifl;
85 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
86 if (interface_match(&(ifl->iface), iface)) {
94 see if a uuid and if_version match to an interface
96 static BOOL interface_match_by_uuid(const struct dcesrv_interface *iface,
97 const char *uuid, uint32_t if_version)
99 if (iface->ndr->if_version != if_version) {
103 if (strcmp(iface->ndr->uuid, uuid)==0) {
111 find the interface operations on an endpoint by uuid
113 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
114 const char *uuid, uint32_t if_version)
116 struct dcesrv_if_list *ifl;
117 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
118 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
119 return &(ifl->iface);
126 find a call that is pending in our call list
128 static struct dcesrv_call_state *dcesrv_find_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
130 struct dcesrv_call_state *c;
131 for (c=dce_conn->call_list;c;c=c->next) {
132 if (c->pkt.call_id == call_id) {
140 register an interface on an endpoint
142 NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
144 const struct dcesrv_interface *iface,
145 const struct security_descriptor *sd)
147 struct dcesrv_endpoint *ep;
148 struct dcesrv_if_list *ifl;
149 struct dcerpc_binding binding;
153 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
155 if (NT_STATUS_IS_ERR(status)) {
156 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
160 /* check if this endpoint exists
162 if ((ep=find_endpoint(dce_ctx, &binding))==NULL) {
163 ep = talloc_p(dce_ctx, struct dcesrv_endpoint);
165 return NT_STATUS_NO_MEMORY;
168 ep->ep_description = binding;
172 /* see if the interface is already registered on te endpoint */
173 if (find_interface(ep, iface)!=NULL) {
174 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
175 iface->ndr->name, ep_name));
176 return NT_STATUS_OBJECT_NAME_COLLISION;
179 /* talloc a new interface list element */
180 ifl = talloc_p(dce_ctx, struct dcesrv_if_list);
182 return NT_STATUS_NO_MEMORY;
185 /* copy the given interface struct to the one on the endpoints interface list */
186 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
188 /* if we have a security descriptor given,
189 * we should see if we can set it up on the endpoint
192 /* if there's currently no security descriptor given on the endpoint
195 if (ep->sd == NULL) {
196 ep->sd = copy_security_descriptor(dce_ctx, sd);
199 /* if now there's no security descriptor given on the endpoint
200 * something goes wrong, either we failed to copy the security descriptor
201 * or there was already one on the endpoint
203 if (ep->sd != NULL) {
204 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
205 " on endpoint '%s'\n",
206 iface->ndr->name, ep_name));
207 if (add_ep) free(ep);
209 return NT_STATUS_OBJECT_NAME_COLLISION;
213 /* finally add the interface on the endpoint */
214 DLIST_ADD(ep->interface_list, ifl);
216 /* if it's a new endpoint add it to the dcesrv_context */
218 DLIST_ADD(dce_ctx->endpoint_list, ep);
221 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
222 iface->ndr->name, ep_name));
227 static NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
228 DATA_BLOB *session_key)
230 if (p->auth_state.session_info->session_key.length) {
231 *session_key = p->auth_state.session_info->session_key;
234 return NT_STATUS_NO_USER_SESSION_KEY;
237 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
238 DATA_BLOB *session_key)
240 /* this took quite a few CPU cycles to find ... */
241 session_key->data = discard_const_p(char, "SystemLibraryDTC");
242 session_key->length = 16;
247 fetch the user session key - may be default (above) or the SMB session key
249 NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
250 DATA_BLOB *session_key)
252 return p->auth_state.session_key(p, session_key);
257 destroy a link to an endpoint
259 static int dcesrv_endpoint_destructor(void *ptr)
261 struct dcesrv_connection *p = ptr;
263 p->iface->unbind(p, p->iface);
266 /* destroy any handles */
268 dcesrv_handle_destroy(p, p->handles);
271 if (p->auth_state.gensec_security) {
272 gensec_end(&p->auth_state.gensec_security);
280 connect to a dcerpc endpoint
282 NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
283 const struct dcesrv_endpoint *ep,
284 struct dcesrv_connection **p)
286 *p = talloc_p(dce_ctx, struct dcesrv_connection);
288 return NT_STATUS_NO_MEMORY;
291 (*p)->dce_ctx = dce_ctx;
294 (*p)->private = NULL;
295 (*p)->call_list = NULL;
296 (*p)->cli_max_recv_frag = 0;
297 (*p)->handles = NULL;
298 (*p)->partial_input = data_blob(NULL, 0);
299 (*p)->auth_state.auth_info = NULL;
300 (*p)->auth_state.gensec_security = NULL;
301 (*p)->auth_state.session_info = NULL;
302 (*p)->auth_state.session_key = dcesrv_generic_session_key;
303 (*p)->srv_conn = NULL;
305 talloc_set_destructor(*p, dcesrv_endpoint_destructor);
311 search and connect to a dcerpc endpoint
313 NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
314 const struct dcerpc_binding *ep_description,
315 struct auth_session_info *session_info,
316 struct dcesrv_connection **dce_conn_p)
319 const struct dcesrv_endpoint *ep;
321 /* make sure this endpoint exists */
322 ep = find_endpoint(dce_ctx, ep_description);
324 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
327 status = dcesrv_endpoint_connect(dce_ctx, ep, dce_conn_p);
328 if (!NT_STATUS_IS_OK(status)) {
332 session_info->refcount++;
333 (*dce_conn_p)->auth_state.session_info = session_info;
334 (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
336 /* TODO: check security descriptor of the endpoint here
337 * if it's a smb named pipe
338 * if it's failed free dce_conn_p
345 static void dcesrv_init_hdr(struct dcerpc_packet *pkt)
348 pkt->rpc_vers_minor = 0;
349 if (lp_rpc_big_endian()) {
352 pkt->drep[0] = DCERPC_DREP_LE;
360 return a dcerpc fault
362 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
364 struct dcerpc_packet pkt;
365 struct dcesrv_call_reply *rep;
368 /* setup a bind_ack */
369 dcesrv_init_hdr(&pkt);
371 pkt.call_id = call->pkt.call_id;
372 pkt.ptype = DCERPC_PKT_FAULT;
373 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
374 pkt.u.fault.alloc_hint = 0;
375 pkt.u.fault.context_id = 0;
376 pkt.u.fault.cancel_count = 0;
377 pkt.u.fault.status = fault_code;
379 rep = talloc_p(call, struct dcesrv_call_reply);
381 return NT_STATUS_NO_MEMORY;
384 status = dcerpc_push_auth(&rep->data, call, &pkt, NULL);
385 if (!NT_STATUS_IS_OK(status)) {
389 dcerpc_set_frag_length(&rep->data, rep->data.length);
391 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
392 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
399 return a dcerpc bind_nak
401 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
403 struct dcerpc_packet pkt;
404 struct dcesrv_call_reply *rep;
407 /* setup a bind_nak */
408 dcesrv_init_hdr(&pkt);
410 pkt.call_id = call->pkt.call_id;
411 pkt.ptype = DCERPC_PKT_BIND_NAK;
412 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
413 pkt.u.bind_nak.reject_reason = reason;
414 pkt.u.bind_nak.num_versions = 0;
416 rep = talloc_p(call, struct dcesrv_call_reply);
418 return NT_STATUS_NO_MEMORY;
421 status = dcerpc_push_auth(&rep->data, call, &pkt, NULL);
422 if (!NT_STATUS_IS_OK(status)) {
426 dcerpc_set_frag_length(&rep->data, rep->data.length);
428 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
429 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
436 handle a bind request
438 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
440 const char *uuid, *transfer_syntax;
441 uint32_t if_version, transfer_syntax_version;
442 struct dcerpc_packet pkt;
443 struct dcesrv_call_reply *rep;
445 uint32_t result=0, reason=0;
447 if (call->pkt.u.bind.num_contexts != 1 ||
448 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
449 return dcesrv_bind_nak(call, 0);
452 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
453 uuid = GUID_string(call, &call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid);
455 return dcesrv_bind_nak(call, 0);
458 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
459 transfer_syntax = GUID_string(call,
460 &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid);
461 if (!transfer_syntax ||
462 strcasecmp(NDR_GUID, transfer_syntax) != 0 ||
463 NDR_GUID_VERSION != transfer_syntax_version) {
464 /* we only do NDR encoded dcerpc */
465 return dcesrv_bind_nak(call, 0);
468 call->conn->iface = find_interface_by_uuid(call->conn->endpoint, uuid, if_version);
469 if (!call->conn->iface) {
470 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
471 /* we don't know about that interface */
472 result = DCERPC_BIND_PROVIDER_REJECT;
473 reason = DCERPC_BIND_REASON_ASYNTAX;
476 if (call->conn->cli_max_recv_frag == 0) {
477 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
480 /* handle any authentication that is being requested */
481 if (!dcesrv_auth_bind(call)) {
482 /* TODO: work out the right reject code */
483 return dcesrv_bind_nak(call, 0);
486 /* setup a bind_ack */
487 dcesrv_init_hdr(&pkt);
489 pkt.call_id = call->pkt.call_id;
490 pkt.ptype = DCERPC_PKT_BIND_ACK;
491 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
492 pkt.u.bind_ack.max_xmit_frag = 0x2000;
493 pkt.u.bind_ack.max_recv_frag = 0x2000;
494 pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
495 if (call->conn->iface && call->conn->iface->ndr) {
496 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
497 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s",
498 call->conn->iface->ndr->name);
500 pkt.u.bind_ack.secondary_address = "";
502 pkt.u.bind_ack.num_results = 1;
503 pkt.u.bind_ack.ctx_list = talloc_p(call, struct dcerpc_ack_ctx);
504 if (!pkt.u.bind_ack.ctx_list) {
505 return NT_STATUS_NO_MEMORY;
507 pkt.u.bind_ack.ctx_list[0].result = result;
508 pkt.u.bind_ack.ctx_list[0].reason = reason;
509 GUID_from_string(NDR_GUID, &pkt.u.bind_ack.ctx_list[0].syntax.uuid);
510 pkt.u.bind_ack.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
511 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
513 if (!dcesrv_auth_bind_ack(call, &pkt)) {
514 return dcesrv_bind_nak(call, 0);
517 if (call->conn->iface) {
518 status = call->conn->iface->bind(call, call->conn->iface);
519 if (!NT_STATUS_IS_OK(status)) {
520 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n", uuid, if_version, nt_errstr(status)));
521 return dcesrv_bind_nak(call, 0);
525 rep = talloc_p(call, struct dcesrv_call_reply);
527 return NT_STATUS_NO_MEMORY;
530 status = dcerpc_push_auth(&rep->data, call, &pkt,
531 call->conn->auth_state.auth_info);
532 if (!NT_STATUS_IS_OK(status)) {
536 dcerpc_set_frag_length(&rep->data, rep->data.length);
538 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
539 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
546 handle a auth3 request
548 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
550 /* handle the auth3 in the auth code */
551 if (!dcesrv_auth_auth3(call)) {
552 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
557 /* we don't send a reply to a auth3 request, except by a
564 handle a dcerpc request packet
566 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
568 struct ndr_pull *pull;
569 struct ndr_push *push;
574 uint32_t total_length;
577 if (!call->conn->iface) {
578 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
581 opnum = call->pkt.u.request.opnum;
583 if (opnum >= call->conn->iface->ndr->num_calls) {
584 return dcesrv_fault(call, DCERPC_FAULT_OP_RNG_ERROR);
587 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
589 return NT_STATUS_NO_MEMORY;
592 r = talloc(call, call->conn->iface->ndr->calls[opnum].struct_size);
594 return NT_STATUS_NO_MEMORY;
597 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
598 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
601 /* unravel the NDR for the packet */
602 status = call->conn->iface->ndr->calls[opnum].ndr_pull(pull, NDR_IN, r);
603 if (!NT_STATUS_IS_OK(status)) {
604 dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN,
605 &call->pkt.u.request.stub_and_verifier);
606 return dcesrv_fault(call, DCERPC_FAULT_NDR);
609 if (pull->offset != pull->data_size) {
610 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
611 pull->data_size - pull->offset));
612 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
615 call->fault_code = 0;
617 /* call the dispatch function */
618 status = call->conn->iface->dispatch(call, call, r);
619 if (!NT_STATUS_IS_OK(status)) {
620 dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN,
621 &call->pkt.u.request.stub_and_verifier);
622 return dcesrv_fault(call, call->fault_code);
625 /* form the reply NDR */
626 push = ndr_push_init_ctx(call);
628 return NT_STATUS_NO_MEMORY;
631 /* carry over the pointer count to the reply in case we are
632 using full pointer. See NDR specification for full
634 push->ptr_count = pull->ptr_count;
636 if (lp_rpc_big_endian()) {
637 push->flags |= LIBNDR_FLAG_BIGENDIAN;
640 status = call->conn->iface->ndr->calls[opnum].ndr_push(push, NDR_OUT, r);
641 if (!NT_STATUS_IS_OK(status)) {
642 return dcesrv_fault(call, DCERPC_FAULT_NDR);
645 stub = ndr_push_blob(push);
647 total_length = stub.length;
651 struct dcesrv_call_reply *rep;
652 struct dcerpc_packet pkt;
654 rep = talloc_p(call, struct dcesrv_call_reply);
656 return NT_STATUS_NO_MEMORY;
659 length = stub.length;
660 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
661 /* the 32 is to cope with signing data */
662 length = call->conn->cli_max_recv_frag -
663 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
666 /* form the dcerpc response packet */
667 dcesrv_init_hdr(&pkt);
669 pkt.call_id = call->pkt.call_id;
670 pkt.ptype = DCERPC_PKT_RESPONSE;
672 if (stub.length == total_length) {
673 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
675 if (length == stub.length) {
676 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
678 pkt.u.response.alloc_hint = stub.length;
679 pkt.u.response.context_id = call->pkt.u.request.context_id;
680 pkt.u.response.cancel_count = 0;
681 pkt.u.response.stub_and_verifier.data = stub.data;
682 pkt.u.response.stub_and_verifier.length = length;
684 if (!dcesrv_auth_response(call, &rep->data, &pkt)) {
685 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
688 dcerpc_set_frag_length(&rep->data, rep->data.length);
690 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
693 stub.length -= length;
694 } while (stub.length != 0);
696 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
703 work out if we have a full packet yet
705 static BOOL dce_full_packet(const DATA_BLOB *data)
707 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
710 if (dcerpc_get_frag_length(data) > data->length) {
717 we might have consumed only part of our input - advance past that part
719 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
723 if (dce_conn->partial_input.length == offset) {
724 data_blob_free(&dce_conn->partial_input);
728 blob = dce_conn->partial_input;
729 dce_conn->partial_input = data_blob(blob.data + offset,
730 blob.length - offset);
731 data_blob_free(&blob);
735 process some input to a dcerpc endpoint server.
737 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
739 struct ndr_pull *ndr;
741 struct dcesrv_call_state *call;
744 call = talloc_p(dce_conn, struct dcesrv_call_state);
746 talloc_free(dce_conn->partial_input.data);
747 return NT_STATUS_NO_MEMORY;
749 call->conn = dce_conn;
750 call->replies = NULL;
752 blob = dce_conn->partial_input;
753 blob.length = dcerpc_get_frag_length(&blob);
755 ndr = ndr_pull_init_blob(&blob, call);
757 talloc_free(dce_conn->partial_input.data);
759 return NT_STATUS_NO_MEMORY;
762 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
763 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
766 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
767 if (!NT_STATUS_IS_OK(status)) {
768 talloc_free(dce_conn->partial_input.data);
773 /* we have to check the signing here, before combining the
775 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
776 !dcesrv_auth_request(call, &blob)) {
777 dce_partial_advance(dce_conn, blob.length);
778 return dcesrv_fault(call, DCERPC_FAULT_LOGON_FAILURE);
781 dce_partial_advance(dce_conn, blob.length);
783 /* see if this is a continued packet */
784 if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
785 struct dcesrv_call_state *call2 = call;
788 /* we only allow fragmented requests, no other packet types */
789 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
790 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
793 /* this is a continuation of an existing call - find the call then
794 tack it on the end */
795 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
797 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
800 if (call->pkt.ptype != call2->pkt.ptype) {
801 /* trying to play silly buggers are we? */
802 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
805 alloc_size = call->pkt.u.request.stub_and_verifier.length +
806 call2->pkt.u.request.stub_and_verifier.length;
807 if (call->pkt.u.request.alloc_hint > alloc_size) {
808 alloc_size = call->pkt.u.request.alloc_hint;
811 call->pkt.u.request.stub_and_verifier.data =
812 talloc_realloc(call, call->pkt.u.request.stub_and_verifier.data, alloc_size);
813 if (!call->pkt.u.request.stub_and_verifier.data) {
814 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
816 memcpy(call->pkt.u.request.stub_and_verifier.data +
817 call->pkt.u.request.stub_and_verifier.length,
818 call2->pkt.u.request.stub_and_verifier.data,
819 call2->pkt.u.request.stub_and_verifier.length);
820 call->pkt.u.request.stub_and_verifier.length +=
821 call2->pkt.u.request.stub_and_verifier.length;
823 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
828 /* this may not be the last pdu in the chain - if its isn't then
829 just put it on the call_list and wait for the rest */
830 if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
831 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
835 switch (call->pkt.ptype) {
836 case DCERPC_PKT_BIND:
837 status = dcesrv_bind(call);
839 case DCERPC_PKT_AUTH3:
840 status = dcesrv_auth3(call);
842 case DCERPC_PKT_REQUEST:
843 status = dcesrv_request(call);
846 status = NT_STATUS_INVALID_PARAMETER;
850 /* if we are going to be sending a reply then add
851 it to the list of pending calls. We add it to the end to keep the call
852 list in the order we will answer */
853 if (!NT_STATUS_IS_OK(status)) {
862 provide some input to a dcerpc endpoint server. This passes data
863 from a dcerpc client into the server
865 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
869 dce_conn->partial_input.data = talloc_realloc(dce_conn,
870 dce_conn->partial_input.data,
871 dce_conn->partial_input.length + data->length);
872 if (!dce_conn->partial_input.data) {
873 return NT_STATUS_NO_MEMORY;
875 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
876 data->data, data->length);
877 dce_conn->partial_input.length += data->length;
879 while (dce_full_packet(&dce_conn->partial_input)) {
880 status = dcesrv_input_process(dce_conn);
881 if (!NT_STATUS_IS_OK(status)) {
890 retrieve some output from a dcerpc server
891 The caller supplies a function that will be called to do the
894 The first argument to write_fn() will be 'private', the second will
895 be a pointer to a buffer containing the data to be sent and the 3rd
896 will be the number of bytes to be sent.
898 write_fn() should return the number of bytes successfully written.
900 this will return STATUS_BUFFER_OVERFLOW if there is more to be read
901 from the current fragment
903 NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
905 ssize_t (*write_fn)(void *, DATA_BLOB *))
907 struct dcesrv_call_state *call;
908 struct dcesrv_call_reply *rep;
911 call = dce_conn->call_list;
912 if (!call || !call->replies) {
913 return NT_STATUS_FOOBAR;
917 nwritten = write_fn(private, &rep->data);
918 if (nwritten == -1) {
919 /* TODO: hmm, how do we cope with this? destroy the
920 connection perhaps? */
921 return NT_STATUS_UNSUCCESSFUL;
924 rep->data.length -= nwritten;
925 rep->data.data += nwritten;
927 if (rep->data.length == 0) {
928 /* we're done with this section of the call */
929 DLIST_REMOVE(call->replies, rep);
932 if (call->replies == NULL) {
933 /* we're done with the whole call */
934 DLIST_REMOVE(dce_conn->call_list, call);
943 write_fn() for dcesrv_output_blob()
945 static ssize_t dcesrv_output_blob_write_fn(void *private, DATA_BLOB *out)
947 DATA_BLOB *blob = private;
948 if (out->length < blob->length) {
949 blob->length = out->length;
951 memcpy(blob->data, out->data, blob->length);
956 a simple wrapper for dcesrv_output() for when we want to output
959 NTSTATUS dcesrv_output_blob(struct dcesrv_connection *dce_conn,
962 return dcesrv_output(dce_conn, blob, dcesrv_output_blob_write_fn);
966 initialise the dcerpc server context
968 NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **dce_ctx)
971 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
973 (*dce_ctx) = talloc_p(mem_ctx, struct dcesrv_context);
975 return NT_STATUS_NO_MEMORY;
978 (*dce_ctx)->endpoint_list = NULL;
980 if (!endpoint_servers) {
981 DEBUG(3,("dcesrv_init_context: no endpoint servers configured\n"));
985 for (i=0;endpoint_servers[i];i++) {
987 const struct dcesrv_endpoint_server *ep_server;
989 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
991 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
992 return NT_STATUS_UNSUCCESSFUL;
995 ret = ep_server->init_server(*dce_ctx, ep_server);
996 if (!NT_STATUS_IS_OK(ret)) {
997 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1002 return NT_STATUS_OK;
1005 static void dcesrv_init(struct server_service *service, const struct model_ops *model_ops)
1007 struct dcesrv_context *dce_ctx;
1009 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
1011 DEBUG(1,("dcesrv_init\n"));
1013 if (!endpoint_servers) {
1014 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1018 dce_ctx = talloc_p(service, struct dcesrv_context);
1020 DEBUG(0,("talloc_p(mem_ctx, struct dcesrv_context) failed\n"));
1024 ZERO_STRUCTP(dce_ctx);
1025 dce_ctx->endpoint_list = NULL;
1027 for (i=0;endpoint_servers[i];i++) {
1029 const struct dcesrv_endpoint_server *ep_server;
1031 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1033 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1037 ret = ep_server->init_server(dce_ctx, ep_server);
1038 if (!NT_STATUS_IS_OK(ret)) {
1039 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1044 dcesrv_sock_init(service, model_ops, dce_ctx);
1049 static void dcesrv_accept(struct server_connection *srv_conn)
1051 dcesrv_sock_accept(srv_conn);
1054 static void dcesrv_recv(struct server_connection *srv_conn, time_t t, uint16_t flags)
1056 dcesrv_sock_recv(srv_conn, t, flags);
1059 static void dcesrv_send(struct server_connection *srv_conn, time_t t, uint16_t flags)
1061 dcesrv_sock_send(srv_conn, t, flags);
1064 static void dcesrv_idle(struct server_connection *srv_conn, time_t t)
1066 dcesrv_sock_idle(srv_conn, t);
1069 static void dcesrv_close(struct server_connection *srv_conn, const char *reason)
1071 dcesrv_sock_close(srv_conn, reason);
1075 static void dcesrv_exit(struct server_service *service, const char *reason)
1077 dcesrv_sock_exit(service, reason);
1081 /* the list of currently registered DCERPC endpoint servers.
1084 struct dcesrv_endpoint_server *ep_server;
1085 } *ep_servers = NULL;
1086 static int num_ep_servers;
1089 register a DCERPC endpoint server.
1091 The 'name' can be later used by other backends to find the operations
1092 structure for this backend.
1094 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1096 static NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1098 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1100 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1101 /* its already registered! */
1102 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1104 return NT_STATUS_OBJECT_NAME_COLLISION;
1107 ep_servers = Realloc(ep_servers, sizeof(ep_servers[0]) * (num_ep_servers+1));
1109 smb_panic("out of memory in dcerpc_register");
1112 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1113 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1117 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1120 return NT_STATUS_OK;
1124 return the operations structure for a named backend of the specified type
1126 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1130 for (i=0;i<num_ep_servers;i++) {
1131 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1132 return ep_servers[i].ep_server;
1140 return the DCERPC module version, and the size of some critical types
1141 This can be used by endpoint server modules to either detect compilation errors, or provide
1142 multiple implementations for different smbd compilation options in one module
1144 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1146 static const struct dcesrv_critical_sizes critical_sizes = {
1147 DCERPC_MODULE_VERSION,
1148 sizeof(struct dcesrv_context),
1149 sizeof(struct dcesrv_endpoint),
1150 sizeof(struct dcesrv_endpoint_server),
1151 sizeof(struct dcesrv_interface),
1152 sizeof(struct dcesrv_if_list),
1153 sizeof(struct dcesrv_connection),
1154 sizeof(struct dcesrv_call_state),
1155 sizeof(struct dcesrv_auth),
1156 sizeof(struct dcesrv_handle)
1159 return &critical_sizes;
1163 initialise the DCERPC subsystem
1165 BOOL subsystem_dcerpc_init(void)
1169 status = register_subsystem("dcerpc", dcerpc_register_ep_server);
1170 if (!NT_STATUS_IS_OK(status)) {
1174 /* FIXME: Perhaps panic if a basic endpoint server, such as EPMAPPER, fails to initialise? */
1177 DEBUG(3,("DCERPC subsystem version %d initialised\n", DCERPC_MODULE_VERSION));
1181 static const struct server_service_ops dcesrv_ops = {
1183 .service_init = dcesrv_init,
1184 .accept_connection = dcesrv_accept,
1185 .recv_handler = dcesrv_recv,
1186 .send_handler = dcesrv_send,
1187 .idle_handler = dcesrv_idle,
1188 .close_connection = dcesrv_close,
1189 .service_exit = dcesrv_exit,
1192 const struct server_service_ops *dcesrv_get_ops(void)
1197 NTSTATUS server_service_rpc_init(void)
1199 return NT_STATUS_OK;