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_ACK;
584 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
585 pkt.u.alter_ack.max_xmit_frag = 0x2000;
586 pkt.u.alter_ack.max_recv_frag = 0x2000;
587 pkt.u.alter_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
588 pkt.u.alter_ack.secondary_address = NULL;
589 pkt.u.alter_ack.num_results = 1;
590 pkt.u.alter_ack.ctx_list = talloc_p(call, struct dcerpc_ack_ctx);
591 if (!pkt.u.alter_ack.ctx_list) {
592 return NT_STATUS_NO_MEMORY;
594 pkt.u.alter_ack.ctx_list[0].result = result;
595 pkt.u.alter_ack.ctx_list[0].reason = reason;
596 GUID_from_string(NDR_GUID, &pkt.u.alter_ack.ctx_list[0].syntax.uuid);
597 pkt.u.alter_ack.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
598 pkt.u.alter_ack.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 =
860 talloc_realloc(call, call->pkt.u.request.stub_and_verifier.data, alloc_size);
861 if (!call->pkt.u.request.stub_and_verifier.data) {
862 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
864 memcpy(call->pkt.u.request.stub_and_verifier.data +
865 call->pkt.u.request.stub_and_verifier.length,
866 call2->pkt.u.request.stub_and_verifier.data,
867 call2->pkt.u.request.stub_and_verifier.length);
868 call->pkt.u.request.stub_and_verifier.length +=
869 call2->pkt.u.request.stub_and_verifier.length;
871 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
876 /* this may not be the last pdu in the chain - if its isn't then
877 just put it on the call_list and wait for the rest */
878 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
879 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
880 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
884 switch (call->pkt.ptype) {
885 case DCERPC_PKT_BIND:
886 status = dcesrv_bind(call);
888 case DCERPC_PKT_AUTH3:
889 status = dcesrv_auth3(call);
891 case DCERPC_PKT_ALTER:
892 status = dcesrv_alter(call);
894 case DCERPC_PKT_REQUEST:
895 status = dcesrv_request(call);
898 status = NT_STATUS_INVALID_PARAMETER;
902 /* if we are going to be sending a reply then add
903 it to the list of pending calls. We add it to the end to keep the call
904 list in the order we will answer */
905 if (!NT_STATUS_IS_OK(status)) {
914 provide some input to a dcerpc endpoint server. This passes data
915 from a dcerpc client into the server
917 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
921 dce_conn->partial_input.data = talloc_realloc(dce_conn,
922 dce_conn->partial_input.data,
923 dce_conn->partial_input.length + data->length);
924 if (!dce_conn->partial_input.data) {
925 return NT_STATUS_NO_MEMORY;
927 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
928 data->data, data->length);
929 dce_conn->partial_input.length += data->length;
931 while (dce_full_packet(&dce_conn->partial_input)) {
932 status = dcesrv_input_process(dce_conn);
933 if (!NT_STATUS_IS_OK(status)) {
942 retrieve some output from a dcerpc server
943 The caller supplies a function that will be called to do the
946 The first argument to write_fn() will be 'private', the second will
947 be a pointer to a buffer containing the data to be sent and the 3rd
948 will be the number of bytes to be sent.
950 write_fn() should return the number of bytes successfully written.
952 this will return STATUS_BUFFER_OVERFLOW if there is more to be read
953 from the current fragment
955 NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
957 ssize_t (*write_fn)(void *, DATA_BLOB *))
959 struct dcesrv_call_state *call;
960 struct dcesrv_call_reply *rep;
963 call = dce_conn->call_list;
964 if (!call || !call->replies) {
965 return NT_STATUS_FOOBAR;
969 nwritten = write_fn(private, &rep->data);
970 if (nwritten == -1) {
971 /* TODO: hmm, how do we cope with this? destroy the
972 connection perhaps? */
973 return NT_STATUS_UNSUCCESSFUL;
976 rep->data.length -= nwritten;
977 rep->data.data += nwritten;
979 if (rep->data.length == 0) {
980 /* we're done with this section of the call */
981 DLIST_REMOVE(call->replies, rep);
983 return STATUS_BUFFER_OVERFLOW;
986 if (call->replies == NULL) {
987 /* we're done with the whole call */
988 DLIST_REMOVE(dce_conn->call_list, call);
997 write_fn() for dcesrv_output_blob()
999 static ssize_t dcesrv_output_blob_write_fn(void *private, DATA_BLOB *out)
1001 DATA_BLOB *blob = private;
1002 if (out->length < blob->length) {
1003 blob->length = out->length;
1005 memcpy(blob->data, out->data, blob->length);
1006 return blob->length;
1010 a simple wrapper for dcesrv_output() for when we want to output
1013 NTSTATUS dcesrv_output_blob(struct dcesrv_connection *dce_conn,
1016 return dcesrv_output(dce_conn, blob, dcesrv_output_blob_write_fn);
1020 initialise the dcerpc server context
1022 NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **dce_ctx)
1025 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
1027 (*dce_ctx) = talloc_p(mem_ctx, struct dcesrv_context);
1029 return NT_STATUS_NO_MEMORY;
1032 (*dce_ctx)->endpoint_list = NULL;
1034 if (!endpoint_servers) {
1035 DEBUG(3,("dcesrv_init_context: no endpoint servers configured\n"));
1036 return NT_STATUS_OK;
1039 for (i=0;endpoint_servers[i];i++) {
1041 const struct dcesrv_endpoint_server *ep_server;
1043 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1045 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1046 return NT_STATUS_UNSUCCESSFUL;
1049 ret = ep_server->init_server(*dce_ctx, ep_server);
1050 if (!NT_STATUS_IS_OK(ret)) {
1051 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1056 return NT_STATUS_OK;
1059 static void dcesrv_init(struct server_service *service, const struct model_ops *model_ops)
1061 struct dcesrv_context *dce_ctx;
1063 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
1065 DEBUG(1,("dcesrv_init\n"));
1067 if (!endpoint_servers) {
1068 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1072 dce_ctx = talloc_p(service, struct dcesrv_context);
1074 DEBUG(0,("talloc_p(mem_ctx, struct dcesrv_context) failed\n"));
1078 ZERO_STRUCTP(dce_ctx);
1079 dce_ctx->endpoint_list = NULL;
1081 for (i=0;endpoint_servers[i];i++) {
1083 const struct dcesrv_endpoint_server *ep_server;
1085 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1087 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1091 ret = ep_server->init_server(dce_ctx, ep_server);
1092 if (!NT_STATUS_IS_OK(ret)) {
1093 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1098 dcesrv_sock_init(service, model_ops, dce_ctx);
1103 static void dcesrv_accept(struct server_connection *srv_conn)
1105 dcesrv_sock_accept(srv_conn);
1108 static void dcesrv_recv(struct server_connection *srv_conn,
1109 struct timeval t, uint16_t flags)
1111 dcesrv_sock_recv(srv_conn, t, flags);
1114 static void dcesrv_send(struct server_connection *srv_conn,
1115 struct timeval t, uint16_t flags)
1117 dcesrv_sock_send(srv_conn, t, flags);
1120 static void dcesrv_close(struct server_connection *srv_conn, const char *reason)
1122 dcesrv_sock_close(srv_conn, reason);
1126 static void dcesrv_exit(struct server_service *service, const char *reason)
1128 dcesrv_sock_exit(service, reason);
1132 /* the list of currently registered DCERPC endpoint servers.
1134 static struct ep_server {
1135 struct dcesrv_endpoint_server *ep_server;
1136 } *ep_servers = NULL;
1137 static int num_ep_servers;
1140 register a DCERPC endpoint server.
1142 The 'name' can be later used by other backends to find the operations
1143 structure for this backend.
1145 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1147 NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1149 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1151 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1152 /* its already registered! */
1153 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1155 return NT_STATUS_OBJECT_NAME_COLLISION;
1158 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1160 smb_panic("out of memory in dcerpc_register");
1163 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1164 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1168 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1171 return NT_STATUS_OK;
1175 return the operations structure for a named backend of the specified type
1177 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1181 for (i=0;i<num_ep_servers;i++) {
1182 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1183 return ep_servers[i].ep_server;
1191 return the DCERPC module version, and the size of some critical types
1192 This can be used by endpoint server modules to either detect compilation errors, or provide
1193 multiple implementations for different smbd compilation options in one module
1195 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1197 static const struct dcesrv_critical_sizes critical_sizes = {
1198 DCERPC_MODULE_VERSION,
1199 sizeof(struct dcesrv_context),
1200 sizeof(struct dcesrv_endpoint),
1201 sizeof(struct dcesrv_endpoint_server),
1202 sizeof(struct dcesrv_interface),
1203 sizeof(struct dcesrv_if_list),
1204 sizeof(struct dcesrv_connection),
1205 sizeof(struct dcesrv_call_state),
1206 sizeof(struct dcesrv_auth),
1207 sizeof(struct dcesrv_handle)
1210 return &critical_sizes;
1213 static const struct server_service_ops dcesrv_ops = {
1215 .service_init = dcesrv_init,
1216 .accept_connection = dcesrv_accept,
1217 .recv_handler = dcesrv_recv,
1218 .send_handler = dcesrv_send,
1219 .idle_handler = NULL,
1220 .close_connection = dcesrv_close,
1221 .service_exit = dcesrv_exit,
1224 const struct server_service_ops *dcesrv_get_ops(void)
1229 NTSTATUS server_service_rpc_init(void)
1231 return NT_STATUS_OK;