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_dcerpc.h"
26 #include "auth/auth.h"
27 #include "dlinklist.h"
28 #include "rpc_server/dcerpc_server.h"
29 #include "lib/events/events.h"
30 #include "smbd/service_task.h"
31 #include "smbd/service_stream.h"
32 #include "smbd/service.h"
33 #include "system/filesys.h"
34 #include "libcli/security/security.h"
38 see if two endpoints match
40 static BOOL endpoints_match(const struct dcerpc_binding *ep1,
41 const struct dcerpc_binding *ep2)
43 if (ep1->transport != ep2->transport) {
47 if (!ep1->endpoint || !ep2->endpoint) {
48 return ep1->endpoint == ep2->endpoint;
51 if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
58 find an endpoint in the dcesrv_context
60 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
61 const struct dcerpc_binding *ep_description)
63 struct dcesrv_endpoint *ep;
64 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
65 if (endpoints_match(ep->ep_description, ep_description)) {
73 find a registered context_id from a bind or alter_context
75 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn,
78 struct dcesrv_connection_context *c;
79 for (c=conn->contexts;c;c=c->next) {
80 if (c->context_id == context_id) return c;
86 see if a uuid and if_version match to an interface
88 static BOOL interface_match(const struct dcesrv_interface *if1,
89 const struct dcesrv_interface *if2)
91 return (if1->syntax_id.if_version == if2->syntax_id.if_version &&
92 GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
96 find the interface operations on an endpoint
98 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
99 const struct dcesrv_interface *iface)
101 struct dcesrv_if_list *ifl;
102 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
103 if (interface_match(&(ifl->iface), iface)) {
104 return &(ifl->iface);
111 see if a uuid and if_version match to an interface
113 static BOOL interface_match_by_uuid(const struct dcesrv_interface *iface,
114 const struct GUID *uuid, uint32_t if_version)
116 return (iface->syntax_id.if_version == if_version &&
117 GUID_equal(&iface->syntax_id.uuid, uuid));
121 find the interface operations on an endpoint by uuid
123 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
124 const struct GUID *uuid, uint32_t if_version)
126 struct dcesrv_if_list *ifl;
127 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
128 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
129 return &(ifl->iface);
136 find a call that is pending in our call list
138 static struct dcesrv_call_state *dcesrv_find_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
140 struct dcesrv_call_state *c;
141 for (c=dce_conn->call_list;c;c=c->next) {
142 if (c->pkt.call_id == call_id) {
150 register an interface on an endpoint
152 NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
154 const struct dcesrv_interface *iface,
155 const struct security_descriptor *sd)
157 struct dcesrv_endpoint *ep;
158 struct dcesrv_if_list *ifl;
159 struct dcerpc_binding *binding;
163 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
165 if (NT_STATUS_IS_ERR(status)) {
166 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
170 /* check if this endpoint exists
172 if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
173 ep = talloc(dce_ctx, struct dcesrv_endpoint);
175 return NT_STATUS_NO_MEMORY;
178 ep->ep_description = talloc_reference(ep, binding);
182 /* see if the interface is already registered on te endpoint */
183 if (find_interface(ep, iface)!=NULL) {
184 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
185 iface->name, ep_name));
186 return NT_STATUS_OBJECT_NAME_COLLISION;
189 /* talloc a new interface list element */
190 ifl = talloc(dce_ctx, struct dcesrv_if_list);
192 return NT_STATUS_NO_MEMORY;
195 /* copy the given interface struct to the one on the endpoints interface list */
196 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
198 /* if we have a security descriptor given,
199 * we should see if we can set it up on the endpoint
202 /* if there's currently no security descriptor given on the endpoint
205 if (ep->sd == NULL) {
206 ep->sd = security_descriptor_copy(dce_ctx, sd);
209 /* if now there's no security descriptor given on the endpoint
210 * something goes wrong, either we failed to copy the security descriptor
211 * or there was already one on the endpoint
213 if (ep->sd != NULL) {
214 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
215 " on endpoint '%s'\n",
216 iface->name, ep_name));
217 if (add_ep) free(ep);
219 return NT_STATUS_OBJECT_NAME_COLLISION;
223 /* finally add the interface on the endpoint */
224 DLIST_ADD(ep->interface_list, ifl);
226 /* if it's a new endpoint add it to the dcesrv_context */
228 DLIST_ADD(dce_ctx->endpoint_list, ep);
231 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
232 iface->name, ep_name));
237 static NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
238 DATA_BLOB *session_key)
240 if (p->auth_state.session_info->session_key.length) {
241 *session_key = p->auth_state.session_info->session_key;
244 return NT_STATUS_NO_USER_SESSION_KEY;
247 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
248 DATA_BLOB *session_key)
250 /* this took quite a few CPU cycles to find ... */
251 session_key->data = discard_const_p(uint8_t, "SystemLibraryDTC");
252 session_key->length = 16;
257 fetch the user session key - may be default (above) or the SMB session key
259 NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
260 DATA_BLOB *session_key)
262 return p->auth_state.session_key(p, session_key);
267 destroy a link to an endpoint
269 static int dcesrv_endpoint_destructor(void *ptr)
271 struct dcesrv_connection *p = ptr;
273 while (p->contexts) {
274 struct dcesrv_connection_context *c = p->contexts;
276 DLIST_REMOVE(p->contexts, c);
279 c->iface->unbind(c, c->iface);
288 connect to a dcerpc endpoint
290 NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
292 const struct dcesrv_endpoint *ep,
293 struct auth_session_info *session_info,
294 struct event_context *event_ctx,
295 uint32_t state_flags,
296 struct dcesrv_connection **_p)
298 struct dcesrv_connection *p;
301 return NT_STATUS_ACCESS_DENIED;
304 p = talloc(mem_ctx, struct dcesrv_connection);
305 NT_STATUS_HAVE_NO_MEMORY(p);
307 if (!talloc_reference(p, session_info)) {
309 return NT_STATUS_NO_MEMORY;
312 p->dce_ctx = dce_ctx;
316 p->pending_call_list = NULL;
317 p->cli_max_recv_frag = 0;
318 p->partial_input = data_blob(NULL, 0);
319 p->auth_state.auth_info = NULL;
320 p->auth_state.gensec_security = NULL;
321 p->auth_state.session_info = session_info;
322 p->auth_state.session_key = dcesrv_generic_session_key;
323 p->event_ctx = event_ctx;
324 p->processing = False;
325 p->state_flags = state_flags;
326 ZERO_STRUCT(p->transport);
328 talloc_set_destructor(p, dcesrv_endpoint_destructor);
335 search and connect to a dcerpc endpoint
337 NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
339 const struct dcerpc_binding *ep_description,
340 struct auth_session_info *session_info,
341 struct event_context *event_ctx,
342 uint32_t state_flags,
343 struct dcesrv_connection **dce_conn_p)
346 const struct dcesrv_endpoint *ep;
348 /* make sure this endpoint exists */
349 ep = find_endpoint(dce_ctx, ep_description);
351 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
354 status = dcesrv_endpoint_connect(dce_ctx, mem_ctx, ep, session_info, event_ctx, state_flags, dce_conn_p);
355 NT_STATUS_NOT_OK_RETURN(status);
357 (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
359 /* TODO: check security descriptor of the endpoint here
360 * if it's a smb named pipe
361 * if it's failed free dce_conn_p
368 static void dcesrv_init_hdr(struct ncacn_packet *pkt)
371 pkt->rpc_vers_minor = 0;
372 if (lp_rpc_big_endian()) {
375 pkt->drep[0] = DCERPC_DREP_LE;
383 return a dcerpc fault
385 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
387 struct ncacn_packet pkt;
388 struct data_blob_list_item *rep;
391 /* setup a bind_ack */
392 dcesrv_init_hdr(&pkt);
394 pkt.call_id = call->pkt.call_id;
395 pkt.ptype = DCERPC_PKT_FAULT;
396 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
397 pkt.u.fault.alloc_hint = 0;
398 pkt.u.fault.context_id = 0;
399 pkt.u.fault.cancel_count = 0;
400 pkt.u.fault.status = fault_code;
402 rep = talloc(call, struct data_blob_list_item);
404 return NT_STATUS_NO_MEMORY;
407 status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
408 if (!NT_STATUS_IS_OK(status)) {
412 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
414 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
415 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
422 return a dcerpc bind_nak
424 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
426 struct ncacn_packet pkt;
427 struct data_blob_list_item *rep;
430 /* setup a bind_nak */
431 dcesrv_init_hdr(&pkt);
433 pkt.call_id = call->pkt.call_id;
434 pkt.ptype = DCERPC_PKT_BIND_NAK;
435 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
436 pkt.u.bind_nak.reject_reason = reason;
437 if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
438 pkt.u.bind_nak.versions.v.num_versions = 0;
441 rep = talloc(call, struct data_blob_list_item);
443 return NT_STATUS_NO_MEMORY;
446 status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
447 if (!NT_STATUS_IS_OK(status)) {
451 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
453 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
454 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
461 handle a bind request
463 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
465 uint32_t if_version, transfer_syntax_version;
466 struct GUID uuid, *transfer_syntax_uuid;
467 struct ncacn_packet pkt;
468 struct data_blob_list_item *rep;
470 uint32_t result=0, reason=0;
472 const struct dcesrv_interface *iface;
474 if (call->pkt.u.bind.num_contexts < 1 ||
475 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
476 return dcesrv_bind_nak(call, 0);
479 context_id = call->pkt.u.bind.ctx_list[0].context_id;
481 /* you can't bind twice on one context */
482 if (dcesrv_find_context(call->conn, context_id) != NULL) {
483 return dcesrv_bind_nak(call, 0);
486 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
487 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
489 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
490 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
491 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
492 ndr_transfer_syntax.if_version != transfer_syntax_version) {
493 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
494 /* we only do NDR encoded dcerpc */
495 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
496 talloc_free(uuid_str);
497 return dcesrv_bind_nak(call, 0);
500 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
502 char *uuid_str = GUID_string(call, &uuid);
503 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
504 talloc_free(uuid_str);
506 /* we don't know about that interface */
507 result = DCERPC_BIND_PROVIDER_REJECT;
508 reason = DCERPC_BIND_REASON_ASYNTAX;
512 /* add this context to the list of available context_ids */
513 struct dcesrv_connection_context *context = talloc(call->conn,
514 struct dcesrv_connection_context);
515 if (context == NULL) {
516 return dcesrv_bind_nak(call, 0);
518 context->conn = call->conn;
519 context->iface = iface;
520 context->context_id = context_id;
521 context->private = NULL;
522 context->handles = NULL;
523 DLIST_ADD(call->conn->contexts, context);
524 call->context = context;
527 if (call->conn->cli_max_recv_frag == 0) {
528 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
531 /* handle any authentication that is being requested */
532 if (!dcesrv_auth_bind(call)) {
533 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
536 /* setup a bind_ack */
537 dcesrv_init_hdr(&pkt);
539 pkt.call_id = call->pkt.call_id;
540 pkt.ptype = DCERPC_PKT_BIND_ACK;
541 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
542 pkt.u.bind_ack.max_xmit_frag = 0x2000;
543 pkt.u.bind_ack.max_recv_frag = 0x2000;
544 pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
546 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
547 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
549 pkt.u.bind_ack.secondary_address = "";
551 pkt.u.bind_ack.num_results = 1;
552 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
553 if (!pkt.u.bind_ack.ctx_list) {
554 return NT_STATUS_NO_MEMORY;
556 pkt.u.bind_ack.ctx_list[0].result = result;
557 pkt.u.bind_ack.ctx_list[0].reason = reason;
558 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
559 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
561 if (!dcesrv_auth_bind_ack(call, &pkt)) {
562 return dcesrv_bind_nak(call, 0);
566 status = iface->bind(call, iface);
567 if (!NT_STATUS_IS_OK(status)) {
568 char *uuid_str = GUID_string(call, &uuid);
569 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
570 uuid_str, if_version, nt_errstr(status)));
571 talloc_free(uuid_str);
572 return dcesrv_bind_nak(call, 0);
576 rep = talloc(call, struct data_blob_list_item);
578 return NT_STATUS_NO_MEMORY;
581 status = ncacn_push_auth(&rep->blob, call, &pkt,
582 call->conn->auth_state.auth_info);
583 if (!NT_STATUS_IS_OK(status)) {
587 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
589 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
590 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
597 handle a auth3 request
599 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
601 /* handle the auth3 in the auth code */
602 if (!dcesrv_auth_auth3(call)) {
603 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
608 /* we don't send a reply to a auth3 request, except by a
615 handle a bind request
617 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
619 uint32_t if_version, transfer_syntax_version;
620 struct dcesrv_connection_context *context;
621 const struct dcesrv_interface *iface;
622 struct GUID uuid, *transfer_syntax_uuid;
624 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
625 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
627 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
628 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
629 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
630 ndr_transfer_syntax.if_version != transfer_syntax_version) {
631 /* we only do NDR encoded dcerpc */
632 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
635 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
637 char *uuid_str = GUID_string(call, &uuid);
638 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
639 talloc_free(uuid_str);
640 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
643 /* add this context to the list of available context_ids */
644 context = talloc(call->conn, struct dcesrv_connection_context);
645 if (context == NULL) {
646 return NT_STATUS_NO_MEMORY;
648 context->conn = call->conn;
649 context->iface = iface;
650 context->context_id = context_id;
651 context->private = NULL;
652 context->handles = NULL;
653 DLIST_ADD(call->conn->contexts, context);
654 call->context = context;
661 handle a alter context request
663 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
665 struct ncacn_packet pkt;
666 struct data_blob_list_item *rep;
668 uint32_t result=0, reason=0;
671 /* handle any authentication that is being requested */
672 if (!dcesrv_auth_alter(call)) {
673 /* TODO: work out the right reject code */
674 result = DCERPC_BIND_PROVIDER_REJECT;
675 reason = DCERPC_BIND_REASON_ASYNTAX;
678 context_id = call->pkt.u.alter.ctx_list[0].context_id;
680 /* see if they are asking for a new interface */
682 dcesrv_find_context(call->conn, context_id) == NULL) {
683 status = dcesrv_alter_new_context(call, context_id);
684 if (!NT_STATUS_IS_OK(status)) {
685 result = DCERPC_BIND_PROVIDER_REJECT;
686 reason = DCERPC_BIND_REASON_ASYNTAX;
690 /* setup a alter_resp */
691 dcesrv_init_hdr(&pkt);
693 pkt.call_id = call->pkt.call_id;
694 pkt.ptype = DCERPC_PKT_ALTER_RESP;
695 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
696 pkt.u.alter_resp.max_xmit_frag = 0x2000;
697 pkt.u.alter_resp.max_recv_frag = 0x2000;
698 pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
699 pkt.u.alter_resp.num_results = 1;
700 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
701 if (!pkt.u.alter_resp.ctx_list) {
702 return NT_STATUS_NO_MEMORY;
704 pkt.u.alter_resp.ctx_list[0].result = result;
705 pkt.u.alter_resp.ctx_list[0].reason = reason;
706 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
707 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
708 pkt.u.alter_resp.secondary_address = "";
710 if (!dcesrv_auth_alter_ack(call, &pkt)) {
711 return dcesrv_bind_nak(call, 0);
714 rep = talloc(call, struct data_blob_list_item);
716 return NT_STATUS_NO_MEMORY;
719 status = ncacn_push_auth(&rep->blob, call, &pkt,
720 call->conn->auth_state.auth_info);
721 if (!NT_STATUS_IS_OK(status)) {
725 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
727 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
728 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
734 handle a dcerpc request packet
736 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
738 struct ndr_pull *pull;
740 struct dcesrv_connection_context *context;
742 call->fault_code = 0;
743 call->state_flags = call->conn->state_flags;
744 call->time = timeval_current();
746 /* if authenticated, and the mech we use can't do async replies, don't use them... */
747 if (call->conn->auth_state.gensec_security &&
748 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
749 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
752 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
753 if (context == NULL) {
754 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
757 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
758 NT_STATUS_HAVE_NO_MEMORY(pull);
760 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
762 call->context = context;
763 call->event_ctx = context->conn->event_ctx;
764 call->ndr_pull = pull;
766 if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_ORPC) {
767 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
770 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
771 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
774 /* unravel the NDR for the packet */
775 status = context->iface->ndr_pull(call, call, pull, &call->r);
776 if (!NT_STATUS_IS_OK(status)) {
777 return dcesrv_fault(call, call->fault_code);
780 if (pull->offset != pull->data_size) {
781 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
782 pull->data_size - pull->offset));
783 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
786 /* call the dispatch function */
787 status = context->iface->dispatch(call, call, call->r);
788 if (!NT_STATUS_IS_OK(status)) {
789 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
790 context->iface->name,
791 call->pkt.u.request.opnum,
792 dcerpc_errstr(pull, call->fault_code)));
793 return dcesrv_fault(call, call->fault_code);
796 /* add the call to the pending list */
797 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
799 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
803 return dcesrv_reply(call);
806 NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
808 struct ndr_push *push;
811 uint32_t total_length;
812 struct dcesrv_connection_context *context = call->context;
814 /* call the reply function */
815 status = context->iface->reply(call, call, call->r);
816 if (!NT_STATUS_IS_OK(status)) {
817 return dcesrv_fault(call, call->fault_code);
820 /* form the reply NDR */
821 push = ndr_push_init_ctx(call);
822 NT_STATUS_HAVE_NO_MEMORY(push);
824 /* carry over the pointer count to the reply in case we are
825 using full pointer. See NDR specification for full
827 push->ptr_count = call->ndr_pull->ptr_count;
829 if (lp_rpc_big_endian()) {
830 push->flags |= LIBNDR_FLAG_BIGENDIAN;
833 status = context->iface->ndr_push(call, call, push, call->r);
834 if (!NT_STATUS_IS_OK(status)) {
835 return dcesrv_fault(call, call->fault_code);
838 stub = ndr_push_blob(push);
840 total_length = stub.length;
844 struct data_blob_list_item *rep;
845 struct ncacn_packet pkt;
847 rep = talloc(call, struct data_blob_list_item);
848 NT_STATUS_HAVE_NO_MEMORY(rep);
850 length = stub.length;
851 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
852 /* the 32 is to cope with signing data */
853 length = call->conn->cli_max_recv_frag -
854 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
857 /* form the dcerpc response packet */
858 dcesrv_init_hdr(&pkt);
860 pkt.call_id = call->pkt.call_id;
861 pkt.ptype = DCERPC_PKT_RESPONSE;
863 if (stub.length == total_length) {
864 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
866 if (length == stub.length) {
867 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
869 pkt.u.response.alloc_hint = stub.length;
870 pkt.u.response.context_id = call->pkt.u.request.context_id;
871 pkt.u.response.cancel_count = 0;
872 pkt.u.response.stub_and_verifier.data = stub.data;
873 pkt.u.response.stub_and_verifier.length = length;
875 if (!dcesrv_auth_response(call, &rep->blob, &pkt)) {
876 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
879 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
881 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
884 stub.length -= length;
885 } while (stub.length != 0);
887 /* move the call from the pending to the finished calls list */
888 DLIST_REMOVE(call->conn->pending_call_list, call);
889 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
891 if (call->conn->call_list && call->conn->call_list->replies) {
892 if (call->conn->transport.report_output_data) {
893 call->conn->transport.report_output_data(call->conn);
900 struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
902 if (!conn->transport.get_my_addr) {
906 return conn->transport.get_my_addr(conn, mem_ctx);
909 struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
911 if (!conn->transport.get_peer_addr) {
915 return conn->transport.get_peer_addr(conn, mem_ctx);
919 work out if we have a full packet yet
921 static BOOL dce_full_packet(const DATA_BLOB *data)
923 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
926 if (dcerpc_get_frag_length(data) > data->length) {
933 we might have consumed only part of our input - advance past that part
935 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
939 if (dce_conn->partial_input.length == offset) {
940 data_blob_free(&dce_conn->partial_input);
944 blob = dce_conn->partial_input;
945 dce_conn->partial_input = data_blob(blob.data + offset,
946 blob.length - offset);
947 data_blob_free(&blob);
951 process some input to a dcerpc endpoint server.
953 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
955 struct ndr_pull *ndr;
957 struct dcesrv_call_state *call;
960 call = talloc(dce_conn, struct dcesrv_call_state);
962 talloc_free(dce_conn->partial_input.data);
963 return NT_STATUS_NO_MEMORY;
965 call->conn = dce_conn;
966 call->replies = NULL;
967 call->context = NULL;
968 call->event_ctx = dce_conn->event_ctx;
970 blob = dce_conn->partial_input;
971 blob.length = dcerpc_get_frag_length(&blob);
973 ndr = ndr_pull_init_blob(&blob, call);
975 talloc_free(dce_conn->partial_input.data);
977 return NT_STATUS_NO_MEMORY;
980 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
981 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
984 status = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
985 if (!NT_STATUS_IS_OK(status)) {
986 talloc_free(dce_conn->partial_input.data);
991 /* we have to check the signing here, before combining the
993 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
994 !dcesrv_auth_request(call, &blob)) {
995 dce_partial_advance(dce_conn, blob.length);
996 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
999 dce_partial_advance(dce_conn, blob.length);
1001 /* see if this is a continued packet */
1002 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1003 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1004 struct dcesrv_call_state *call2 = call;
1005 uint32_t alloc_size;
1007 /* we only allow fragmented requests, no other packet types */
1008 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1009 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1012 /* this is a continuation of an existing call - find the call then
1013 tack it on the end */
1014 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
1016 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1019 if (call->pkt.ptype != call2->pkt.ptype) {
1020 /* trying to play silly buggers are we? */
1021 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1024 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1025 call2->pkt.u.request.stub_and_verifier.length;
1026 if (call->pkt.u.request.alloc_hint > alloc_size) {
1027 alloc_size = call->pkt.u.request.alloc_hint;
1030 call->pkt.u.request.stub_and_verifier.data =
1031 talloc_realloc(call,
1032 call->pkt.u.request.stub_and_verifier.data,
1033 uint8_t, alloc_size);
1034 if (!call->pkt.u.request.stub_and_verifier.data) {
1035 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1037 memcpy(call->pkt.u.request.stub_and_verifier.data +
1038 call->pkt.u.request.stub_and_verifier.length,
1039 call2->pkt.u.request.stub_and_verifier.data,
1040 call2->pkt.u.request.stub_and_verifier.length);
1041 call->pkt.u.request.stub_and_verifier.length +=
1042 call2->pkt.u.request.stub_and_verifier.length;
1044 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1049 /* this may not be the last pdu in the chain - if its isn't then
1050 just put it on the call_list and wait for the rest */
1051 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1052 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1053 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
1054 return NT_STATUS_OK;
1057 switch (call->pkt.ptype) {
1058 case DCERPC_PKT_BIND:
1059 status = dcesrv_bind(call);
1061 case DCERPC_PKT_AUTH3:
1062 status = dcesrv_auth3(call);
1064 case DCERPC_PKT_ALTER:
1065 status = dcesrv_alter(call);
1067 case DCERPC_PKT_REQUEST:
1068 status = dcesrv_request(call);
1071 status = NT_STATUS_INVALID_PARAMETER;
1075 /* if we are going to be sending a reply then add
1076 it to the list of pending calls. We add it to the end to keep the call
1077 list in the order we will answer */
1078 if (!NT_STATUS_IS_OK(status)) {
1087 provide some input to a dcerpc endpoint server. This passes data
1088 from a dcerpc client into the server
1090 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1094 dce_conn->partial_input.data = talloc_realloc(dce_conn,
1095 dce_conn->partial_input.data,
1097 dce_conn->partial_input.length + data->length);
1098 if (!dce_conn->partial_input.data) {
1099 return NT_STATUS_NO_MEMORY;
1101 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1102 data->data, data->length);
1103 dce_conn->partial_input.length += data->length;
1105 while (dce_full_packet(&dce_conn->partial_input)) {
1106 status = dcesrv_input_process(dce_conn);
1107 if (!NT_STATUS_IS_OK(status)) {
1112 return NT_STATUS_OK;
1116 retrieve some output from a dcerpc server
1117 The caller supplies a function that will be called to do the
1120 The first argument to write_fn() will be 'private', the second will
1121 be a pointer to a buffer containing the data to be sent and the 3rd
1122 will be a pointer to a size_t variable that will be set to the
1123 number of bytes that are consumed from the output.
1125 from the current fragment
1127 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
1129 NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1132 struct dcesrv_call_state *call;
1133 struct data_blob_list_item *rep;
1136 call = dce_conn->call_list;
1137 if (!call || !call->replies) {
1138 if (dce_conn->pending_call_list) {
1139 /* TODO: we need to say act async here
1140 * as we know we have pending requests
1141 * which will be finished at a time
1143 return NT_STATUS_FOOBAR;
1145 return NT_STATUS_FOOBAR;
1147 rep = call->replies;
1149 status = write_fn(private_data, &rep->blob, &nwritten);
1150 NT_STATUS_IS_ERR_RETURN(status);
1152 rep->blob.length -= nwritten;
1153 rep->blob.data += nwritten;
1155 if (rep->blob.length == 0) {
1156 /* we're done with this section of the call */
1157 DLIST_REMOVE(call->replies, rep);
1160 if (call->replies == NULL) {
1161 /* we're done with the whole call */
1162 DLIST_REMOVE(dce_conn->call_list, call);
1169 static NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1172 struct dcesrv_context *dce_ctx;
1175 if (!endpoint_servers) {
1176 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1177 return NT_STATUS_INTERNAL_ERROR;
1180 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1181 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1182 dce_ctx->endpoint_list = NULL;
1184 for (i=0;endpoint_servers[i];i++) {
1185 const struct dcesrv_endpoint_server *ep_server;
1187 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1189 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1190 return NT_STATUS_INTERNAL_ERROR;
1193 status = ep_server->init_server(dce_ctx, ep_server);
1194 if (!NT_STATUS_IS_OK(status)) {
1195 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1196 nt_errstr(status)));
1201 *_dce_ctx = dce_ctx;
1202 return NT_STATUS_OK;
1206 initialise the dcerpc server context for ncacn_np based services
1208 NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **_dce_ctx)
1211 struct dcesrv_context *dce_ctx;
1213 status = dcesrv_init_context(mem_ctx, lp_dcerpc_endpoint_servers(), &dce_ctx);
1214 NT_STATUS_NOT_OK_RETURN(status);
1216 *_dce_ctx = dce_ctx;
1217 return NT_STATUS_OK;
1220 /* the list of currently registered DCERPC endpoint servers.
1222 static struct ep_server {
1223 struct dcesrv_endpoint_server *ep_server;
1224 } *ep_servers = NULL;
1225 static int num_ep_servers;
1228 register a DCERPC endpoint server.
1230 The 'name' can be later used by other backends to find the operations
1231 structure for this backend.
1233 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1235 NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1237 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1239 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1240 /* its already registered! */
1241 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1243 return NT_STATUS_OBJECT_NAME_COLLISION;
1246 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1248 smb_panic("out of memory in dcerpc_register");
1251 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1252 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1256 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1259 return NT_STATUS_OK;
1263 return the operations structure for a named backend of the specified type
1265 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1269 for (i=0;i<num_ep_servers;i++) {
1270 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1271 return ep_servers[i].ep_server;
1279 return the DCERPC module version, and the size of some critical types
1280 This can be used by endpoint server modules to either detect compilation errors, or provide
1281 multiple implementations for different smbd compilation options in one module
1283 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1285 static const struct dcesrv_critical_sizes critical_sizes = {
1286 DCERPC_MODULE_VERSION,
1287 sizeof(struct dcesrv_context),
1288 sizeof(struct dcesrv_endpoint),
1289 sizeof(struct dcesrv_endpoint_server),
1290 sizeof(struct dcesrv_interface),
1291 sizeof(struct dcesrv_if_list),
1292 sizeof(struct dcesrv_connection),
1293 sizeof(struct dcesrv_call_state),
1294 sizeof(struct dcesrv_auth),
1295 sizeof(struct dcesrv_handle)
1298 return &critical_sizes;
1302 open the dcerpc server sockets
1304 static void dcesrv_task_init(struct task_server *task)
1307 struct dcesrv_context *dce_ctx;
1308 struct dcesrv_endpoint *e;
1310 task_server_set_title(task, "task[dcesrv]");
1312 status = dcesrv_init_context(task->event_ctx,
1313 lp_dcerpc_endpoint_servers(),
1315 if (!NT_STATUS_IS_OK(status)) goto failed;
1317 /* Make sure the directory for NCALRPC exists */
1318 if (!directory_exist(lp_ncalrpc_dir())) {
1319 mkdir(lp_ncalrpc_dir(), 0755);
1322 for (e=dce_ctx->endpoint_list;e;e=e->next) {
1323 switch (e->ep_description->transport) {
1324 case NCACN_UNIX_STREAM:
1325 status = dcesrv_add_ep_unix(dce_ctx, e, task->event_ctx, task->model_ops);
1326 if (!NT_STATUS_IS_OK(status)) goto failed;
1330 status = dcesrv_add_ep_ncalrpc(dce_ctx, e, task->event_ctx, task->model_ops);
1331 if (!NT_STATUS_IS_OK(status)) goto failed;
1335 status = dcesrv_add_ep_tcp(dce_ctx, e, task->event_ctx, task->model_ops);
1336 if (!NT_STATUS_IS_OK(status)) goto failed;
1340 /* FIXME: status = dcesrv_add_ep_np(dce_ctx, e, task->event_ctx, task->model_ops);
1341 if (!NT_STATUS_IS_OK(status)) goto failed;
1345 status = NT_STATUS_NOT_SUPPORTED;
1346 if (!NT_STATUS_IS_OK(status)) goto failed;
1352 task_server_terminate(task, "Failed to startup dcerpc server task");
1356 called on startup of the smb server service It's job is to start
1357 listening on all configured sockets
1359 static NTSTATUS dcesrv_init(struct event_context *event_context,
1360 const struct model_ops *model_ops)
1362 return task_server_startup(event_context, model_ops, dcesrv_task_init);
1365 NTSTATUS server_service_rpc_init(void)
1367 init_module_fn static_init[] = STATIC_dcerpc_server_MODULES;
1368 init_module_fn *shared_init = load_samba_modules(NULL, "dcerpc_server");
1370 run_init_functions(static_init);
1371 run_init_functions(shared_init);
1373 talloc_free(shared_init);
1375 return register_server_service("rpc", dcesrv_init);