2 Unix SMB/CIFS implementation.
4 server side dcerpc core code
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) Stefan (metze) Metzmacher 2004-2005
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"
33 see if two endpoints match
35 static BOOL endpoints_match(const struct dcerpc_binding *ep1,
36 const struct dcerpc_binding *ep2)
38 if (ep1->transport != ep2->transport) {
42 if (!ep1->endpoint || !ep2->endpoint) {
43 return ep1->endpoint == ep2->endpoint;
46 if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
53 find an endpoint in the dcesrv_context
55 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
56 const struct dcerpc_binding *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 find a registered context_id from a bind or alter_context
70 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn,
73 struct dcesrv_connection_context *c;
74 for (c=conn->contexts;c;c=c->next) {
75 if (c->context_id == context_id) return c;
81 see if a uuid and if_version match to an interface
83 static BOOL interface_match(const struct dcesrv_interface *if1,
84 const struct dcesrv_interface *if2)
86 if (if1->if_version != if2->if_version) {
90 if (strcmp(if1->uuid, if2->uuid)==0) {
98 find the interface operations on an endpoint
100 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
101 const struct dcesrv_interface *iface)
103 struct dcesrv_if_list *ifl;
104 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
105 if (interface_match(&(ifl->iface), iface)) {
106 return &(ifl->iface);
113 see if a uuid and if_version match to an interface
115 static BOOL interface_match_by_uuid(const struct dcesrv_interface *iface,
116 const char *uuid, uint32_t if_version)
118 if (iface->if_version != if_version) {
122 if (strcmp(iface->uuid, uuid)==0) {
130 find the interface operations on an endpoint by uuid
132 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
133 const char *uuid, uint32_t if_version)
135 struct dcesrv_if_list *ifl;
136 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
137 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
138 return &(ifl->iface);
145 find a call that is pending in our call list
147 static struct dcesrv_call_state *dcesrv_find_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
149 struct dcesrv_call_state *c;
150 for (c=dce_conn->call_list;c;c=c->next) {
151 if (c->pkt.call_id == call_id) {
159 register an interface on an endpoint
161 NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
163 const struct dcesrv_interface *iface,
164 const struct security_descriptor *sd)
166 struct dcesrv_endpoint *ep;
167 struct dcesrv_if_list *ifl;
168 struct dcerpc_binding binding;
172 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
174 if (NT_STATUS_IS_ERR(status)) {
175 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
179 /* check if this endpoint exists
181 if ((ep=find_endpoint(dce_ctx, &binding))==NULL) {
182 ep = talloc_p(dce_ctx, struct dcesrv_endpoint);
184 return NT_STATUS_NO_MEMORY;
187 ep->ep_description = binding;
191 /* see if the interface is already registered on te endpoint */
192 if (find_interface(ep, iface)!=NULL) {
193 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
194 iface->name, ep_name));
195 return NT_STATUS_OBJECT_NAME_COLLISION;
198 /* talloc a new interface list element */
199 ifl = talloc_p(dce_ctx, struct dcesrv_if_list);
201 return NT_STATUS_NO_MEMORY;
204 /* copy the given interface struct to the one on the endpoints interface list */
205 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
207 /* if we have a security descriptor given,
208 * we should see if we can set it up on the endpoint
211 /* if there's currently no security descriptor given on the endpoint
214 if (ep->sd == NULL) {
215 ep->sd = security_descriptor_copy(dce_ctx, sd);
218 /* if now there's no security descriptor given on the endpoint
219 * something goes wrong, either we failed to copy the security descriptor
220 * or there was already one on the endpoint
222 if (ep->sd != NULL) {
223 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
224 " on endpoint '%s'\n",
225 iface->name, ep_name));
226 if (add_ep) free(ep);
228 return NT_STATUS_OBJECT_NAME_COLLISION;
232 /* finally add the interface on the endpoint */
233 DLIST_ADD(ep->interface_list, ifl);
235 /* if it's a new endpoint add it to the dcesrv_context */
237 DLIST_ADD(dce_ctx->endpoint_list, ep);
240 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
241 iface->name, ep_name));
246 static NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
247 DATA_BLOB *session_key)
249 if (p->auth_state.session_info->session_key.length) {
250 *session_key = p->auth_state.session_info->session_key;
253 return NT_STATUS_NO_USER_SESSION_KEY;
256 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
257 DATA_BLOB *session_key)
259 /* this took quite a few CPU cycles to find ... */
260 session_key->data = discard_const_p(uint8_t, "SystemLibraryDTC");
261 session_key->length = 16;
266 fetch the user session key - may be default (above) or the SMB session key
268 NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
269 DATA_BLOB *session_key)
271 return p->auth_state.session_key(p, session_key);
276 destroy a link to an endpoint
278 static int dcesrv_endpoint_destructor(void *ptr)
280 struct dcesrv_connection *p = ptr;
282 while (p->contexts) {
283 struct dcesrv_connection_context *c = p->contexts;
285 DLIST_REMOVE(p->contexts, c);
288 c->iface->unbind(c, c->iface);
297 connect to a dcerpc endpoint
299 NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
301 const struct dcesrv_endpoint *ep,
302 struct server_connection *srv_conn,
303 struct dcesrv_connection **_p)
305 struct dcesrv_connection *p;
307 p = talloc(mem_ctx, struct dcesrv_connection);
308 NT_STATUS_HAVE_NO_MEMORY(p);
310 p->dce_ctx = dce_ctx;
314 p->pending_call_list = NULL;
315 p->cli_max_recv_frag = 0;
316 p->partial_input = data_blob(NULL, 0);
317 p->auth_state.auth_info = NULL;
318 p->auth_state.gensec_security = NULL;
319 p->auth_state.session_info = NULL;
320 p->auth_state.session_key = dcesrv_generic_session_key;
321 p->srv_conn = srv_conn;
323 talloc_set_destructor(p, dcesrv_endpoint_destructor);
330 search and connect to a dcerpc endpoint
332 NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
334 const struct dcerpc_binding *ep_description,
335 struct auth_session_info *session_info,
336 struct server_connection *srv_conn,
337 struct dcesrv_connection **dce_conn_p)
340 const struct dcesrv_endpoint *ep;
342 /* make sure this endpoint exists */
343 ep = find_endpoint(dce_ctx, ep_description);
345 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
348 status = dcesrv_endpoint_connect(dce_ctx, mem_ctx, ep, srv_conn, dce_conn_p);
349 if (!NT_STATUS_IS_OK(status)) {
353 (*dce_conn_p)->auth_state.session_info = talloc_reference((*dce_conn_p), session_info);
354 (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
356 /* TODO: check security descriptor of the endpoint here
357 * if it's a smb named pipe
358 * if it's failed free dce_conn_p
365 static void dcesrv_init_hdr(struct dcerpc_packet *pkt)
368 pkt->rpc_vers_minor = 0;
369 if (lp_rpc_big_endian()) {
372 pkt->drep[0] = DCERPC_DREP_LE;
380 return a dcerpc fault
382 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
384 struct dcerpc_packet pkt;
385 struct dcesrv_call_reply *rep;
388 /* setup a bind_ack */
389 dcesrv_init_hdr(&pkt);
391 pkt.call_id = call->pkt.call_id;
392 pkt.ptype = DCERPC_PKT_FAULT;
393 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
394 pkt.u.fault.alloc_hint = 0;
395 pkt.u.fault.context_id = 0;
396 pkt.u.fault.cancel_count = 0;
397 pkt.u.fault.status = fault_code;
399 rep = talloc_p(call, struct dcesrv_call_reply);
401 return NT_STATUS_NO_MEMORY;
404 status = dcerpc_push_auth(&rep->data, call, &pkt, NULL);
405 if (!NT_STATUS_IS_OK(status)) {
409 dcerpc_set_frag_length(&rep->data, rep->data.length);
411 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
412 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
419 return a dcerpc bind_nak
421 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
423 struct dcerpc_packet pkt;
424 struct dcesrv_call_reply *rep;
427 /* setup a bind_nak */
428 dcesrv_init_hdr(&pkt);
430 pkt.call_id = call->pkt.call_id;
431 pkt.ptype = DCERPC_PKT_BIND_NAK;
432 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
433 pkt.u.bind_nak.reject_reason = reason;
434 pkt.u.bind_nak.num_versions = 0;
436 rep = talloc_p(call, struct dcesrv_call_reply);
438 return NT_STATUS_NO_MEMORY;
441 status = dcerpc_push_auth(&rep->data, call, &pkt, NULL);
442 if (!NT_STATUS_IS_OK(status)) {
446 dcerpc_set_frag_length(&rep->data, rep->data.length);
448 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
449 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
456 handle a bind request
458 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
460 const char *uuid, *transfer_syntax;
461 uint32_t if_version, transfer_syntax_version;
462 struct dcerpc_packet pkt;
463 struct dcesrv_call_reply *rep;
465 uint32_t result=0, reason=0;
467 const struct dcesrv_interface *iface;
469 if (call->pkt.u.bind.num_contexts != 1 ||
470 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
471 return dcesrv_bind_nak(call, 0);
474 context_id = call->pkt.u.bind.ctx_list[0].context_id;
476 /* you can't bind twice on one context */
477 if (dcesrv_find_context(call->conn, context_id) != NULL) {
478 return dcesrv_bind_nak(call, 0);
481 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
482 uuid = GUID_string(call, &call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid);
484 return dcesrv_bind_nak(call, 0);
487 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
488 transfer_syntax = GUID_string(call,
489 &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid);
490 if (!transfer_syntax ||
491 strcasecmp(NDR_GUID, transfer_syntax) != 0 ||
492 NDR_GUID_VERSION != transfer_syntax_version) {
493 /* we only do NDR encoded dcerpc */
494 return dcesrv_bind_nak(call, 0);
497 iface = find_interface_by_uuid(call->conn->endpoint, uuid, if_version);
499 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
500 /* we don't know about that interface */
501 result = DCERPC_BIND_PROVIDER_REJECT;
502 reason = DCERPC_BIND_REASON_ASYNTAX;
506 /* add this context to the list of available context_ids */
507 struct dcesrv_connection_context *context = talloc(call->conn,
508 struct dcesrv_connection_context);
509 if (context == NULL) {
510 return dcesrv_bind_nak(call, 0);
512 context->conn = call->conn;
513 context->iface = iface;
514 context->context_id = context_id;
515 context->private = NULL;
516 context->handles = NULL;
517 DLIST_ADD(call->conn->contexts, context);
518 call->context = context;
521 if (call->conn->cli_max_recv_frag == 0) {
522 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
525 /* handle any authentication that is being requested */
526 if (!dcesrv_auth_bind(call)) {
527 /* TODO: work out the right reject code */
528 return dcesrv_bind_nak(call, 0);
531 /* setup a bind_ack */
532 dcesrv_init_hdr(&pkt);
534 pkt.call_id = call->pkt.call_id;
535 pkt.ptype = DCERPC_PKT_BIND_ACK;
536 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
537 pkt.u.bind_ack.max_xmit_frag = 0x2000;
538 pkt.u.bind_ack.max_recv_frag = 0x2000;
539 pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
541 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
542 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
544 pkt.u.bind_ack.secondary_address = "";
546 pkt.u.bind_ack.num_results = 1;
547 pkt.u.bind_ack.ctx_list = talloc_p(call, struct dcerpc_ack_ctx);
548 if (!pkt.u.bind_ack.ctx_list) {
549 return NT_STATUS_NO_MEMORY;
551 pkt.u.bind_ack.ctx_list[0].result = result;
552 pkt.u.bind_ack.ctx_list[0].reason = reason;
553 GUID_from_string(NDR_GUID, &pkt.u.bind_ack.ctx_list[0].syntax.uuid);
554 pkt.u.bind_ack.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
555 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
557 if (!dcesrv_auth_bind_ack(call, &pkt)) {
558 return dcesrv_bind_nak(call, 0);
562 status = iface->bind(call, iface);
563 if (!NT_STATUS_IS_OK(status)) {
564 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
565 uuid, if_version, nt_errstr(status)));
566 return dcesrv_bind_nak(call, 0);
570 rep = talloc(call, struct dcesrv_call_reply);
572 return NT_STATUS_NO_MEMORY;
575 status = dcerpc_push_auth(&rep->data, call, &pkt,
576 call->conn->auth_state.auth_info);
577 if (!NT_STATUS_IS_OK(status)) {
581 dcerpc_set_frag_length(&rep->data, rep->data.length);
583 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
584 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
591 handle a auth3 request
593 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
595 /* handle the auth3 in the auth code */
596 if (!dcesrv_auth_auth3(call)) {
597 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
602 /* we don't send a reply to a auth3 request, except by a
609 handle a bind request
611 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32 context_id)
613 uint32_t if_version, transfer_syntax_version;
614 const char *uuid, *transfer_syntax;
615 struct dcesrv_connection_context *context;
616 const struct dcesrv_interface *iface;
618 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
619 uuid = GUID_string(call, &call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid);
621 return NT_STATUS_NO_MEMORY;
624 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
625 transfer_syntax = GUID_string(call,
626 &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid);
627 if (!transfer_syntax ||
628 strcasecmp(NDR_GUID, transfer_syntax) != 0 ||
629 NDR_GUID_VERSION != transfer_syntax_version) {
630 /* we only do NDR encoded dcerpc */
631 return NT_STATUS_NO_MEMORY;
634 iface = find_interface_by_uuid(call->conn->endpoint, uuid, if_version);
636 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
637 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
640 /* add this context to the list of available context_ids */
641 context = talloc(call->conn, struct dcesrv_connection_context);
642 if (context == NULL) {
643 return NT_STATUS_NO_MEMORY;
645 context->conn = call->conn;
646 context->iface = iface;
647 context->context_id = context_id;
648 context->private = NULL;
649 context->handles = NULL;
650 DLIST_ADD(call->conn->contexts, context);
651 call->context = context;
658 handle a bind request
660 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
662 struct dcerpc_packet pkt;
663 struct dcesrv_call_reply *rep;
665 uint32_t result=0, reason=0;
668 /* handle any authentication that is being requested */
669 if (!dcesrv_auth_alter(call)) {
670 /* TODO: work out the right reject code */
671 result = DCERPC_BIND_PROVIDER_REJECT;
672 reason = DCERPC_BIND_REASON_ASYNTAX;
675 context_id = call->pkt.u.alter.ctx_list[0].context_id;
677 /* see if they are asking for a new interface */
679 dcesrv_find_context(call->conn, context_id) == NULL) {
680 status = dcesrv_alter_new_context(call, context_id);
681 if (!NT_STATUS_IS_OK(status)) {
682 result = DCERPC_BIND_PROVIDER_REJECT;
683 reason = DCERPC_BIND_REASON_ASYNTAX;
687 /* setup a alter_resp */
688 dcesrv_init_hdr(&pkt);
690 pkt.call_id = call->pkt.call_id;
691 pkt.ptype = DCERPC_PKT_ALTER_RESP;
692 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
693 pkt.u.alter_resp.max_xmit_frag = 0x2000;
694 pkt.u.alter_resp.max_recv_frag = 0x2000;
695 pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
696 pkt.u.alter_resp.num_results = 1;
697 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
698 if (!pkt.u.alter_resp.ctx_list) {
699 return NT_STATUS_NO_MEMORY;
701 pkt.u.alter_resp.ctx_list[0].result = result;
702 pkt.u.alter_resp.ctx_list[0].reason = reason;
703 GUID_from_string(NDR_GUID, &pkt.u.alter_resp.ctx_list[0].syntax.uuid);
704 pkt.u.alter_resp.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
705 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
706 pkt.u.alter_resp.secondary_address = "";
708 if (!dcesrv_auth_alter_ack(call, &pkt)) {
709 return dcesrv_bind_nak(call, 0);
712 rep = talloc_p(call, struct dcesrv_call_reply);
714 return NT_STATUS_NO_MEMORY;
717 status = dcerpc_push_auth(&rep->data, call, &pkt,
718 call->conn->auth_state.auth_info);
719 if (!NT_STATUS_IS_OK(status)) {
723 dcerpc_set_frag_length(&rep->data, rep->data.length);
725 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
726 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
732 handle a dcerpc request packet
734 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
736 struct ndr_pull *pull;
738 struct dcesrv_connection_context *context;
740 call->fault_code = 0;
741 call->state_flags = call->conn->dce_ctx->state_flags;
742 call->time = timeval_current();
744 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
745 if (context == NULL) {
746 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
749 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
750 NT_STATUS_HAVE_NO_MEMORY(pull);
752 call->context = context;
753 call->event_ctx = context->conn->srv_conn->event.ctx;
754 call->ndr_pull = pull;
756 if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_ORPC) {
757 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
760 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
761 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
764 /* unravel the NDR for the packet */
765 status = context->iface->ndr_pull(call, call, pull, &call->r);
766 if (!NT_STATUS_IS_OK(status)) {
767 return dcesrv_fault(call, call->fault_code);
770 if (pull->offset != pull->data_size) {
771 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
772 pull->data_size - pull->offset));
773 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
776 /* call the dispatch function */
777 status = context->iface->dispatch(call, call, call->r);
778 if (!NT_STATUS_IS_OK(status)) {
779 return dcesrv_fault(call, call->fault_code);
782 /* add the call to the pending list */
783 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
785 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
789 return dcesrv_reply(call);
792 NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
794 struct ndr_push *push;
797 uint32_t total_length;
798 struct dcesrv_connection_context *context = call->context;
800 /* call the reply function */
801 status = context->iface->reply(call, call, call->r);
802 if (!NT_STATUS_IS_OK(status)) {
803 return dcesrv_fault(call, call->fault_code);
806 /* form the reply NDR */
807 push = ndr_push_init_ctx(call);
808 NT_STATUS_HAVE_NO_MEMORY(push);
810 /* carry over the pointer count to the reply in case we are
811 using full pointer. See NDR specification for full
813 push->ptr_count = call->ndr_pull->ptr_count;
815 if (lp_rpc_big_endian()) {
816 push->flags |= LIBNDR_FLAG_BIGENDIAN;
819 status = context->iface->ndr_push(call, call, push, call->r);
820 if (!NT_STATUS_IS_OK(status)) {
821 return dcesrv_fault(call, call->fault_code);
824 stub = ndr_push_blob(push);
826 total_length = stub.length;
830 struct dcesrv_call_reply *rep;
831 struct dcerpc_packet pkt;
833 rep = talloc(call, struct dcesrv_call_reply);
834 NT_STATUS_HAVE_NO_MEMORY(rep);
836 length = stub.length;
837 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
838 /* the 32 is to cope with signing data */
839 length = call->conn->cli_max_recv_frag -
840 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
843 /* form the dcerpc response packet */
844 dcesrv_init_hdr(&pkt);
846 pkt.call_id = call->pkt.call_id;
847 pkt.ptype = DCERPC_PKT_RESPONSE;
849 if (stub.length == total_length) {
850 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
852 if (length == stub.length) {
853 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
855 pkt.u.response.alloc_hint = stub.length;
856 pkt.u.response.context_id = call->pkt.u.request.context_id;
857 pkt.u.response.cancel_count = 0;
858 pkt.u.response.stub_and_verifier.data = stub.data;
859 pkt.u.response.stub_and_verifier.length = length;
861 if (!dcesrv_auth_response(call, &rep->data, &pkt)) {
862 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
865 dcerpc_set_frag_length(&rep->data, rep->data.length);
867 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
870 stub.length -= length;
871 } while (stub.length != 0);
873 /* move the call from the pending to the finished calls list */
874 DLIST_REMOVE(call->conn->pending_call_list, call);
875 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
877 if (call->conn->call_list && call->conn->call_list->replies) {
878 if (call->conn->srv_conn &&
879 call->conn->srv_conn->event.fde) {
880 call->conn->srv_conn->event.fde->flags |= EVENT_FD_WRITE;
889 work out if we have a full packet yet
891 static BOOL dce_full_packet(const DATA_BLOB *data)
893 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
896 if (dcerpc_get_frag_length(data) > data->length) {
903 we might have consumed only part of our input - advance past that part
905 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
909 if (dce_conn->partial_input.length == offset) {
910 data_blob_free(&dce_conn->partial_input);
914 blob = dce_conn->partial_input;
915 dce_conn->partial_input = data_blob(blob.data + offset,
916 blob.length - offset);
917 data_blob_free(&blob);
921 process some input to a dcerpc endpoint server.
923 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
925 struct ndr_pull *ndr;
927 struct dcesrv_call_state *call;
930 call = talloc(dce_conn, struct dcesrv_call_state);
932 talloc_free(dce_conn->partial_input.data);
933 return NT_STATUS_NO_MEMORY;
935 call->conn = dce_conn;
936 call->replies = NULL;
937 call->context = NULL;
939 blob = dce_conn->partial_input;
940 blob.length = dcerpc_get_frag_length(&blob);
942 ndr = ndr_pull_init_blob(&blob, call);
944 talloc_free(dce_conn->partial_input.data);
946 return NT_STATUS_NO_MEMORY;
949 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
950 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
953 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
954 if (!NT_STATUS_IS_OK(status)) {
955 talloc_free(dce_conn->partial_input.data);
960 /* we have to check the signing here, before combining the
962 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
963 !dcesrv_auth_request(call, &blob)) {
964 dce_partial_advance(dce_conn, blob.length);
965 return dcesrv_fault(call, DCERPC_FAULT_LOGON_FAILURE);
968 dce_partial_advance(dce_conn, blob.length);
970 /* see if this is a continued packet */
971 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
972 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
973 struct dcesrv_call_state *call2 = call;
976 /* we only allow fragmented requests, no other packet types */
977 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
978 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
981 /* this is a continuation of an existing call - find the call then
982 tack it on the end */
983 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
985 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
988 if (call->pkt.ptype != call2->pkt.ptype) {
989 /* trying to play silly buggers are we? */
990 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
993 alloc_size = call->pkt.u.request.stub_and_verifier.length +
994 call2->pkt.u.request.stub_and_verifier.length;
995 if (call->pkt.u.request.alloc_hint > alloc_size) {
996 alloc_size = call->pkt.u.request.alloc_hint;
999 call->pkt.u.request.stub_and_verifier.data =
1000 talloc_realloc(call,
1001 call->pkt.u.request.stub_and_verifier.data,
1002 uint8_t, alloc_size);
1003 if (!call->pkt.u.request.stub_and_verifier.data) {
1004 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1006 memcpy(call->pkt.u.request.stub_and_verifier.data +
1007 call->pkt.u.request.stub_and_verifier.length,
1008 call2->pkt.u.request.stub_and_verifier.data,
1009 call2->pkt.u.request.stub_and_verifier.length);
1010 call->pkt.u.request.stub_and_verifier.length +=
1011 call2->pkt.u.request.stub_and_verifier.length;
1013 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1018 /* this may not be the last pdu in the chain - if its isn't then
1019 just put it on the call_list and wait for the rest */
1020 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1021 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1022 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
1023 return NT_STATUS_OK;
1026 switch (call->pkt.ptype) {
1027 case DCERPC_PKT_BIND:
1028 status = dcesrv_bind(call);
1030 case DCERPC_PKT_AUTH3:
1031 status = dcesrv_auth3(call);
1033 case DCERPC_PKT_ALTER:
1034 status = dcesrv_alter(call);
1036 case DCERPC_PKT_REQUEST:
1037 status = dcesrv_request(call);
1040 status = NT_STATUS_INVALID_PARAMETER;
1044 /* if we are going to be sending a reply then add
1045 it to the list of pending calls. We add it to the end to keep the call
1046 list in the order we will answer */
1047 if (!NT_STATUS_IS_OK(status)) {
1056 provide some input to a dcerpc endpoint server. This passes data
1057 from a dcerpc client into the server
1059 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1063 dce_conn->partial_input.data = talloc_realloc(dce_conn,
1064 dce_conn->partial_input.data,
1066 dce_conn->partial_input.length + data->length);
1067 if (!dce_conn->partial_input.data) {
1068 return NT_STATUS_NO_MEMORY;
1070 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1071 data->data, data->length);
1072 dce_conn->partial_input.length += data->length;
1074 while (dce_full_packet(&dce_conn->partial_input)) {
1075 status = dcesrv_input_process(dce_conn);
1076 if (!NT_STATUS_IS_OK(status)) {
1081 return NT_STATUS_OK;
1085 retrieve some output from a dcerpc server
1086 The caller supplies a function that will be called to do the
1089 The first argument to write_fn() will be 'private', the second will
1090 be a pointer to a buffer containing the data to be sent and the 3rd
1091 will be the number of bytes to be sent.
1093 write_fn() should return the number of bytes successfully written.
1095 this will return STATUS_BUFFER_OVERFLOW if there is more to be read
1096 from the current fragment
1098 NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
1100 ssize_t (*write_fn)(void *, DATA_BLOB *))
1102 struct dcesrv_call_state *call;
1103 struct dcesrv_call_reply *rep;
1106 call = dce_conn->call_list;
1107 if (!call || !call->replies) {
1108 if (dce_conn->pending_call_list) {
1109 /* TODO: we need to say act async here
1110 * as we know we have pending requests
1111 * which will be finished at a time
1113 return NT_STATUS_FOOBAR;
1115 return NT_STATUS_FOOBAR;
1117 rep = call->replies;
1119 nwritten = write_fn(private, &rep->data);
1120 if (nwritten == -1) {
1121 /* TODO: hmm, how do we cope with this? destroy the
1122 connection perhaps? */
1123 return NT_STATUS_UNSUCCESSFUL;
1126 rep->data.length -= nwritten;
1127 rep->data.data += nwritten;
1129 if (rep->data.length == 0) {
1130 /* we're done with this section of the call */
1131 DLIST_REMOVE(call->replies, rep);
1133 return STATUS_BUFFER_OVERFLOW;
1136 if (call->replies == NULL) {
1137 /* we're done with the whole call */
1138 DLIST_REMOVE(dce_conn->call_list, call);
1142 return NT_STATUS_OK;
1147 write_fn() for dcesrv_output_blob()
1149 static ssize_t dcesrv_output_blob_write_fn(void *private, DATA_BLOB *out)
1151 DATA_BLOB *blob = private;
1152 if (out->length < blob->length) {
1153 blob->length = out->length;
1155 memcpy(blob->data, out->data, blob->length);
1156 return blob->length;
1160 a simple wrapper for dcesrv_output() for when we want to output
1163 NTSTATUS dcesrv_output_blob(struct dcesrv_connection *dce_conn,
1166 return dcesrv_output(dce_conn, blob, dcesrv_output_blob_write_fn);
1169 static NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, const char **endpoint_servers, uint32_t state_flags, struct dcesrv_context **_dce_ctx)
1172 struct dcesrv_context *dce_ctx;
1175 DEBUG(1,("dcesrv_init\n"));
1177 if (!endpoint_servers) {
1178 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1179 return NT_STATUS_INTERNAL_ERROR;
1182 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1183 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1184 dce_ctx->endpoint_list = NULL;
1185 dce_ctx->state_flags = state_flags;
1187 for (i=0;endpoint_servers[i];i++) {
1188 const struct dcesrv_endpoint_server *ep_server;
1190 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1192 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1193 return NT_STATUS_INTERNAL_ERROR;
1196 status = ep_server->init_server(dce_ctx, ep_server);
1197 if (!NT_STATUS_IS_OK(status)) {
1198 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1199 nt_errstr(status)));
1204 *_dce_ctx = dce_ctx;
1205 return NT_STATUS_OK;
1209 initialise the dcerpc server context
1211 NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **_dce_ctx)
1214 struct dcesrv_context *dce_ctx;
1216 status = dcesrv_init_context(mem_ctx, lp_dcerpc_endpoint_servers(), 0, &dce_ctx);
1217 NT_STATUS_NOT_OK_RETURN(status);
1219 *_dce_ctx = dce_ctx;
1220 return NT_STATUS_OK;
1223 static void dcesrv_init(struct server_service *service)
1226 struct dcesrv_context *dce_ctx;
1228 DEBUG(1,("dcesrv_init\n"));
1230 status = dcesrv_init_context(service,
1231 lp_dcerpc_endpoint_servers(),
1232 DCESRV_CALL_STATE_FLAG_MAY_ASYNC,
1234 if (!NT_STATUS_IS_OK(status)) {
1238 service->service.private_data = dce_ctx;
1240 dcesrv_sock_init(service);
1245 static void dcesrv_accept(struct server_connection *srv_conn)
1247 dcesrv_sock_accept(srv_conn);
1250 static void dcesrv_recv(struct server_connection *srv_conn,
1251 struct timeval t, uint16_t flags)
1253 dcesrv_sock_recv(srv_conn, t, flags);
1256 static void dcesrv_send(struct server_connection *srv_conn,
1257 struct timeval t, uint16_t flags)
1259 dcesrv_sock_send(srv_conn, t, flags);
1262 /* the list of currently registered DCERPC endpoint servers.
1264 static struct ep_server {
1265 struct dcesrv_endpoint_server *ep_server;
1266 } *ep_servers = NULL;
1267 static int num_ep_servers;
1270 register a DCERPC endpoint server.
1272 The 'name' can be later used by other backends to find the operations
1273 structure for this backend.
1275 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1277 NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1279 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1281 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1282 /* its already registered! */
1283 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1285 return NT_STATUS_OBJECT_NAME_COLLISION;
1288 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1290 smb_panic("out of memory in dcerpc_register");
1293 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1294 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1298 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1301 return NT_STATUS_OK;
1305 return the operations structure for a named backend of the specified type
1307 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1311 for (i=0;i<num_ep_servers;i++) {
1312 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1313 return ep_servers[i].ep_server;
1321 return the DCERPC module version, and the size of some critical types
1322 This can be used by endpoint server modules to either detect compilation errors, or provide
1323 multiple implementations for different smbd compilation options in one module
1325 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1327 static const struct dcesrv_critical_sizes critical_sizes = {
1328 DCERPC_MODULE_VERSION,
1329 sizeof(struct dcesrv_context),
1330 sizeof(struct dcesrv_endpoint),
1331 sizeof(struct dcesrv_endpoint_server),
1332 sizeof(struct dcesrv_interface),
1333 sizeof(struct dcesrv_if_list),
1334 sizeof(struct dcesrv_connection),
1335 sizeof(struct dcesrv_call_state),
1336 sizeof(struct dcesrv_auth),
1337 sizeof(struct dcesrv_handle)
1340 return &critical_sizes;
1343 static const struct server_stream_ops dcesrv_stream_ops = {
1345 .socket_init = NULL,
1346 .accept_connection = dcesrv_accept,
1347 .recv_handler = dcesrv_recv,
1348 .send_handler = dcesrv_send,
1349 .idle_handler = NULL,
1350 .close_connection = NULL
1353 const struct server_stream_ops *dcesrv_get_stream_ops(void)
1355 return &dcesrv_stream_ops;
1358 static const struct server_service_ops dcesrv_ops = {
1360 .service_init = dcesrv_init,
1363 const struct server_service_ops *dcesrv_get_ops(void)
1368 NTSTATUS server_service_rpc_init(void)
1370 return NT_STATUS_OK;