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/proto.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->if_version == if2->if_version &&
92 GUID_equal(&if1->uuid, &if2->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->if_version == if_version && GUID_equal(&iface->uuid, uuid));
120 find the interface operations on an endpoint by uuid
122 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
123 const struct GUID *uuid, uint32_t if_version)
125 struct dcesrv_if_list *ifl;
126 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
127 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
128 return &(ifl->iface);
135 find a call that is pending in our call list
137 static struct dcesrv_call_state *dcesrv_find_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
139 struct dcesrv_call_state *c;
140 for (c=dce_conn->call_list;c;c=c->next) {
141 if (c->pkt.call_id == call_id) {
149 register an interface on an endpoint
151 NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
153 const struct dcesrv_interface *iface,
154 const struct security_descriptor *sd)
156 struct dcesrv_endpoint *ep;
157 struct dcesrv_if_list *ifl;
158 struct dcerpc_binding *binding;
162 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
164 if (NT_STATUS_IS_ERR(status)) {
165 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
169 /* check if this endpoint exists
171 if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
172 ep = talloc(dce_ctx, struct dcesrv_endpoint);
174 return NT_STATUS_NO_MEMORY;
177 ep->ep_description = talloc_reference(ep, binding);
181 /* see if the interface is already registered on te endpoint */
182 if (find_interface(ep, iface)!=NULL) {
183 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
184 iface->name, ep_name));
185 return NT_STATUS_OBJECT_NAME_COLLISION;
188 /* talloc a new interface list element */
189 ifl = talloc(dce_ctx, struct dcesrv_if_list);
191 return NT_STATUS_NO_MEMORY;
194 /* copy the given interface struct to the one on the endpoints interface list */
195 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
197 /* if we have a security descriptor given,
198 * we should see if we can set it up on the endpoint
201 /* if there's currently no security descriptor given on the endpoint
204 if (ep->sd == NULL) {
205 ep->sd = security_descriptor_copy(dce_ctx, sd);
208 /* if now there's no security descriptor given on the endpoint
209 * something goes wrong, either we failed to copy the security descriptor
210 * or there was already one on the endpoint
212 if (ep->sd != NULL) {
213 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
214 " on endpoint '%s'\n",
215 iface->name, ep_name));
216 if (add_ep) free(ep);
218 return NT_STATUS_OBJECT_NAME_COLLISION;
222 /* finally add the interface on the endpoint */
223 DLIST_ADD(ep->interface_list, ifl);
225 /* if it's a new endpoint add it to the dcesrv_context */
227 DLIST_ADD(dce_ctx->endpoint_list, ep);
230 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
231 iface->name, ep_name));
236 static NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
237 DATA_BLOB *session_key)
239 if (p->auth_state.session_info->session_key.length) {
240 *session_key = p->auth_state.session_info->session_key;
243 return NT_STATUS_NO_USER_SESSION_KEY;
246 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
247 DATA_BLOB *session_key)
249 /* this took quite a few CPU cycles to find ... */
250 session_key->data = discard_const_p(uint8_t, "SystemLibraryDTC");
251 session_key->length = 16;
256 fetch the user session key - may be default (above) or the SMB session key
258 NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
259 DATA_BLOB *session_key)
261 return p->auth_state.session_key(p, session_key);
266 destroy a link to an endpoint
268 static int dcesrv_endpoint_destructor(void *ptr)
270 struct dcesrv_connection *p = ptr;
272 while (p->contexts) {
273 struct dcesrv_connection_context *c = p->contexts;
275 DLIST_REMOVE(p->contexts, c);
278 c->iface->unbind(c, c->iface);
287 connect to a dcerpc endpoint
289 NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
291 const struct dcesrv_endpoint *ep,
292 struct auth_session_info *session_info,
293 struct event_context *event_ctx,
294 uint32_t state_flags,
295 struct dcesrv_connection **_p)
297 struct dcesrv_connection *p;
300 return NT_STATUS_ACCESS_DENIED;
303 p = talloc(mem_ctx, struct dcesrv_connection);
304 NT_STATUS_HAVE_NO_MEMORY(p);
306 if (!talloc_reference(p, session_info)) {
308 return NT_STATUS_NO_MEMORY;
311 p->dce_ctx = dce_ctx;
315 p->pending_call_list = NULL;
316 p->cli_max_recv_frag = 0;
317 p->partial_input = data_blob(NULL, 0);
318 p->auth_state.auth_info = NULL;
319 p->auth_state.gensec_security = NULL;
320 p->auth_state.session_info = session_info;
321 p->auth_state.session_key = dcesrv_generic_session_key;
322 p->event_ctx = event_ctx;
323 p->processing = False;
324 p->state_flags = state_flags;
325 ZERO_STRUCT(p->transport);
327 talloc_set_destructor(p, dcesrv_endpoint_destructor);
334 search and connect to a dcerpc endpoint
336 NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
338 const struct dcerpc_binding *ep_description,
339 struct auth_session_info *session_info,
340 struct event_context *event_ctx,
341 uint32_t state_flags,
342 struct dcesrv_connection **dce_conn_p)
345 const struct dcesrv_endpoint *ep;
347 /* make sure this endpoint exists */
348 ep = find_endpoint(dce_ctx, ep_description);
350 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
353 status = dcesrv_endpoint_connect(dce_ctx, mem_ctx, ep, session_info, event_ctx, state_flags, dce_conn_p);
354 NT_STATUS_NOT_OK_RETURN(status);
356 (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
358 /* TODO: check security descriptor of the endpoint here
359 * if it's a smb named pipe
360 * if it's failed free dce_conn_p
367 static void dcesrv_init_hdr(struct ncacn_packet *pkt)
370 pkt->rpc_vers_minor = 0;
371 if (lp_rpc_big_endian()) {
374 pkt->drep[0] = DCERPC_DREP_LE;
382 return a dcerpc fault
384 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
386 struct ncacn_packet pkt;
387 struct data_blob_list_item *rep;
390 /* setup a bind_ack */
391 dcesrv_init_hdr(&pkt);
393 pkt.call_id = call->pkt.call_id;
394 pkt.ptype = DCERPC_PKT_FAULT;
395 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
396 pkt.u.fault.alloc_hint = 0;
397 pkt.u.fault.context_id = 0;
398 pkt.u.fault.cancel_count = 0;
399 pkt.u.fault.status = fault_code;
401 rep = talloc(call, struct data_blob_list_item);
403 return NT_STATUS_NO_MEMORY;
406 status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
407 if (!NT_STATUS_IS_OK(status)) {
411 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
413 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
414 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
421 return a dcerpc bind_nak
423 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
425 struct ncacn_packet pkt;
426 struct data_blob_list_item *rep;
429 /* setup a bind_nak */
430 dcesrv_init_hdr(&pkt);
432 pkt.call_id = call->pkt.call_id;
433 pkt.ptype = DCERPC_PKT_BIND_NAK;
434 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
435 pkt.u.bind_nak.reject_reason = reason;
436 pkt.u.bind_nak.num_versions = 0;
438 rep = talloc(call, struct data_blob_list_item);
440 return NT_STATUS_NO_MEMORY;
443 status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
444 if (!NT_STATUS_IS_OK(status)) {
448 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
450 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
451 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
458 handle a bind request
460 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
462 uint32_t if_version, transfer_syntax_version;
463 struct GUID uuid, *transfer_syntax_uuid;
464 struct ncacn_packet pkt;
465 struct data_blob_list_item *rep;
467 uint32_t result=0, reason=0;
469 const struct dcesrv_interface *iface;
471 if (call->pkt.u.bind.num_contexts < 1 ||
472 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
473 return dcesrv_bind_nak(call, 0);
476 context_id = call->pkt.u.bind.ctx_list[0].context_id;
478 /* you can't bind twice on one context */
479 if (dcesrv_find_context(call->conn, context_id) != NULL) {
480 return dcesrv_bind_nak(call, 0);
483 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
484 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
486 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
487 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
488 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
489 ndr_transfer_syntax.if_version != transfer_syntax_version) {
490 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
491 /* we only do NDR encoded dcerpc */
492 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
493 talloc_free(uuid_str);
494 return dcesrv_bind_nak(call, 0);
497 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
499 char *uuid_str = GUID_string(call, &uuid);
500 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
501 talloc_free(uuid_str);
503 /* we don't know about that interface */
504 result = DCERPC_BIND_PROVIDER_REJECT;
505 reason = DCERPC_BIND_REASON_ASYNTAX;
509 /* add this context to the list of available context_ids */
510 struct dcesrv_connection_context *context = talloc(call->conn,
511 struct dcesrv_connection_context);
512 if (context == NULL) {
513 return dcesrv_bind_nak(call, 0);
515 context->conn = call->conn;
516 context->iface = iface;
517 context->context_id = context_id;
518 context->private = NULL;
519 context->handles = NULL;
520 DLIST_ADD(call->conn->contexts, context);
521 call->context = context;
524 if (call->conn->cli_max_recv_frag == 0) {
525 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
528 /* handle any authentication that is being requested */
529 if (!dcesrv_auth_bind(call)) {
530 /* TODO: work out the right reject code */
531 return dcesrv_bind_nak(call, 0);
534 /* setup a bind_ack */
535 dcesrv_init_hdr(&pkt);
537 pkt.call_id = call->pkt.call_id;
538 pkt.ptype = DCERPC_PKT_BIND_ACK;
539 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
540 pkt.u.bind_ack.max_xmit_frag = 0x2000;
541 pkt.u.bind_ack.max_recv_frag = 0x2000;
542 pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
544 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
545 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
547 pkt.u.bind_ack.secondary_address = "";
549 pkt.u.bind_ack.num_results = 1;
550 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
551 if (!pkt.u.bind_ack.ctx_list) {
552 return NT_STATUS_NO_MEMORY;
554 pkt.u.bind_ack.ctx_list[0].result = result;
555 pkt.u.bind_ack.ctx_list[0].reason = reason;
556 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
557 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
559 if (!dcesrv_auth_bind_ack(call, &pkt)) {
560 return dcesrv_bind_nak(call, 0);
564 status = iface->bind(call, iface);
565 if (!NT_STATUS_IS_OK(status)) {
566 char *uuid_str = GUID_string(call, &uuid);
567 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
568 uuid_str, if_version, nt_errstr(status)));
569 talloc_free(uuid_str);
570 return dcesrv_bind_nak(call, 0);
574 rep = talloc(call, struct data_blob_list_item);
576 return NT_STATUS_NO_MEMORY;
579 status = ncacn_push_auth(&rep->blob, call, &pkt,
580 call->conn->auth_state.auth_info);
581 if (!NT_STATUS_IS_OK(status)) {
585 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
587 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
588 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
595 handle a auth3 request
597 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
599 /* handle the auth3 in the auth code */
600 if (!dcesrv_auth_auth3(call)) {
601 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
606 /* we don't send a reply to a auth3 request, except by a
613 handle a bind request
615 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
617 uint32_t if_version, transfer_syntax_version;
618 struct dcesrv_connection_context *context;
619 const struct dcesrv_interface *iface;
620 struct GUID uuid, *transfer_syntax_uuid;
622 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
623 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
625 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
626 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
627 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
628 ndr_transfer_syntax.if_version != transfer_syntax_version) {
629 /* we only do NDR encoded dcerpc */
630 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
633 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
635 char *uuid_str = GUID_string(call, &uuid);
636 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
637 talloc_free(uuid_str);
638 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
641 /* add this context to the list of available context_ids */
642 context = talloc(call->conn, struct dcesrv_connection_context);
643 if (context == NULL) {
644 return NT_STATUS_NO_MEMORY;
646 context->conn = call->conn;
647 context->iface = iface;
648 context->context_id = context_id;
649 context->private = NULL;
650 context->handles = NULL;
651 DLIST_ADD(call->conn->contexts, context);
652 call->context = context;
659 handle a alter context request
661 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
663 struct ncacn_packet pkt;
664 struct data_blob_list_item *rep;
666 uint32_t result=0, reason=0;
669 /* handle any authentication that is being requested */
670 if (!dcesrv_auth_alter(call)) {
671 /* TODO: work out the right reject code */
672 result = DCERPC_BIND_PROVIDER_REJECT;
673 reason = DCERPC_BIND_REASON_ASYNTAX;
676 context_id = call->pkt.u.alter.ctx_list[0].context_id;
678 /* see if they are asking for a new interface */
680 dcesrv_find_context(call->conn, context_id) == NULL) {
681 status = dcesrv_alter_new_context(call, context_id);
682 if (!NT_STATUS_IS_OK(status)) {
683 result = DCERPC_BIND_PROVIDER_REJECT;
684 reason = DCERPC_BIND_REASON_ASYNTAX;
688 /* setup a alter_resp */
689 dcesrv_init_hdr(&pkt);
691 pkt.call_id = call->pkt.call_id;
692 pkt.ptype = DCERPC_PKT_ALTER_RESP;
693 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
694 pkt.u.alter_resp.max_xmit_frag = 0x2000;
695 pkt.u.alter_resp.max_recv_frag = 0x2000;
696 pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
697 pkt.u.alter_resp.num_results = 1;
698 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
699 if (!pkt.u.alter_resp.ctx_list) {
700 return NT_STATUS_NO_MEMORY;
702 pkt.u.alter_resp.ctx_list[0].result = result;
703 pkt.u.alter_resp.ctx_list[0].reason = reason;
704 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
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(call, struct data_blob_list_item);
714 return NT_STATUS_NO_MEMORY;
717 status = ncacn_push_auth(&rep->blob, call, &pkt,
718 call->conn->auth_state.auth_info);
719 if (!NT_STATUS_IS_OK(status)) {
723 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
725 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
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->state_flags;
742 call->time = timeval_current();
744 /* if authenticated, and the mech we use can't do async replies, don't use them... */
745 if (call->conn->auth_state.gensec_security &&
746 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
747 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
750 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
751 if (context == NULL) {
752 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
755 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
756 NT_STATUS_HAVE_NO_MEMORY(pull);
758 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
760 call->context = context;
761 call->event_ctx = context->conn->event_ctx;
762 call->ndr_pull = pull;
764 if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_ORPC) {
765 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
768 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
769 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
772 /* unravel the NDR for the packet */
773 status = context->iface->ndr_pull(call, call, pull, &call->r);
774 if (!NT_STATUS_IS_OK(status)) {
775 return dcesrv_fault(call, call->fault_code);
778 if (pull->offset != pull->data_size) {
779 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
780 pull->data_size - pull->offset));
781 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
784 /* call the dispatch function */
785 status = context->iface->dispatch(call, call, call->r);
786 if (!NT_STATUS_IS_OK(status)) {
787 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
788 context->iface->name,
789 call->pkt.u.request.opnum,
790 dcerpc_errstr(pull, call->fault_code)));
791 return dcesrv_fault(call, call->fault_code);
794 /* add the call to the pending list */
795 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
797 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
801 return dcesrv_reply(call);
804 NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
806 struct ndr_push *push;
809 uint32_t total_length;
810 struct dcesrv_connection_context *context = call->context;
812 /* call the reply function */
813 status = context->iface->reply(call, call, call->r);
814 if (!NT_STATUS_IS_OK(status)) {
815 return dcesrv_fault(call, call->fault_code);
818 /* form the reply NDR */
819 push = ndr_push_init_ctx(call);
820 NT_STATUS_HAVE_NO_MEMORY(push);
822 /* carry over the pointer count to the reply in case we are
823 using full pointer. See NDR specification for full
825 push->ptr_count = call->ndr_pull->ptr_count;
827 if (lp_rpc_big_endian()) {
828 push->flags |= LIBNDR_FLAG_BIGENDIAN;
831 status = context->iface->ndr_push(call, call, push, call->r);
832 if (!NT_STATUS_IS_OK(status)) {
833 return dcesrv_fault(call, call->fault_code);
836 stub = ndr_push_blob(push);
838 total_length = stub.length;
842 struct data_blob_list_item *rep;
843 struct ncacn_packet pkt;
845 rep = talloc(call, struct data_blob_list_item);
846 NT_STATUS_HAVE_NO_MEMORY(rep);
848 length = stub.length;
849 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
850 /* the 32 is to cope with signing data */
851 length = call->conn->cli_max_recv_frag -
852 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
855 /* form the dcerpc response packet */
856 dcesrv_init_hdr(&pkt);
858 pkt.call_id = call->pkt.call_id;
859 pkt.ptype = DCERPC_PKT_RESPONSE;
861 if (stub.length == total_length) {
862 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
864 if (length == stub.length) {
865 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
867 pkt.u.response.alloc_hint = stub.length;
868 pkt.u.response.context_id = call->pkt.u.request.context_id;
869 pkt.u.response.cancel_count = 0;
870 pkt.u.response.stub_and_verifier.data = stub.data;
871 pkt.u.response.stub_and_verifier.length = length;
873 if (!dcesrv_auth_response(call, &rep->blob, &pkt)) {
874 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
877 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
879 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
882 stub.length -= length;
883 } while (stub.length != 0);
885 /* move the call from the pending to the finished calls list */
886 DLIST_REMOVE(call->conn->pending_call_list, call);
887 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
889 if (call->conn->call_list && call->conn->call_list->replies) {
890 if (call->conn->transport.report_output_data) {
891 call->conn->transport.report_output_data(call->conn);
898 struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
900 if (!conn->transport.get_my_addr) {
904 return conn->transport.get_my_addr(conn, mem_ctx);
907 struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
909 if (!conn->transport.get_peer_addr) {
913 return conn->transport.get_peer_addr(conn, mem_ctx);
917 work out if we have a full packet yet
919 static BOOL dce_full_packet(const DATA_BLOB *data)
921 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
924 if (dcerpc_get_frag_length(data) > data->length) {
931 we might have consumed only part of our input - advance past that part
933 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
937 if (dce_conn->partial_input.length == offset) {
938 data_blob_free(&dce_conn->partial_input);
942 blob = dce_conn->partial_input;
943 dce_conn->partial_input = data_blob(blob.data + offset,
944 blob.length - offset);
945 data_blob_free(&blob);
949 process some input to a dcerpc endpoint server.
951 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
953 struct ndr_pull *ndr;
955 struct dcesrv_call_state *call;
958 call = talloc(dce_conn, struct dcesrv_call_state);
960 talloc_free(dce_conn->partial_input.data);
961 return NT_STATUS_NO_MEMORY;
963 call->conn = dce_conn;
964 call->replies = NULL;
965 call->context = NULL;
966 call->event_ctx = dce_conn->event_ctx;
968 blob = dce_conn->partial_input;
969 blob.length = dcerpc_get_frag_length(&blob);
971 ndr = ndr_pull_init_blob(&blob, call);
973 talloc_free(dce_conn->partial_input.data);
975 return NT_STATUS_NO_MEMORY;
978 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
979 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
982 status = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
983 if (!NT_STATUS_IS_OK(status)) {
984 talloc_free(dce_conn->partial_input.data);
989 /* we have to check the signing here, before combining the
991 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
992 !dcesrv_auth_request(call, &blob)) {
993 dce_partial_advance(dce_conn, blob.length);
994 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
997 dce_partial_advance(dce_conn, blob.length);
999 /* see if this is a continued packet */
1000 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1001 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1002 struct dcesrv_call_state *call2 = call;
1003 uint32_t alloc_size;
1005 /* we only allow fragmented requests, no other packet types */
1006 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1007 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1010 /* this is a continuation of an existing call - find the call then
1011 tack it on the end */
1012 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
1014 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1017 if (call->pkt.ptype != call2->pkt.ptype) {
1018 /* trying to play silly buggers are we? */
1019 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1022 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1023 call2->pkt.u.request.stub_and_verifier.length;
1024 if (call->pkt.u.request.alloc_hint > alloc_size) {
1025 alloc_size = call->pkt.u.request.alloc_hint;
1028 call->pkt.u.request.stub_and_verifier.data =
1029 talloc_realloc(call,
1030 call->pkt.u.request.stub_and_verifier.data,
1031 uint8_t, alloc_size);
1032 if (!call->pkt.u.request.stub_and_verifier.data) {
1033 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1035 memcpy(call->pkt.u.request.stub_and_verifier.data +
1036 call->pkt.u.request.stub_and_verifier.length,
1037 call2->pkt.u.request.stub_and_verifier.data,
1038 call2->pkt.u.request.stub_and_verifier.length);
1039 call->pkt.u.request.stub_and_verifier.length +=
1040 call2->pkt.u.request.stub_and_verifier.length;
1042 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1047 /* this may not be the last pdu in the chain - if its isn't then
1048 just put it on the call_list and wait for the rest */
1049 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1050 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1051 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
1052 return NT_STATUS_OK;
1055 switch (call->pkt.ptype) {
1056 case DCERPC_PKT_BIND:
1057 status = dcesrv_bind(call);
1059 case DCERPC_PKT_AUTH3:
1060 status = dcesrv_auth3(call);
1062 case DCERPC_PKT_ALTER:
1063 status = dcesrv_alter(call);
1065 case DCERPC_PKT_REQUEST:
1066 status = dcesrv_request(call);
1069 status = NT_STATUS_INVALID_PARAMETER;
1073 /* if we are going to be sending a reply then add
1074 it to the list of pending calls. We add it to the end to keep the call
1075 list in the order we will answer */
1076 if (!NT_STATUS_IS_OK(status)) {
1085 provide some input to a dcerpc endpoint server. This passes data
1086 from a dcerpc client into the server
1088 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1092 dce_conn->partial_input.data = talloc_realloc(dce_conn,
1093 dce_conn->partial_input.data,
1095 dce_conn->partial_input.length + data->length);
1096 if (!dce_conn->partial_input.data) {
1097 return NT_STATUS_NO_MEMORY;
1099 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1100 data->data, data->length);
1101 dce_conn->partial_input.length += data->length;
1103 while (dce_full_packet(&dce_conn->partial_input)) {
1104 status = dcesrv_input_process(dce_conn);
1105 if (!NT_STATUS_IS_OK(status)) {
1110 return NT_STATUS_OK;
1114 retrieve some output from a dcerpc server
1115 The caller supplies a function that will be called to do the
1118 The first argument to write_fn() will be 'private', the second will
1119 be a pointer to a buffer containing the data to be sent and the 3rd
1120 will be a pointer to a size_t variable that will be set to the
1121 number of bytes that are consumed from the output.
1123 from the current fragment
1125 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
1127 NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1130 struct dcesrv_call_state *call;
1131 struct data_blob_list_item *rep;
1134 call = dce_conn->call_list;
1135 if (!call || !call->replies) {
1136 if (dce_conn->pending_call_list) {
1137 /* TODO: we need to say act async here
1138 * as we know we have pending requests
1139 * which will be finished at a time
1141 return NT_STATUS_FOOBAR;
1143 return NT_STATUS_FOOBAR;
1145 rep = call->replies;
1147 status = write_fn(private_data, &rep->blob, &nwritten);
1148 NT_STATUS_IS_ERR_RETURN(status);
1150 rep->blob.length -= nwritten;
1151 rep->blob.data += nwritten;
1153 if (rep->blob.length == 0) {
1154 /* we're done with this section of the call */
1155 DLIST_REMOVE(call->replies, rep);
1158 if (call->replies == NULL) {
1159 /* we're done with the whole call */
1160 DLIST_REMOVE(dce_conn->call_list, call);
1167 static NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1170 struct dcesrv_context *dce_ctx;
1173 if (!endpoint_servers) {
1174 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1175 return NT_STATUS_INTERNAL_ERROR;
1178 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1179 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1180 dce_ctx->endpoint_list = NULL;
1182 for (i=0;endpoint_servers[i];i++) {
1183 const struct dcesrv_endpoint_server *ep_server;
1185 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1187 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1188 return NT_STATUS_INTERNAL_ERROR;
1191 status = ep_server->init_server(dce_ctx, ep_server);
1192 if (!NT_STATUS_IS_OK(status)) {
1193 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1194 nt_errstr(status)));
1199 *_dce_ctx = dce_ctx;
1200 return NT_STATUS_OK;
1204 initialise the dcerpc server context for ncacn_np based services
1206 NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **_dce_ctx)
1209 struct dcesrv_context *dce_ctx;
1211 status = dcesrv_init_context(mem_ctx, lp_dcerpc_endpoint_servers(), &dce_ctx);
1212 NT_STATUS_NOT_OK_RETURN(status);
1214 *_dce_ctx = dce_ctx;
1215 return NT_STATUS_OK;
1218 /* the list of currently registered DCERPC endpoint servers.
1220 static struct ep_server {
1221 struct dcesrv_endpoint_server *ep_server;
1222 } *ep_servers = NULL;
1223 static int num_ep_servers;
1226 register a DCERPC endpoint server.
1228 The 'name' can be later used by other backends to find the operations
1229 structure for this backend.
1231 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1233 NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1235 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1237 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1238 /* its already registered! */
1239 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1241 return NT_STATUS_OBJECT_NAME_COLLISION;
1244 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1246 smb_panic("out of memory in dcerpc_register");
1249 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1250 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1254 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1257 return NT_STATUS_OK;
1261 return the operations structure for a named backend of the specified type
1263 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1267 for (i=0;i<num_ep_servers;i++) {
1268 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1269 return ep_servers[i].ep_server;
1277 return the DCERPC module version, and the size of some critical types
1278 This can be used by endpoint server modules to either detect compilation errors, or provide
1279 multiple implementations for different smbd compilation options in one module
1281 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1283 static const struct dcesrv_critical_sizes critical_sizes = {
1284 DCERPC_MODULE_VERSION,
1285 sizeof(struct dcesrv_context),
1286 sizeof(struct dcesrv_endpoint),
1287 sizeof(struct dcesrv_endpoint_server),
1288 sizeof(struct dcesrv_interface),
1289 sizeof(struct dcesrv_if_list),
1290 sizeof(struct dcesrv_connection),
1291 sizeof(struct dcesrv_call_state),
1292 sizeof(struct dcesrv_auth),
1293 sizeof(struct dcesrv_handle)
1296 return &critical_sizes;
1300 open the dcerpc server sockets
1302 static void dcesrv_task_init(struct task_server *task)
1305 struct dcesrv_context *dce_ctx;
1306 struct dcesrv_endpoint *e;
1308 task_server_set_title(task, "task[dcesrv]");
1310 status = dcesrv_init_context(task->event_ctx,
1311 lp_dcerpc_endpoint_servers(),
1313 if (!NT_STATUS_IS_OK(status)) goto failed;
1315 /* Make sure the directory for NCALRPC exists */
1316 if (!directory_exist(lp_ncalrpc_dir())) {
1317 mkdir(lp_ncalrpc_dir(), 0755);
1320 for (e=dce_ctx->endpoint_list;e;e=e->next) {
1321 switch (e->ep_description->transport) {
1322 case NCACN_UNIX_STREAM:
1323 status = dcesrv_add_ep_unix(dce_ctx, e, task->event_ctx, task->model_ops);
1324 if (!NT_STATUS_IS_OK(status)) goto failed;
1328 status = dcesrv_add_ep_ncalrpc(dce_ctx, e, task->event_ctx, task->model_ops);
1329 if (!NT_STATUS_IS_OK(status)) goto failed;
1333 status = dcesrv_add_ep_tcp(dce_ctx, e, task->event_ctx, task->model_ops);
1334 if (!NT_STATUS_IS_OK(status)) goto failed;
1338 /* FIXME: status = dcesrv_add_ep_np(dce_ctx, e, task->event_ctx, task->model_ops);
1339 if (!NT_STATUS_IS_OK(status)) goto failed;
1343 status = NT_STATUS_NOT_SUPPORTED;
1344 if (!NT_STATUS_IS_OK(status)) goto failed;
1350 task_server_terminate(task, "Failed to startup dcerpc server task");
1354 called on startup of the smb server service It's job is to start
1355 listening on all configured sockets
1357 static NTSTATUS dcesrv_init(struct event_context *event_context,
1358 const struct model_ops *model_ops)
1360 return task_server_startup(event_context, model_ops, dcesrv_task_init);
1363 NTSTATUS server_service_rpc_init(void)
1365 init_module_fn static_init[] = STATIC_dcerpc_server_MODULES;
1366 init_module_fn *shared_init = load_samba_modules(NULL, "dcerpc_server");
1368 run_init_functions(static_init);
1369 run_init_functions(shared_init);
1371 talloc_free(shared_init);
1373 return register_server_service("rpc", dcesrv_init);