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 dcesrv_ep_description *ep1,
30 const struct dcesrv_ep_description *ep2)
32 if (ep1->type != ep2->type) {
38 if (strcasecmp(ep1->info.smb_pipe,ep2->info.smb_pipe)==0) {
43 if (ep1->info.tcp_port == ep2->info.tcp_port) {
53 find an endpoint in the dcesrv_context
55 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
56 const struct dcesrv_ep_description *ep_description)
58 struct dcesrv_endpoint *ep;
59 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
60 if (endpoints_match(&ep->ep_description, ep_description)) {
68 see if a uuid and if_version match to an interface
70 static BOOL interface_match(const struct dcesrv_interface *if1,
71 const struct dcesrv_interface *if2)
73 if (if1->ndr->if_version != if2->ndr->if_version) {
77 if (strcmp(if1->ndr->uuid, if2->ndr->uuid)==0) {
85 find the interface operations on an endpoint
87 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
88 const struct dcesrv_interface *iface)
90 struct dcesrv_if_list *ifl;
91 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
92 if (interface_match(&(ifl->iface), iface)) {
100 see if a uuid and if_version match to an interface
102 static BOOL interface_match_by_uuid(const struct dcesrv_interface *iface,
103 const char *uuid, uint32_t if_version)
105 if (iface->ndr->if_version != if_version) {
109 if (strcmp(iface->ndr->uuid, uuid)==0) {
117 find the interface operations on an endpoint by uuid
119 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
120 const char *uuid, uint32_t if_version)
122 struct dcesrv_if_list *ifl;
123 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
124 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
125 return &(ifl->iface);
132 find a call that is pending in our call list
134 static struct dcesrv_call_state *dcesrv_find_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
136 struct dcesrv_call_state *c;
137 for (c=dce_conn->call_list;c;c=c->next) {
138 if (c->pkt.call_id == call_id) {
146 register an interface on an endpoint
148 NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
150 const struct dcesrv_interface *iface,
151 const struct security_descriptor *sd)
153 struct dcesrv_ep_description ep_description;
154 struct dcesrv_endpoint *ep;
155 struct dcesrv_if_list *ifl;
159 tcp = (strncasecmp(ep_name, "TCP-", 4) == 0);
162 ep_description.type = ENDPOINT_TCP;
163 ep_description.info.tcp_port = atoi(ep_name+4);
165 ep_description.type = ENDPOINT_SMB;
166 ep_description.info.smb_pipe = ep_name;
169 /* check if this endpoint exists
171 if ((ep=find_endpoint(dce_ctx, &ep_description))==NULL) {
172 ep = talloc_p(dce_ctx, struct dcesrv_endpoint);
174 return NT_STATUS_NO_MEMORY;
178 ep->ep_description.type = ENDPOINT_TCP;
179 ep->ep_description.info.tcp_port = atoi(ep_name+4);
181 ep->ep_description.type = ENDPOINT_SMB;
182 ep->ep_description.info.smb_pipe = smb_xstrdup(ep_name);
187 /* see if the interface is already registered on te endpoint */
188 if (find_interface(ep, iface)!=NULL) {
189 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
190 iface->ndr->name, ep_name));
191 return NT_STATUS_OBJECT_NAME_COLLISION;
194 /* talloc a new interface list element */
195 ifl = talloc_p(dce_ctx, struct dcesrv_if_list);
197 return NT_STATUS_NO_MEMORY;
200 /* copy the given interface struct to the one on the endpoints interface list */
201 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
203 /* if we have a security descriptor given,
204 * we should see if we can set it up on the endpoint
207 /* if there's currently no security descriptor given on the endpoint
210 if (ep->sd == NULL) {
211 ep->sd = copy_security_descriptor(dce_ctx, sd);
214 /* if now there's no security descriptor given on the endpoint
215 * something goes wrong, either we failed to copy the security descriptor
216 * or there was already one on the endpoint
218 if (ep->sd != NULL) {
219 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
220 " on endpoint '%s'\n",
221 iface->ndr->name, ep_name));
222 if (add_ep) free(ep);
224 return NT_STATUS_OBJECT_NAME_COLLISION;
228 /* finally add the interface on the endpoint */
229 DLIST_ADD(ep->interface_list, ifl);
231 /* if it's a new endpoint add it to the dcesrv_context */
233 DLIST_ADD(dce_ctx->endpoint_list, ep);
236 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
237 iface->ndr->name, ep_name));
242 static NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
243 DATA_BLOB *session_key)
245 if (p->auth_state.session_info->session_key.length) {
246 *session_key = p->auth_state.session_info->session_key;
249 return NT_STATUS_NO_USER_SESSION_KEY;
252 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
253 DATA_BLOB *session_key)
255 /* this took quite a few CPU cycles to find ... */
256 session_key->data = "SystemLibraryDTC";
257 session_key->length = 16;
262 fetch the user session key - may be default (above) or the SMB session key
264 NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
265 DATA_BLOB *session_key)
267 return p->auth_state.session_key(p, session_key);
272 connect to a dcerpc endpoint
274 NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
275 const struct dcesrv_endpoint *ep,
276 struct dcesrv_connection **p)
278 *p = talloc_p(dce_ctx, struct dcesrv_connection);
280 return NT_STATUS_NO_MEMORY;
283 (*p)->dce_ctx = dce_ctx;
286 (*p)->private = NULL;
287 (*p)->call_list = NULL;
288 (*p)->cli_max_recv_frag = 0;
289 (*p)->handles = NULL;
290 (*p)->partial_input = data_blob(NULL, 0);
291 (*p)->auth_state.auth_info = NULL;
292 (*p)->auth_state.gensec_security = NULL;
293 (*p)->auth_state.session_info = NULL;
294 (*p)->auth_state.session_key = dcesrv_generic_session_key;
295 (*p)->srv_conn = NULL;
301 search and connect to a dcerpc endpoint
303 NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
304 const struct dcesrv_ep_description *ep_description,
305 struct auth_session_info *session_info,
306 struct dcesrv_connection **dce_conn_p)
309 const struct dcesrv_endpoint *ep;
311 /* make sure this endpoint exists */
312 ep = find_endpoint(dce_ctx, ep_description);
314 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
317 status = dcesrv_endpoint_connect(dce_ctx, ep, dce_conn_p);
318 if (!NT_STATUS_IS_OK(status)) {
322 session_info->refcount++;
323 (*dce_conn_p)->auth_state.session_info = session_info;
324 (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
326 /* TODO: check security descriptor of the endpoint here
327 * if it's a smb named pipe
328 * if it's failed free dce_conn_p
336 disconnect a link to an endpoint
338 void dcesrv_endpoint_disconnect(struct dcesrv_connection *p)
341 p->iface->unbind(p, p->iface);
344 /* destroy any handles */
346 dcesrv_handle_destroy(p, p->handles);
349 if (p->auth_state.gensec_security) {
350 gensec_end(&p->auth_state.gensec_security);
356 static void dcesrv_init_hdr(struct dcerpc_packet *pkt)
359 pkt->rpc_vers_minor = 0;
360 if (lp_rpc_big_endian()) {
363 pkt->drep[0] = DCERPC_DREP_LE;
371 return a dcerpc fault
373 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
375 struct dcerpc_packet pkt;
376 struct dcesrv_call_reply *rep;
379 /* setup a bind_ack */
380 dcesrv_init_hdr(&pkt);
382 pkt.call_id = call->pkt.call_id;
383 pkt.ptype = DCERPC_PKT_FAULT;
384 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
385 pkt.u.fault.alloc_hint = 0;
386 pkt.u.fault.context_id = 0;
387 pkt.u.fault.cancel_count = 0;
388 pkt.u.fault.status = fault_code;
390 rep = talloc_p(call, struct dcesrv_call_reply);
392 return NT_STATUS_NO_MEMORY;
395 status = dcerpc_push_auth(&rep->data, call, &pkt, NULL);
396 if (!NT_STATUS_IS_OK(status)) {
400 dcerpc_set_frag_length(&rep->data, rep->data.length);
402 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
403 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
410 return a dcerpc bind_nak
412 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
414 struct dcerpc_packet pkt;
415 struct dcesrv_call_reply *rep;
418 /* setup a bind_nak */
419 dcesrv_init_hdr(&pkt);
421 pkt.call_id = call->pkt.call_id;
422 pkt.ptype = DCERPC_PKT_BIND_NAK;
423 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
424 pkt.u.bind_nak.reject_reason = reason;
425 pkt.u.bind_nak.num_versions = 0;
427 rep = talloc_p(call, struct dcesrv_call_reply);
429 return NT_STATUS_NO_MEMORY;
432 status = dcerpc_push_auth(&rep->data, call, &pkt, NULL);
433 if (!NT_STATUS_IS_OK(status)) {
437 dcerpc_set_frag_length(&rep->data, rep->data.length);
439 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
440 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
447 handle a bind request
449 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
451 const char *uuid, *transfer_syntax;
452 uint32_t if_version, transfer_syntax_version;
453 struct dcerpc_packet pkt;
454 struct dcesrv_call_reply *rep;
456 uint32_t result=0, reason=0;
458 if (call->pkt.u.bind.num_contexts != 1 ||
459 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
460 return dcesrv_bind_nak(call, 0);
463 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
464 uuid = GUID_string(call, &call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid);
466 return dcesrv_bind_nak(call, 0);
469 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
470 transfer_syntax = GUID_string(call,
471 &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid);
472 if (!transfer_syntax ||
473 strcasecmp(NDR_GUID, transfer_syntax) != 0 ||
474 NDR_GUID_VERSION != transfer_syntax_version) {
475 /* we only do NDR encoded dcerpc */
476 return dcesrv_bind_nak(call, 0);
479 call->conn->iface = find_interface_by_uuid(call->conn->endpoint, uuid, if_version);
480 if (!call->conn->iface) {
481 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
482 /* we don't know about that interface */
483 result = DCERPC_BIND_PROVIDER_REJECT;
484 reason = DCERPC_BIND_REASON_ASYNTAX;
487 if (call->conn->cli_max_recv_frag == 0) {
488 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
491 /* handle any authentication that is being requested */
492 if (!dcesrv_auth_bind(call)) {
493 /* TODO: work out the right reject code */
494 return dcesrv_bind_nak(call, 0);
497 /* setup a bind_ack */
498 dcesrv_init_hdr(&pkt);
500 pkt.call_id = call->pkt.call_id;
501 pkt.ptype = DCERPC_PKT_BIND_ACK;
502 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
503 pkt.u.bind_ack.max_xmit_frag = 0x2000;
504 pkt.u.bind_ack.max_recv_frag = 0x2000;
505 pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
506 if (call->conn->iface && call->conn->iface->ndr) {
507 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s",
508 call->conn->iface->ndr->name);
510 pkt.u.bind_ack.secondary_address = "";
512 pkt.u.bind_ack.num_results = 1;
513 pkt.u.bind_ack.ctx_list = talloc_p(call, struct dcerpc_ack_ctx);
514 if (!pkt.u.bind_ack.ctx_list) {
515 return NT_STATUS_NO_MEMORY;
517 pkt.u.bind_ack.ctx_list[0].result = result;
518 pkt.u.bind_ack.ctx_list[0].reason = reason;
519 GUID_from_string(NDR_GUID, &pkt.u.bind_ack.ctx_list[0].syntax.uuid);
520 pkt.u.bind_ack.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
521 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
523 if (!dcesrv_auth_bind_ack(call, &pkt)) {
524 return dcesrv_bind_nak(call, 0);
527 if (call->conn->iface) {
528 status = call->conn->iface->bind(call, call->conn->iface);
529 if (!NT_STATUS_IS_OK(status)) {
530 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n", uuid, if_version, nt_errstr(status)));
531 return dcesrv_bind_nak(call, 0);
535 rep = talloc_p(call, struct dcesrv_call_reply);
537 return NT_STATUS_NO_MEMORY;
540 status = dcerpc_push_auth(&rep->data, call, &pkt,
541 call->conn->auth_state.auth_info);
542 if (!NT_STATUS_IS_OK(status)) {
546 dcerpc_set_frag_length(&rep->data, rep->data.length);
548 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
549 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
556 handle a auth3 request
558 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
560 /* handle the auth3 in the auth code */
561 if (!dcesrv_auth_auth3(call)) {
562 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
567 /* we don't send a reply to a auth3 request, except by a
574 handle a dcerpc request packet
576 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
578 struct ndr_pull *pull;
579 struct ndr_push *push;
584 uint32_t total_length;
587 if (!call->conn->iface) {
588 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
591 opnum = call->pkt.u.request.opnum;
593 if (opnum >= call->conn->iface->ndr->num_calls) {
594 return dcesrv_fault(call, DCERPC_FAULT_OP_RNG_ERROR);
597 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
599 return NT_STATUS_NO_MEMORY;
602 r = talloc(call, call->conn->iface->ndr->calls[opnum].struct_size);
604 return NT_STATUS_NO_MEMORY;
607 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
608 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
611 /* unravel the NDR for the packet */
612 status = call->conn->iface->ndr->calls[opnum].ndr_pull(pull, NDR_IN, r);
613 if (!NT_STATUS_IS_OK(status)) {
614 dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN,
615 &call->pkt.u.request.stub_and_verifier);
616 return dcesrv_fault(call, DCERPC_FAULT_NDR);
619 if (pull->offset != pull->data_size) {
620 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
621 pull->data_size - pull->offset));
622 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
625 call->fault_code = 0;
627 /* call the dispatch function */
628 status = call->conn->iface->dispatch(call, call, r);
629 if (!NT_STATUS_IS_OK(status)) {
630 dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN,
631 &call->pkt.u.request.stub_and_verifier);
632 return dcesrv_fault(call, call->fault_code);
635 /* form the reply NDR */
636 push = ndr_push_init_ctx(call);
638 return NT_STATUS_NO_MEMORY;
641 /* carry over the pointer count to the reply in case we are
642 using full pointer. See NDR specification for full
644 push->ptr_count = pull->ptr_count;
646 if (lp_rpc_big_endian()) {
647 push->flags |= LIBNDR_FLAG_BIGENDIAN;
650 status = call->conn->iface->ndr->calls[opnum].ndr_push(push, NDR_OUT, r);
651 if (!NT_STATUS_IS_OK(status)) {
652 return dcesrv_fault(call, DCERPC_FAULT_NDR);
655 stub = ndr_push_blob(push);
657 total_length = stub.length;
661 struct dcesrv_call_reply *rep;
662 struct dcerpc_packet pkt;
664 rep = talloc_p(call, struct dcesrv_call_reply);
666 return NT_STATUS_NO_MEMORY;
669 length = stub.length;
670 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
671 /* the 32 is to cope with signing data */
672 length = call->conn->cli_max_recv_frag -
673 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
676 /* form the dcerpc response packet */
677 dcesrv_init_hdr(&pkt);
679 pkt.call_id = call->pkt.call_id;
680 pkt.ptype = DCERPC_PKT_RESPONSE;
682 if (stub.length == total_length) {
683 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
685 if (length == stub.length) {
686 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
688 pkt.u.response.alloc_hint = stub.length;
689 pkt.u.response.context_id = call->pkt.u.request.context_id;
690 pkt.u.response.cancel_count = 0;
691 pkt.u.response.stub_and_verifier.data = stub.data;
692 pkt.u.response.stub_and_verifier.length = length;
694 if (!dcesrv_auth_response(call, &rep->data, &pkt)) {
695 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
698 dcerpc_set_frag_length(&rep->data, rep->data.length);
700 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
703 stub.length -= length;
704 } while (stub.length != 0);
706 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
713 work out if we have a full packet yet
715 static BOOL dce_full_packet(const DATA_BLOB *data)
717 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
720 if (dcerpc_get_frag_length(data) > data->length) {
727 we might have consumed only part of our input - advance past that part
729 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
733 if (dce_conn->partial_input.length == offset) {
734 data_blob_free(&dce_conn->partial_input);
738 blob = dce_conn->partial_input;
739 dce_conn->partial_input = data_blob(blob.data + offset,
740 blob.length - offset);
741 data_blob_free(&blob);
745 process some input to a dcerpc endpoint server.
747 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
749 struct ndr_pull *ndr;
751 struct dcesrv_call_state *call;
754 call = talloc_p(dce_conn, struct dcesrv_call_state);
756 talloc_free(dce_conn->partial_input.data);
757 return NT_STATUS_NO_MEMORY;
759 call->conn = dce_conn;
760 call->replies = NULL;
762 blob = dce_conn->partial_input;
763 blob.length = dcerpc_get_frag_length(&blob);
765 ndr = ndr_pull_init_blob(&blob, call);
767 talloc_free(dce_conn->partial_input.data);
769 return NT_STATUS_NO_MEMORY;
772 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
773 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
776 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
777 if (!NT_STATUS_IS_OK(status)) {
778 talloc_free(dce_conn->partial_input.data);
783 /* we have to check the signing here, before combining the
785 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
786 !dcesrv_auth_request(call, &blob)) {
787 dce_partial_advance(dce_conn, blob.length);
788 return dcesrv_fault(call, DCERPC_FAULT_LOGON_FAILURE);
791 dce_partial_advance(dce_conn, blob.length);
793 /* see if this is a continued packet */
794 if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
795 struct dcesrv_call_state *call2 = call;
798 /* we only allow fragmented requests, no other packet types */
799 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
800 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
803 /* this is a continuation of an existing call - find the call then
804 tack it on the end */
805 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
807 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
810 if (call->pkt.ptype != call2->pkt.ptype) {
811 /* trying to play silly buggers are we? */
812 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
815 alloc_size = call->pkt.u.request.stub_and_verifier.length +
816 call2->pkt.u.request.stub_and_verifier.length;
817 if (call->pkt.u.request.alloc_hint > alloc_size) {
818 alloc_size = call->pkt.u.request.alloc_hint;
821 call->pkt.u.request.stub_and_verifier.data =
822 talloc_realloc(call, call->pkt.u.request.stub_and_verifier.data, alloc_size);
823 if (!call->pkt.u.request.stub_and_verifier.data) {
824 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
826 memcpy(call->pkt.u.request.stub_and_verifier.data +
827 call->pkt.u.request.stub_and_verifier.length,
828 call2->pkt.u.request.stub_and_verifier.data,
829 call2->pkt.u.request.stub_and_verifier.length);
830 call->pkt.u.request.stub_and_verifier.length +=
831 call2->pkt.u.request.stub_and_verifier.length;
833 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
838 /* this may not be the last pdu in the chain - if its isn't then
839 just put it on the call_list and wait for the rest */
840 if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
841 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
845 switch (call->pkt.ptype) {
846 case DCERPC_PKT_BIND:
847 status = dcesrv_bind(call);
849 case DCERPC_PKT_AUTH3:
850 status = dcesrv_auth3(call);
852 case DCERPC_PKT_REQUEST:
853 status = dcesrv_request(call);
856 status = NT_STATUS_INVALID_PARAMETER;
860 /* if we are going to be sending a reply then add
861 it to the list of pending calls. We add it to the end to keep the call
862 list in the order we will answer */
863 if (!NT_STATUS_IS_OK(status)) {
872 provide some input to a dcerpc endpoint server. This passes data
873 from a dcerpc client into the server
875 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
879 dce_conn->partial_input.data = talloc_realloc(dce_conn,
880 dce_conn->partial_input.data,
881 dce_conn->partial_input.length + data->length);
882 if (!dce_conn->partial_input.data) {
883 return NT_STATUS_NO_MEMORY;
885 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
886 data->data, data->length);
887 dce_conn->partial_input.length += data->length;
889 while (dce_full_packet(&dce_conn->partial_input)) {
890 status = dcesrv_input_process(dce_conn);
891 if (!NT_STATUS_IS_OK(status)) {
900 retrieve some output from a dcerpc server
901 The caller supplies a function that will be called to do the
904 The first argument to write_fn() will be 'private', the second will
905 be a pointer to a buffer containing the data to be sent and the 3rd
906 will be the number of bytes to be sent.
908 write_fn() should return the number of bytes successfully written.
910 this will return STATUS_BUFFER_OVERFLOW if there is more to be read
911 from the current fragment
913 NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
915 ssize_t (*write_fn)(void *, DATA_BLOB *))
917 struct dcesrv_call_state *call;
918 struct dcesrv_call_reply *rep;
920 NTSTATUS status = NT_STATUS_OK;
922 call = dce_conn->call_list;
923 if (!call || !call->replies) {
924 return NT_STATUS_FOOBAR;
928 nwritten = write_fn(private, &rep->data);
929 if (nwritten == -1) {
930 /* TODO: hmm, how do we cope with this? destroy the
931 connection perhaps? */
932 return NT_STATUS_UNSUCCESSFUL;
935 rep->data.length -= nwritten;
936 rep->data.data += nwritten;
938 if (rep->data.length == 0) {
939 /* we're done with this section of the call */
940 DLIST_REMOVE(call->replies, rep);
942 status = STATUS_BUFFER_OVERFLOW;
945 if (call->replies == NULL) {
946 /* we're done with the whole call */
947 DLIST_REMOVE(dce_conn->call_list, call);
956 write_fn() for dcesrv_output_blob()
958 static ssize_t dcesrv_output_blob_write_fn(void *private, DATA_BLOB *out)
960 DATA_BLOB *blob = private;
961 if (out->length < blob->length) {
962 blob->length = out->length;
964 memcpy(blob->data, out->data, blob->length);
969 a simple wrapper for dcesrv_output() for when we want to output
972 NTSTATUS dcesrv_output_blob(struct dcesrv_connection *dce_conn,
975 return dcesrv_output(dce_conn, blob, dcesrv_output_blob_write_fn);
979 initialise the dcerpc server context
981 NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **dce_ctx)
984 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
986 (*dce_ctx) = talloc_p(mem_ctx, struct dcesrv_context);
988 return NT_STATUS_NO_MEMORY;
991 (*dce_ctx)->endpoint_list = NULL;
993 if (!endpoint_servers) {
994 DEBUG(3,("dcesrv_init_context: no endpoint servers configured\n"));
998 for (i=0;endpoint_servers[i];i++) {
1000 const struct dcesrv_endpoint_server *ep_server;
1002 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1004 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1005 return NT_STATUS_UNSUCCESSFUL;
1008 ret = ep_server->init_server(*dce_ctx, ep_server);
1009 if (!NT_STATUS_IS_OK(ret)) {
1010 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1015 return NT_STATUS_OK;
1018 static void dcesrv_init(struct server_service *service, const struct model_ops *model_ops)
1020 struct dcesrv_context *dce_ctx;
1022 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
1024 DEBUG(1,("dcesrv_init\n"));
1026 if (!endpoint_servers) {
1027 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1031 dce_ctx = talloc_p(service, struct dcesrv_context);
1033 DEBUG(0,("talloc_p(mem_ctx, struct dcesrv_context) failed\n"));
1037 ZERO_STRUCTP(dce_ctx);
1038 dce_ctx->endpoint_list = NULL;
1040 for (i=0;endpoint_servers[i];i++) {
1042 const struct dcesrv_endpoint_server *ep_server;
1044 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1046 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1050 ret = ep_server->init_server(dce_ctx, ep_server);
1051 if (!NT_STATUS_IS_OK(ret)) {
1052 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1057 dcesrv_tcp_init(service, model_ops, dce_ctx);
1062 static void dcesrv_accept(struct server_connection *srv_conn)
1064 dcesrv_tcp_accept(srv_conn);
1067 static void dcesrv_recv(struct server_connection *srv_conn, time_t t, uint16_t flags)
1069 dcesrv_tcp_recv(srv_conn, t, flags);
1072 static void dcesrv_send(struct server_connection *srv_conn, time_t t, uint16_t flags)
1074 dcesrv_tcp_send(srv_conn, t, flags);
1077 static void dcesrv_idle(struct server_connection *srv_conn, time_t t)
1079 dcesrv_tcp_idle(srv_conn, t);
1082 static void dcesrv_close(struct server_connection *srv_conn, const char *reason)
1084 dcesrv_tcp_close(srv_conn, reason);
1088 static void dcesrv_exit(struct server_service *service, const char *reason)
1090 dcesrv_tcp_exit(service, reason);
1094 /* the list of currently registered DCERPC endpoint servers.
1097 struct dcesrv_endpoint_server *ep_server;
1098 } *ep_servers = NULL;
1099 static int num_ep_servers;
1102 register a DCERPC endpoint server.
1104 The 'name' can be later used by other backends to find the operations
1105 structure for this backend.
1107 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1109 static NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1111 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1113 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1114 /* its already registered! */
1115 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1117 return NT_STATUS_OBJECT_NAME_COLLISION;
1120 ep_servers = Realloc(ep_servers, sizeof(ep_servers[0]) * (num_ep_servers+1));
1122 smb_panic("out of memory in dcerpc_register");
1125 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1126 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1130 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1133 return NT_STATUS_OK;
1137 return the operations structure for a named backend of the specified type
1139 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1143 for (i=0;i<num_ep_servers;i++) {
1144 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1145 return ep_servers[i].ep_server;
1153 return the DCERPC module version, and the size of some critical types
1154 This can be used by endpoint server modules to either detect compilation errors, or provide
1155 multiple implementations for different smbd compilation options in one module
1157 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1159 static const struct dcesrv_critical_sizes critical_sizes = {
1160 DCERPC_MODULE_VERSION,
1161 sizeof(struct dcesrv_context),
1162 sizeof(struct dcesrv_endpoint),
1163 sizeof(struct dcesrv_endpoint_server),
1164 sizeof(struct dcesrv_ep_description),
1165 sizeof(struct dcesrv_interface),
1166 sizeof(struct dcesrv_if_list),
1167 sizeof(struct dcesrv_connection),
1168 sizeof(struct dcesrv_call_state),
1169 sizeof(struct dcesrv_auth),
1170 sizeof(struct dcesrv_handle)
1173 return &critical_sizes;
1177 initialise the DCERPC subsystem
1179 BOOL subsystem_dcerpc_init(void)
1183 status = register_subsystem("dcerpc", dcerpc_register_ep_server);
1184 if (!NT_STATUS_IS_OK(status)) {
1188 /* FIXME: Perhaps panic if a basic endpoint server, such as EPMAPER, fails to initialise? */
1191 DEBUG(3,("DCERPC subsystem version %d initialised\n", DCERPC_MODULE_VERSION));
1195 static const struct server_service_ops dcesrv_ops = {
1197 .service_init = dcesrv_init,
1198 .accept_connection = dcesrv_accept,
1199 .recv_handler = dcesrv_recv,
1200 .send_handler = dcesrv_send,
1201 .idle_handler = dcesrv_idle,
1202 .close_connection = dcesrv_close,
1203 .service_exit = dcesrv_exit,
1206 const struct server_service_ops *dcesrv_get_ops(void)
1211 NTSTATUS server_service_rpc_init(void)
1213 return NT_STATUS_OK;