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->if_version != if2->if_version) {
76 if (strcmp(if1->uuid, if2->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->if_version != if_version) {
108 if (strcmp(iface->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->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->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->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(uint8_t, "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);
281 connect to a dcerpc endpoint
283 NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
284 const struct dcesrv_endpoint *ep,
285 struct dcesrv_connection **p)
287 *p = talloc_p(dce_ctx, struct dcesrv_connection);
289 return NT_STATUS_NO_MEMORY;
292 (*p)->dce_ctx = dce_ctx;
295 (*p)->private = NULL;
296 (*p)->call_list = NULL;
297 (*p)->cli_max_recv_frag = 0;
298 (*p)->handles = NULL;
299 (*p)->partial_input = data_blob(NULL, 0);
300 (*p)->auth_state.auth_info = NULL;
301 (*p)->auth_state.gensec_security = NULL;
302 (*p)->auth_state.session_info = NULL;
303 (*p)->auth_state.session_key = dcesrv_generic_session_key;
304 (*p)->srv_conn = NULL;
306 talloc_set_destructor(*p, dcesrv_endpoint_destructor);
312 search and connect to a dcerpc endpoint
314 NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
315 const struct dcerpc_binding *ep_description,
316 struct auth_session_info *session_info,
317 struct dcesrv_connection **dce_conn_p)
320 const struct dcesrv_endpoint *ep;
322 /* make sure this endpoint exists */
323 ep = find_endpoint(dce_ctx, ep_description);
325 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
328 status = dcesrv_endpoint_connect(dce_ctx, ep, dce_conn_p);
329 if (!NT_STATUS_IS_OK(status)) {
333 session_info->refcount++;
334 (*dce_conn_p)->auth_state.session_info = session_info;
335 (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
337 /* TODO: check security descriptor of the endpoint here
338 * if it's a smb named pipe
339 * if it's failed free dce_conn_p
346 static void dcesrv_init_hdr(struct dcerpc_packet *pkt)
349 pkt->rpc_vers_minor = 0;
350 if (lp_rpc_big_endian()) {
353 pkt->drep[0] = DCERPC_DREP_LE;
361 return a dcerpc fault
363 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
365 struct dcerpc_packet pkt;
366 struct dcesrv_call_reply *rep;
369 /* setup a bind_ack */
370 dcesrv_init_hdr(&pkt);
372 pkt.call_id = call->pkt.call_id;
373 pkt.ptype = DCERPC_PKT_FAULT;
374 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
375 pkt.u.fault.alloc_hint = 0;
376 pkt.u.fault.context_id = 0;
377 pkt.u.fault.cancel_count = 0;
378 pkt.u.fault.status = fault_code;
380 rep = talloc_p(call, struct dcesrv_call_reply);
382 return NT_STATUS_NO_MEMORY;
385 status = dcerpc_push_auth(&rep->data, call, &pkt, NULL);
386 if (!NT_STATUS_IS_OK(status)) {
390 dcerpc_set_frag_length(&rep->data, rep->data.length);
392 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
393 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
400 return a dcerpc bind_nak
402 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
404 struct dcerpc_packet pkt;
405 struct dcesrv_call_reply *rep;
408 /* setup a bind_nak */
409 dcesrv_init_hdr(&pkt);
411 pkt.call_id = call->pkt.call_id;
412 pkt.ptype = DCERPC_PKT_BIND_NAK;
413 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
414 pkt.u.bind_nak.reject_reason = reason;
415 pkt.u.bind_nak.num_versions = 0;
417 rep = talloc_p(call, struct dcesrv_call_reply);
419 return NT_STATUS_NO_MEMORY;
422 status = dcerpc_push_auth(&rep->data, call, &pkt, NULL);
423 if (!NT_STATUS_IS_OK(status)) {
427 dcerpc_set_frag_length(&rep->data, rep->data.length);
429 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
430 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
437 handle a bind request
439 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
441 const char *uuid, *transfer_syntax;
442 uint32_t if_version, transfer_syntax_version;
443 struct dcerpc_packet pkt;
444 struct dcesrv_call_reply *rep;
446 uint32_t result=0, reason=0;
448 if (call->pkt.u.bind.num_contexts != 1 ||
449 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
450 return dcesrv_bind_nak(call, 0);
453 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
454 uuid = GUID_string(call, &call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid);
456 return dcesrv_bind_nak(call, 0);
459 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
460 transfer_syntax = GUID_string(call,
461 &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid);
462 if (!transfer_syntax ||
463 strcasecmp(NDR_GUID, transfer_syntax) != 0 ||
464 NDR_GUID_VERSION != transfer_syntax_version) {
465 /* we only do NDR encoded dcerpc */
466 return dcesrv_bind_nak(call, 0);
469 call->conn->iface = find_interface_by_uuid(call->conn->endpoint, uuid, if_version);
470 if (!call->conn->iface) {
471 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
472 /* we don't know about that interface */
473 result = DCERPC_BIND_PROVIDER_REJECT;
474 reason = DCERPC_BIND_REASON_ASYNTAX;
477 if (call->conn->cli_max_recv_frag == 0) {
478 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
481 /* handle any authentication that is being requested */
482 if (!dcesrv_auth_bind(call)) {
483 /* TODO: work out the right reject code */
484 return dcesrv_bind_nak(call, 0);
487 /* setup a bind_ack */
488 dcesrv_init_hdr(&pkt);
490 pkt.call_id = call->pkt.call_id;
491 pkt.ptype = DCERPC_PKT_BIND_ACK;
492 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
493 pkt.u.bind_ack.max_xmit_frag = 0x2000;
494 pkt.u.bind_ack.max_recv_frag = 0x2000;
495 pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
496 if (call->conn->iface) {
497 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
498 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s",
499 call->conn->iface->name);
501 pkt.u.bind_ack.secondary_address = "";
503 pkt.u.bind_ack.num_results = 1;
504 pkt.u.bind_ack.ctx_list = talloc_p(call, struct dcerpc_ack_ctx);
505 if (!pkt.u.bind_ack.ctx_list) {
506 return NT_STATUS_NO_MEMORY;
508 pkt.u.bind_ack.ctx_list[0].result = result;
509 pkt.u.bind_ack.ctx_list[0].reason = reason;
510 GUID_from_string(NDR_GUID, &pkt.u.bind_ack.ctx_list[0].syntax.uuid);
511 pkt.u.bind_ack.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
512 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
514 if (!dcesrv_auth_bind_ack(call, &pkt)) {
515 return dcesrv_bind_nak(call, 0);
518 if (call->conn->iface) {
519 status = call->conn->iface->bind(call, call->conn->iface);
520 if (!NT_STATUS_IS_OK(status)) {
521 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n", uuid, if_version, nt_errstr(status)));
522 return dcesrv_bind_nak(call, 0);
526 rep = talloc_p(call, struct dcesrv_call_reply);
528 return NT_STATUS_NO_MEMORY;
531 status = dcerpc_push_auth(&rep->data, call, &pkt,
532 call->conn->auth_state.auth_info);
533 if (!NT_STATUS_IS_OK(status)) {
537 dcerpc_set_frag_length(&rep->data, rep->data.length);
539 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
540 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
547 handle a auth3 request
549 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
551 /* handle the auth3 in the auth code */
552 if (!dcesrv_auth_auth3(call)) {
553 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
558 /* we don't send a reply to a auth3 request, except by a
564 handle a bind request
566 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
568 struct dcerpc_packet pkt;
569 struct dcesrv_call_reply *rep;
571 uint32_t result=0, reason=0;
573 /* handle any authentication that is being requested */
574 if (!dcesrv_auth_alter(call)) {
575 /* TODO: work out the right reject code */
576 return dcesrv_bind_nak(call, 0);
579 /* setup a alter_ack */
580 dcesrv_init_hdr(&pkt);
582 pkt.call_id = call->pkt.call_id;
583 pkt.ptype = DCERPC_PKT_ALTER_RESP;
584 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
585 pkt.u.alter_resp.max_xmit_frag = 0x2000;
586 pkt.u.alter_resp.max_recv_frag = 0x2000;
587 pkt.u.alter_resp.assoc_group_id = call->pkt.u.bind.assoc_group_id;
588 pkt.u.alter_resp.secondary_address = NULL;
589 pkt.u.alter_resp.num_results = 1;
590 pkt.u.alter_resp.ctx_list = talloc_p(call, struct dcerpc_ack_ctx);
591 if (!pkt.u.alter_resp.ctx_list) {
592 return NT_STATUS_NO_MEMORY;
594 pkt.u.alter_resp.ctx_list[0].result = result;
595 pkt.u.alter_resp.ctx_list[0].reason = reason;
596 GUID_from_string(NDR_GUID, &pkt.u.alter_resp.ctx_list[0].syntax.uuid);
597 pkt.u.alter_resp.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
598 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
600 if (!dcesrv_auth_alter_ack(call, &pkt)) {
601 return dcesrv_bind_nak(call, 0);
604 rep = talloc_p(call, struct dcesrv_call_reply);
606 return NT_STATUS_NO_MEMORY;
609 status = dcerpc_push_auth(&rep->data, call, &pkt,
610 call->conn->auth_state.auth_info);
611 if (!NT_STATUS_IS_OK(status)) {
615 dcerpc_set_frag_length(&rep->data, rep->data.length);
617 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
618 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
624 handle a dcerpc request packet
626 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
628 struct ndr_pull *pull;
629 struct ndr_push *push;
633 uint32_t total_length;
635 call->fault_code = 0;
637 if (!call->conn->iface) {
638 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
641 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
643 return NT_STATUS_NO_MEMORY;
646 if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_ORPC) {
647 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
650 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
651 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
654 /* unravel the NDR for the packet */
655 status = call->conn->iface->ndr_pull(call, call, pull, &r);
656 if (!NT_STATUS_IS_OK(status)) {
657 return dcesrv_fault(call, call->fault_code);
660 if (pull->offset != pull->data_size) {
661 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
662 pull->data_size - pull->offset));
663 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
666 /* call the dispatch function */
667 status = call->conn->iface->dispatch(call, call, r);
668 if (!NT_STATUS_IS_OK(status)) {
669 return dcesrv_fault(call, call->fault_code);
672 /* form the reply NDR */
673 push = ndr_push_init_ctx(call);
675 return NT_STATUS_NO_MEMORY;
678 /* carry over the pointer count to the reply in case we are
679 using full pointer. See NDR specification for full
681 push->ptr_count = pull->ptr_count;
683 if (lp_rpc_big_endian()) {
684 push->flags |= LIBNDR_FLAG_BIGENDIAN;
687 status = call->conn->iface->ndr_push(call, call, push, r);
688 if (!NT_STATUS_IS_OK(status)) {
689 return dcesrv_fault(call, call->fault_code);
692 stub = ndr_push_blob(push);
694 total_length = stub.length;
698 struct dcesrv_call_reply *rep;
699 struct dcerpc_packet pkt;
701 rep = talloc_p(call, struct dcesrv_call_reply);
703 return NT_STATUS_NO_MEMORY;
706 length = stub.length;
707 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
708 /* the 32 is to cope with signing data */
709 length = call->conn->cli_max_recv_frag -
710 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
713 /* form the dcerpc response packet */
714 dcesrv_init_hdr(&pkt);
716 pkt.call_id = call->pkt.call_id;
717 pkt.ptype = DCERPC_PKT_RESPONSE;
719 if (stub.length == total_length) {
720 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
722 if (length == stub.length) {
723 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
725 pkt.u.response.alloc_hint = stub.length;
726 pkt.u.response.context_id = call->pkt.u.request.context_id;
727 pkt.u.response.cancel_count = 0;
728 pkt.u.response.stub_and_verifier.data = stub.data;
729 pkt.u.response.stub_and_verifier.length = length;
731 if (!dcesrv_auth_response(call, &rep->data, &pkt)) {
732 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
735 dcerpc_set_frag_length(&rep->data, rep->data.length);
737 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
740 stub.length -= length;
741 } while (stub.length != 0);
743 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
750 work out if we have a full packet yet
752 static BOOL dce_full_packet(const DATA_BLOB *data)
754 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
757 if (dcerpc_get_frag_length(data) > data->length) {
764 we might have consumed only part of our input - advance past that part
766 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
770 if (dce_conn->partial_input.length == offset) {
771 data_blob_free(&dce_conn->partial_input);
775 blob = dce_conn->partial_input;
776 dce_conn->partial_input = data_blob(blob.data + offset,
777 blob.length - offset);
778 data_blob_free(&blob);
782 process some input to a dcerpc endpoint server.
784 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
786 struct ndr_pull *ndr;
788 struct dcesrv_call_state *call;
791 call = talloc_p(dce_conn, struct dcesrv_call_state);
793 talloc_free(dce_conn->partial_input.data);
794 return NT_STATUS_NO_MEMORY;
796 call->conn = dce_conn;
797 call->replies = NULL;
799 blob = dce_conn->partial_input;
800 blob.length = dcerpc_get_frag_length(&blob);
802 ndr = ndr_pull_init_blob(&blob, call);
804 talloc_free(dce_conn->partial_input.data);
806 return NT_STATUS_NO_MEMORY;
809 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
810 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
813 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
814 if (!NT_STATUS_IS_OK(status)) {
815 talloc_free(dce_conn->partial_input.data);
820 /* we have to check the signing here, before combining the
822 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
823 !dcesrv_auth_request(call, &blob)) {
824 dce_partial_advance(dce_conn, blob.length);
825 return dcesrv_fault(call, DCERPC_FAULT_LOGON_FAILURE);
828 dce_partial_advance(dce_conn, blob.length);
830 /* see if this is a continued packet */
831 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
832 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
833 struct dcesrv_call_state *call2 = call;
836 /* we only allow fragmented requests, no other packet types */
837 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
838 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
841 /* this is a continuation of an existing call - find the call then
842 tack it on the end */
843 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
845 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
848 if (call->pkt.ptype != call2->pkt.ptype) {
849 /* trying to play silly buggers are we? */
850 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
853 alloc_size = call->pkt.u.request.stub_and_verifier.length +
854 call2->pkt.u.request.stub_and_verifier.length;
855 if (call->pkt.u.request.alloc_hint > alloc_size) {
856 alloc_size = call->pkt.u.request.alloc_hint;
859 call->pkt.u.request.stub_and_verifier.data =
861 call->pkt.u.request.stub_and_verifier.data,
862 uint8_t, alloc_size);
863 if (!call->pkt.u.request.stub_and_verifier.data) {
864 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
866 memcpy(call->pkt.u.request.stub_and_verifier.data +
867 call->pkt.u.request.stub_and_verifier.length,
868 call2->pkt.u.request.stub_and_verifier.data,
869 call2->pkt.u.request.stub_and_verifier.length);
870 call->pkt.u.request.stub_and_verifier.length +=
871 call2->pkt.u.request.stub_and_verifier.length;
873 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
878 /* this may not be the last pdu in the chain - if its isn't then
879 just put it on the call_list and wait for the rest */
880 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
881 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
882 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
886 switch (call->pkt.ptype) {
887 case DCERPC_PKT_BIND:
888 status = dcesrv_bind(call);
890 case DCERPC_PKT_AUTH3:
891 status = dcesrv_auth3(call);
893 case DCERPC_PKT_ALTER:
894 status = dcesrv_alter(call);
896 case DCERPC_PKT_REQUEST:
897 status = dcesrv_request(call);
900 status = NT_STATUS_INVALID_PARAMETER;
904 /* if we are going to be sending a reply then add
905 it to the list of pending calls. We add it to the end to keep the call
906 list in the order we will answer */
907 if (!NT_STATUS_IS_OK(status)) {
916 provide some input to a dcerpc endpoint server. This passes data
917 from a dcerpc client into the server
919 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
923 dce_conn->partial_input.data = talloc_realloc(dce_conn,
924 dce_conn->partial_input.data,
926 dce_conn->partial_input.length + data->length);
927 if (!dce_conn->partial_input.data) {
928 return NT_STATUS_NO_MEMORY;
930 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
931 data->data, data->length);
932 dce_conn->partial_input.length += data->length;
934 while (dce_full_packet(&dce_conn->partial_input)) {
935 status = dcesrv_input_process(dce_conn);
936 if (!NT_STATUS_IS_OK(status)) {
945 retrieve some output from a dcerpc server
946 The caller supplies a function that will be called to do the
949 The first argument to write_fn() will be 'private', the second will
950 be a pointer to a buffer containing the data to be sent and the 3rd
951 will be the number of bytes to be sent.
953 write_fn() should return the number of bytes successfully written.
955 this will return STATUS_BUFFER_OVERFLOW if there is more to be read
956 from the current fragment
958 NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
960 ssize_t (*write_fn)(void *, DATA_BLOB *))
962 struct dcesrv_call_state *call;
963 struct dcesrv_call_reply *rep;
966 call = dce_conn->call_list;
967 if (!call || !call->replies) {
968 return NT_STATUS_FOOBAR;
972 nwritten = write_fn(private, &rep->data);
973 if (nwritten == -1) {
974 /* TODO: hmm, how do we cope with this? destroy the
975 connection perhaps? */
976 return NT_STATUS_UNSUCCESSFUL;
979 rep->data.length -= nwritten;
980 rep->data.data += nwritten;
982 if (rep->data.length == 0) {
983 /* we're done with this section of the call */
984 DLIST_REMOVE(call->replies, rep);
986 return STATUS_BUFFER_OVERFLOW;
989 if (call->replies == NULL) {
990 /* we're done with the whole call */
991 DLIST_REMOVE(dce_conn->call_list, call);
1000 write_fn() for dcesrv_output_blob()
1002 static ssize_t dcesrv_output_blob_write_fn(void *private, DATA_BLOB *out)
1004 DATA_BLOB *blob = private;
1005 if (out->length < blob->length) {
1006 blob->length = out->length;
1008 memcpy(blob->data, out->data, blob->length);
1009 return blob->length;
1013 a simple wrapper for dcesrv_output() for when we want to output
1016 NTSTATUS dcesrv_output_blob(struct dcesrv_connection *dce_conn,
1019 return dcesrv_output(dce_conn, blob, dcesrv_output_blob_write_fn);
1023 initialise the dcerpc server context
1025 NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **dce_ctx)
1028 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
1030 (*dce_ctx) = talloc_p(mem_ctx, struct dcesrv_context);
1032 return NT_STATUS_NO_MEMORY;
1035 (*dce_ctx)->endpoint_list = NULL;
1037 if (!endpoint_servers) {
1038 DEBUG(3,("dcesrv_init_context: no endpoint servers configured\n"));
1039 return NT_STATUS_OK;
1042 for (i=0;endpoint_servers[i];i++) {
1044 const struct dcesrv_endpoint_server *ep_server;
1046 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1048 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1049 return NT_STATUS_UNSUCCESSFUL;
1052 ret = ep_server->init_server(*dce_ctx, ep_server);
1053 if (!NT_STATUS_IS_OK(ret)) {
1054 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1059 return NT_STATUS_OK;
1062 static void dcesrv_init(struct server_service *service, const struct model_ops *model_ops)
1064 struct dcesrv_context *dce_ctx;
1066 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
1068 DEBUG(1,("dcesrv_init\n"));
1070 if (!endpoint_servers) {
1071 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1075 dce_ctx = talloc_p(service, struct dcesrv_context);
1077 DEBUG(0,("talloc_p(mem_ctx, struct dcesrv_context) failed\n"));
1081 ZERO_STRUCTP(dce_ctx);
1082 dce_ctx->endpoint_list = NULL;
1084 for (i=0;endpoint_servers[i];i++) {
1086 const struct dcesrv_endpoint_server *ep_server;
1088 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1090 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1094 ret = ep_server->init_server(dce_ctx, ep_server);
1095 if (!NT_STATUS_IS_OK(ret)) {
1096 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1101 dcesrv_sock_init(service, model_ops, dce_ctx);
1106 static void dcesrv_accept(struct server_connection *srv_conn)
1108 dcesrv_sock_accept(srv_conn);
1111 static void dcesrv_recv(struct server_connection *srv_conn,
1112 struct timeval t, uint16_t flags)
1114 dcesrv_sock_recv(srv_conn, t, flags);
1117 static void dcesrv_send(struct server_connection *srv_conn,
1118 struct timeval t, uint16_t flags)
1120 dcesrv_sock_send(srv_conn, t, flags);
1123 static void dcesrv_close(struct server_connection *srv_conn, const char *reason)
1125 dcesrv_sock_close(srv_conn, reason);
1129 static void dcesrv_exit(struct server_service *service, const char *reason)
1131 dcesrv_sock_exit(service, reason);
1135 /* the list of currently registered DCERPC endpoint servers.
1137 static struct ep_server {
1138 struct dcesrv_endpoint_server *ep_server;
1139 } *ep_servers = NULL;
1140 static int num_ep_servers;
1143 register a DCERPC endpoint server.
1145 The 'name' can be later used by other backends to find the operations
1146 structure for this backend.
1148 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1150 NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1152 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1154 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1155 /* its already registered! */
1156 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1158 return NT_STATUS_OBJECT_NAME_COLLISION;
1161 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1163 smb_panic("out of memory in dcerpc_register");
1166 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1167 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1171 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1174 return NT_STATUS_OK;
1178 return the operations structure for a named backend of the specified type
1180 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1184 for (i=0;i<num_ep_servers;i++) {
1185 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1186 return ep_servers[i].ep_server;
1194 return the DCERPC module version, and the size of some critical types
1195 This can be used by endpoint server modules to either detect compilation errors, or provide
1196 multiple implementations for different smbd compilation options in one module
1198 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1200 static const struct dcesrv_critical_sizes critical_sizes = {
1201 DCERPC_MODULE_VERSION,
1202 sizeof(struct dcesrv_context),
1203 sizeof(struct dcesrv_endpoint),
1204 sizeof(struct dcesrv_endpoint_server),
1205 sizeof(struct dcesrv_interface),
1206 sizeof(struct dcesrv_if_list),
1207 sizeof(struct dcesrv_connection),
1208 sizeof(struct dcesrv_call_state),
1209 sizeof(struct dcesrv_auth),
1210 sizeof(struct dcesrv_handle)
1213 return &critical_sizes;
1216 static const struct server_service_ops dcesrv_ops = {
1218 .service_init = dcesrv_init,
1219 .accept_connection = dcesrv_accept,
1220 .recv_handler = dcesrv_recv,
1221 .send_handler = dcesrv_send,
1222 .idle_handler = NULL,
1223 .close_connection = dcesrv_close,
1224 .service_exit = dcesrv_exit,
1227 const struct server_service_ops *dcesrv_get_ops(void)
1232 NTSTATUS server_service_rpc_init(void)
1234 return NT_STATUS_OK;