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 "lib/util/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 _PUBLIC_ 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 _PUBLIC_ 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(struct dcesrv_connection *p)
271 while (p->contexts) {
272 struct dcesrv_connection_context *c = p->contexts;
274 DLIST_REMOVE(p->contexts, c);
277 c->iface->unbind(c, c->iface);
286 connect to a dcerpc endpoint
288 NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
290 const struct dcesrv_endpoint *ep,
291 struct auth_session_info *session_info,
292 struct event_context *event_ctx,
293 struct messaging_context *msg_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->msg_ctx = msg_ctx;
325 p->server_id = server_id;
326 p->processing = False;
327 p->state_flags = state_flags;
328 ZERO_STRUCT(p->transport);
330 talloc_set_destructor(p, dcesrv_endpoint_destructor);
337 search and connect to a dcerpc endpoint
339 _PUBLIC_ NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
341 const struct dcerpc_binding *ep_description,
342 struct auth_session_info *session_info,
343 struct event_context *event_ctx,
344 struct messaging_context *msg_ctx,
346 uint32_t state_flags,
347 struct dcesrv_connection **dce_conn_p)
350 const struct dcesrv_endpoint *ep;
352 /* make sure this endpoint exists */
353 ep = find_endpoint(dce_ctx, ep_description);
355 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
358 status = dcesrv_endpoint_connect(dce_ctx, mem_ctx, ep, session_info,
359 event_ctx, msg_ctx, server_id,
360 state_flags, dce_conn_p);
361 NT_STATUS_NOT_OK_RETURN(status);
363 (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
365 /* TODO: check security descriptor of the endpoint here
366 * if it's a smb named pipe
367 * if it's failed free dce_conn_p
374 static void dcesrv_init_hdr(struct ncacn_packet *pkt)
377 pkt->rpc_vers_minor = 0;
378 if (lp_rpc_big_endian()) {
381 pkt->drep[0] = DCERPC_DREP_LE;
389 return a dcerpc fault
391 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
393 struct ncacn_packet pkt;
394 struct data_blob_list_item *rep;
397 /* setup a bind_ack */
398 dcesrv_init_hdr(&pkt);
400 pkt.call_id = call->pkt.call_id;
401 pkt.ptype = DCERPC_PKT_FAULT;
402 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
403 pkt.u.fault.alloc_hint = 0;
404 pkt.u.fault.context_id = 0;
405 pkt.u.fault.cancel_count = 0;
406 pkt.u.fault.status = fault_code;
408 rep = talloc(call, struct data_blob_list_item);
410 return NT_STATUS_NO_MEMORY;
413 status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
414 if (!NT_STATUS_IS_OK(status)) {
418 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
420 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
421 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
428 return a dcerpc bind_nak
430 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
432 struct ncacn_packet pkt;
433 struct data_blob_list_item *rep;
436 /* setup a bind_nak */
437 dcesrv_init_hdr(&pkt);
439 pkt.call_id = call->pkt.call_id;
440 pkt.ptype = DCERPC_PKT_BIND_NAK;
441 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
442 pkt.u.bind_nak.reject_reason = reason;
443 if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
444 pkt.u.bind_nak.versions.v.num_versions = 0;
447 rep = talloc(call, struct data_blob_list_item);
449 return NT_STATUS_NO_MEMORY;
452 status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
453 if (!NT_STATUS_IS_OK(status)) {
457 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
459 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
460 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
467 handle a bind request
469 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
471 uint32_t if_version, transfer_syntax_version;
472 struct GUID uuid, *transfer_syntax_uuid;
473 struct ncacn_packet pkt;
474 struct data_blob_list_item *rep;
476 uint32_t result=0, reason=0;
478 const struct dcesrv_interface *iface;
480 if (call->pkt.u.bind.num_contexts < 1 ||
481 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
482 return dcesrv_bind_nak(call, 0);
485 context_id = call->pkt.u.bind.ctx_list[0].context_id;
487 /* you can't bind twice on one context */
488 if (dcesrv_find_context(call->conn, context_id) != NULL) {
489 return dcesrv_bind_nak(call, 0);
492 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
493 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
495 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
496 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
497 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
498 ndr_transfer_syntax.if_version != transfer_syntax_version) {
499 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
500 /* we only do NDR encoded dcerpc */
501 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
502 talloc_free(uuid_str);
503 return dcesrv_bind_nak(call, 0);
506 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
508 char *uuid_str = GUID_string(call, &uuid);
509 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
510 talloc_free(uuid_str);
512 /* we don't know about that interface */
513 result = DCERPC_BIND_PROVIDER_REJECT;
514 reason = DCERPC_BIND_REASON_ASYNTAX;
518 /* add this context to the list of available context_ids */
519 struct dcesrv_connection_context *context = talloc(call->conn,
520 struct dcesrv_connection_context);
521 if (context == NULL) {
522 return dcesrv_bind_nak(call, 0);
524 context->conn = call->conn;
525 context->iface = iface;
526 context->context_id = context_id;
527 context->private = NULL;
528 context->handles = NULL;
529 DLIST_ADD(call->conn->contexts, context);
530 call->context = context;
533 if (call->conn->cli_max_recv_frag == 0) {
534 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
537 /* handle any authentication that is being requested */
538 if (!dcesrv_auth_bind(call)) {
539 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
542 /* setup a bind_ack */
543 dcesrv_init_hdr(&pkt);
545 pkt.call_id = call->pkt.call_id;
546 pkt.ptype = DCERPC_PKT_BIND_ACK;
547 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
548 pkt.u.bind_ack.max_xmit_frag = 0x2000;
549 pkt.u.bind_ack.max_recv_frag = 0x2000;
550 pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
552 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
553 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
555 pkt.u.bind_ack.secondary_address = "";
557 pkt.u.bind_ack.num_results = 1;
558 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
559 if (!pkt.u.bind_ack.ctx_list) {
560 return NT_STATUS_NO_MEMORY;
562 pkt.u.bind_ack.ctx_list[0].result = result;
563 pkt.u.bind_ack.ctx_list[0].reason = reason;
564 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
565 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
567 if (!dcesrv_auth_bind_ack(call, &pkt)) {
568 return dcesrv_bind_nak(call, 0);
572 status = iface->bind(call, iface);
573 if (!NT_STATUS_IS_OK(status)) {
574 char *uuid_str = GUID_string(call, &uuid);
575 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
576 uuid_str, if_version, nt_errstr(status)));
577 talloc_free(uuid_str);
578 return dcesrv_bind_nak(call, 0);
582 rep = talloc(call, struct data_blob_list_item);
584 return NT_STATUS_NO_MEMORY;
587 status = ncacn_push_auth(&rep->blob, call, &pkt,
588 call->conn->auth_state.auth_info);
589 if (!NT_STATUS_IS_OK(status)) {
593 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
595 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
596 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
603 handle a auth3 request
605 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
607 /* handle the auth3 in the auth code */
608 if (!dcesrv_auth_auth3(call)) {
609 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
614 /* we don't send a reply to a auth3 request, except by a
621 handle a bind request
623 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
625 uint32_t if_version, transfer_syntax_version;
626 struct dcesrv_connection_context *context;
627 const struct dcesrv_interface *iface;
628 struct GUID uuid, *transfer_syntax_uuid;
630 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
631 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
633 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
634 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
635 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
636 ndr_transfer_syntax.if_version != transfer_syntax_version) {
637 /* we only do NDR encoded dcerpc */
638 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
641 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
643 char *uuid_str = GUID_string(call, &uuid);
644 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
645 talloc_free(uuid_str);
646 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
649 /* add this context to the list of available context_ids */
650 context = talloc(call->conn, struct dcesrv_connection_context);
651 if (context == NULL) {
652 return NT_STATUS_NO_MEMORY;
654 context->conn = call->conn;
655 context->iface = iface;
656 context->context_id = context_id;
657 context->private = NULL;
658 context->handles = NULL;
659 DLIST_ADD(call->conn->contexts, context);
660 call->context = context;
667 handle a alter context request
669 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
671 struct ncacn_packet pkt;
672 struct data_blob_list_item *rep;
674 uint32_t result=0, reason=0;
677 /* handle any authentication that is being requested */
678 if (!dcesrv_auth_alter(call)) {
679 /* TODO: work out the right reject code */
680 result = DCERPC_BIND_PROVIDER_REJECT;
681 reason = DCERPC_BIND_REASON_ASYNTAX;
684 context_id = call->pkt.u.alter.ctx_list[0].context_id;
686 /* see if they are asking for a new interface */
688 dcesrv_find_context(call->conn, context_id) == NULL) {
689 status = dcesrv_alter_new_context(call, context_id);
690 if (!NT_STATUS_IS_OK(status)) {
691 result = DCERPC_BIND_PROVIDER_REJECT;
692 reason = DCERPC_BIND_REASON_ASYNTAX;
696 /* setup a alter_resp */
697 dcesrv_init_hdr(&pkt);
699 pkt.call_id = call->pkt.call_id;
700 pkt.ptype = DCERPC_PKT_ALTER_RESP;
701 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
702 pkt.u.alter_resp.max_xmit_frag = 0x2000;
703 pkt.u.alter_resp.max_recv_frag = 0x2000;
704 pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
705 pkt.u.alter_resp.num_results = 1;
706 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
707 if (!pkt.u.alter_resp.ctx_list) {
708 return NT_STATUS_NO_MEMORY;
710 pkt.u.alter_resp.ctx_list[0].result = result;
711 pkt.u.alter_resp.ctx_list[0].reason = reason;
712 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
713 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
714 pkt.u.alter_resp.secondary_address = "";
716 if (!dcesrv_auth_alter_ack(call, &pkt)) {
717 return dcesrv_bind_nak(call, 0);
720 rep = talloc(call, struct data_blob_list_item);
722 return NT_STATUS_NO_MEMORY;
725 status = ncacn_push_auth(&rep->blob, call, &pkt,
726 call->conn->auth_state.auth_info);
727 if (!NT_STATUS_IS_OK(status)) {
731 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
733 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
734 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
740 handle a dcerpc request packet
742 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
744 struct ndr_pull *pull;
746 struct dcesrv_connection_context *context;
748 /* if authenticated, and the mech we use can't do async replies, don't use them... */
749 if (call->conn->auth_state.gensec_security &&
750 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
751 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
754 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
755 if (context == NULL) {
756 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
759 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
760 NT_STATUS_HAVE_NO_MEMORY(pull);
762 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
764 call->context = context;
765 call->ndr_pull = pull;
767 if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_ORPC) {
768 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
771 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
772 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
775 /* unravel the NDR for the packet */
776 status = context->iface->ndr_pull(call, call, pull, &call->r);
777 if (!NT_STATUS_IS_OK(status)) {
778 return dcesrv_fault(call, call->fault_code);
781 if (pull->offset != pull->data_size) {
782 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
783 pull->data_size - pull->offset));
784 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
787 /* call the dispatch function */
788 status = context->iface->dispatch(call, call, call->r);
789 if (!NT_STATUS_IS_OK(status)) {
790 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
791 context->iface->name,
792 call->pkt.u.request.opnum,
793 dcerpc_errstr(pull, call->fault_code)));
794 return dcesrv_fault(call, call->fault_code);
797 /* add the call to the pending list */
798 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
800 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
804 return dcesrv_reply(call);
807 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
809 struct ndr_push *push;
812 uint32_t total_length;
813 struct dcesrv_connection_context *context = call->context;
815 /* call the reply function */
816 status = context->iface->reply(call, call, call->r);
817 if (!NT_STATUS_IS_OK(status)) {
818 return dcesrv_fault(call, call->fault_code);
821 /* form the reply NDR */
822 push = ndr_push_init_ctx(call);
823 NT_STATUS_HAVE_NO_MEMORY(push);
825 /* carry over the pointer count to the reply in case we are
826 using full pointer. See NDR specification for full
828 push->ptr_count = call->ndr_pull->ptr_count;
830 if (lp_rpc_big_endian()) {
831 push->flags |= LIBNDR_FLAG_BIGENDIAN;
834 status = context->iface->ndr_push(call, call, push, call->r);
835 if (!NT_STATUS_IS_OK(status)) {
836 return dcesrv_fault(call, call->fault_code);
839 stub = ndr_push_blob(push);
841 total_length = stub.length;
845 struct data_blob_list_item *rep;
846 struct ncacn_packet pkt;
848 rep = talloc(call, struct data_blob_list_item);
849 NT_STATUS_HAVE_NO_MEMORY(rep);
851 length = stub.length;
852 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
853 /* the 32 is to cope with signing data */
854 length = call->conn->cli_max_recv_frag -
855 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
858 /* form the dcerpc response packet */
859 dcesrv_init_hdr(&pkt);
861 pkt.call_id = call->pkt.call_id;
862 pkt.ptype = DCERPC_PKT_RESPONSE;
864 if (stub.length == total_length) {
865 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
867 if (length == stub.length) {
868 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
870 pkt.u.response.alloc_hint = stub.length;
871 pkt.u.response.context_id = call->pkt.u.request.context_id;
872 pkt.u.response.cancel_count = 0;
873 pkt.u.response.stub_and_verifier.data = stub.data;
874 pkt.u.response.stub_and_verifier.length = length;
876 if (!dcesrv_auth_response(call, &rep->blob, &pkt)) {
877 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
880 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
882 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
885 stub.length -= length;
886 } while (stub.length != 0);
888 /* move the call from the pending to the finished calls list */
889 DLIST_REMOVE(call->conn->pending_call_list, call);
890 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
892 if (call->conn->call_list && call->conn->call_list->replies) {
893 if (call->conn->transport.report_output_data) {
894 call->conn->transport.report_output_data(call->conn);
901 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
903 if (!conn->transport.get_my_addr) {
907 return conn->transport.get_my_addr(conn, mem_ctx);
910 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
912 if (!conn->transport.get_peer_addr) {
916 return conn->transport.get_peer_addr(conn, mem_ctx);
920 work out if we have a full packet yet
922 static BOOL dce_full_packet(const DATA_BLOB *data)
924 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
927 if (dcerpc_get_frag_length(data) > data->length) {
934 we might have consumed only part of our input - advance past that part
936 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
940 if (dce_conn->partial_input.length == offset) {
941 data_blob_free(&dce_conn->partial_input);
945 blob = dce_conn->partial_input;
946 dce_conn->partial_input = data_blob(blob.data + offset,
947 blob.length - offset);
948 data_blob_free(&blob);
952 process some input to a dcerpc endpoint server.
954 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
956 struct ndr_pull *ndr;
958 struct dcesrv_call_state *call;
961 call = talloc_zero(dce_conn, struct dcesrv_call_state);
963 talloc_free(dce_conn->partial_input.data);
964 return NT_STATUS_NO_MEMORY;
966 call->conn = dce_conn;
967 call->event_ctx = dce_conn->event_ctx;
968 call->msg_ctx = dce_conn->msg_ctx;
969 call->state_flags = call->conn->state_flags;
970 call->time = timeval_current();
972 blob = dce_conn->partial_input;
973 blob.length = dcerpc_get_frag_length(&blob);
975 ndr = ndr_pull_init_blob(&blob, call);
977 talloc_free(dce_conn->partial_input.data);
979 return NT_STATUS_NO_MEMORY;
982 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
983 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
986 status = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
987 if (!NT_STATUS_IS_OK(status)) {
988 talloc_free(dce_conn->partial_input.data);
993 /* we have to check the signing here, before combining the
995 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
996 !dcesrv_auth_request(call, &blob)) {
997 dce_partial_advance(dce_conn, blob.length);
998 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1001 dce_partial_advance(dce_conn, blob.length);
1003 /* see if this is a continued packet */
1004 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1005 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1006 struct dcesrv_call_state *call2 = call;
1007 uint32_t alloc_size;
1009 /* we only allow fragmented requests, no other packet types */
1010 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1011 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1014 /* this is a continuation of an existing call - find the call then
1015 tack it on the end */
1016 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
1018 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1021 if (call->pkt.ptype != call2->pkt.ptype) {
1022 /* trying to play silly buggers are we? */
1023 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1026 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1027 call2->pkt.u.request.stub_and_verifier.length;
1028 if (call->pkt.u.request.alloc_hint > alloc_size) {
1029 alloc_size = call->pkt.u.request.alloc_hint;
1032 call->pkt.u.request.stub_and_verifier.data =
1033 talloc_realloc(call,
1034 call->pkt.u.request.stub_and_verifier.data,
1035 uint8_t, alloc_size);
1036 if (!call->pkt.u.request.stub_and_verifier.data) {
1037 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1039 memcpy(call->pkt.u.request.stub_and_verifier.data +
1040 call->pkt.u.request.stub_and_verifier.length,
1041 call2->pkt.u.request.stub_and_verifier.data,
1042 call2->pkt.u.request.stub_and_verifier.length);
1043 call->pkt.u.request.stub_and_verifier.length +=
1044 call2->pkt.u.request.stub_and_verifier.length;
1046 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1051 /* this may not be the last pdu in the chain - if its isn't then
1052 just put it on the call_list and wait for the rest */
1053 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1054 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1055 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
1056 return NT_STATUS_OK;
1059 switch (call->pkt.ptype) {
1060 case DCERPC_PKT_BIND:
1061 status = dcesrv_bind(call);
1063 case DCERPC_PKT_AUTH3:
1064 status = dcesrv_auth3(call);
1066 case DCERPC_PKT_ALTER:
1067 status = dcesrv_alter(call);
1069 case DCERPC_PKT_REQUEST:
1070 status = dcesrv_request(call);
1073 status = NT_STATUS_INVALID_PARAMETER;
1077 /* if we are going to be sending a reply then add
1078 it to the list of pending calls. We add it to the end to keep the call
1079 list in the order we will answer */
1080 if (!NT_STATUS_IS_OK(status)) {
1089 provide some input to a dcerpc endpoint server. This passes data
1090 from a dcerpc client into the server
1092 _PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1096 dce_conn->partial_input.data = talloc_realloc(dce_conn,
1097 dce_conn->partial_input.data,
1099 dce_conn->partial_input.length + data->length);
1100 if (!dce_conn->partial_input.data) {
1101 return NT_STATUS_NO_MEMORY;
1103 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1104 data->data, data->length);
1105 dce_conn->partial_input.length += data->length;
1107 while (dce_full_packet(&dce_conn->partial_input)) {
1108 status = dcesrv_input_process(dce_conn);
1109 if (!NT_STATUS_IS_OK(status)) {
1114 return NT_STATUS_OK;
1118 retrieve some output from a dcerpc server
1119 The caller supplies a function that will be called to do the
1122 The first argument to write_fn() will be 'private', the second will
1123 be a pointer to a buffer containing the data to be sent and the 3rd
1124 will be a pointer to a size_t variable that will be set to the
1125 number of bytes that are consumed from the output.
1127 from the current fragment
1129 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
1131 NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1134 struct dcesrv_call_state *call;
1135 struct data_blob_list_item *rep;
1138 call = dce_conn->call_list;
1139 if (!call || !call->replies) {
1140 if (dce_conn->pending_call_list) {
1141 /* TODO: we need to say act async here
1142 * as we know we have pending requests
1143 * which will be finished at a time
1145 return NT_STATUS_FOOBAR;
1147 return NT_STATUS_FOOBAR;
1149 rep = call->replies;
1151 status = write_fn(private_data, &rep->blob, &nwritten);
1152 NT_STATUS_IS_ERR_RETURN(status);
1154 rep->blob.length -= nwritten;
1155 rep->blob.data += nwritten;
1157 if (rep->blob.length == 0) {
1158 /* we're done with this section of the call */
1159 DLIST_REMOVE(call->replies, rep);
1162 if (call->replies == NULL) {
1163 /* we're done with the whole call */
1164 DLIST_REMOVE(dce_conn->call_list, call);
1171 static NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1174 struct dcesrv_context *dce_ctx;
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;
1186 for (i=0;endpoint_servers[i];i++) {
1187 const struct dcesrv_endpoint_server *ep_server;
1189 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1191 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1192 return NT_STATUS_INTERNAL_ERROR;
1195 status = ep_server->init_server(dce_ctx, ep_server);
1196 if (!NT_STATUS_IS_OK(status)) {
1197 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1198 nt_errstr(status)));
1203 *_dce_ctx = dce_ctx;
1204 return NT_STATUS_OK;
1208 initialise the dcerpc server context for ncacn_np based services
1210 _PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **_dce_ctx)
1213 struct dcesrv_context *dce_ctx;
1215 status = dcesrv_init_context(mem_ctx, lp_dcerpc_endpoint_servers(), &dce_ctx);
1216 NT_STATUS_NOT_OK_RETURN(status);
1218 *_dce_ctx = dce_ctx;
1219 return NT_STATUS_OK;
1222 /* the list of currently registered DCERPC endpoint servers.
1224 static struct ep_server {
1225 struct dcesrv_endpoint_server *ep_server;
1226 } *ep_servers = NULL;
1227 static int num_ep_servers;
1230 register a DCERPC endpoint server.
1232 The 'name' can be later used by other backends to find the operations
1233 structure for this backend.
1235 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1237 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1239 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1241 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1242 /* its already registered! */
1243 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1245 return NT_STATUS_OBJECT_NAME_COLLISION;
1248 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1250 smb_panic("out of memory in dcerpc_register");
1253 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1254 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1258 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1261 return NT_STATUS_OK;
1265 return the operations structure for a named backend of the specified type
1267 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1271 for (i=0;i<num_ep_servers;i++) {
1272 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1273 return ep_servers[i].ep_server;
1281 return the DCERPC module version, and the size of some critical types
1282 This can be used by endpoint server modules to either detect compilation errors, or provide
1283 multiple implementations for different smbd compilation options in one module
1285 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1287 static const struct dcesrv_critical_sizes critical_sizes = {
1288 DCERPC_MODULE_VERSION,
1289 sizeof(struct dcesrv_context),
1290 sizeof(struct dcesrv_endpoint),
1291 sizeof(struct dcesrv_endpoint_server),
1292 sizeof(struct dcesrv_interface),
1293 sizeof(struct dcesrv_if_list),
1294 sizeof(struct dcesrv_connection),
1295 sizeof(struct dcesrv_call_state),
1296 sizeof(struct dcesrv_auth),
1297 sizeof(struct dcesrv_handle)
1300 return &critical_sizes;
1304 open the dcerpc server sockets
1306 static void dcesrv_task_init(struct task_server *task)
1309 struct dcesrv_context *dce_ctx;
1310 struct dcesrv_endpoint *e;
1312 task_server_set_title(task, "task[dcesrv]");
1314 status = dcesrv_init_context(task->event_ctx,
1315 lp_dcerpc_endpoint_servers(),
1317 if (!NT_STATUS_IS_OK(status)) goto failed;
1319 /* Make sure the directory for NCALRPC exists */
1320 if (!directory_exist(lp_ncalrpc_dir())) {
1321 mkdir(lp_ncalrpc_dir(), 0755);
1324 for (e=dce_ctx->endpoint_list;e;e=e->next) {
1325 switch (e->ep_description->transport) {
1326 case NCACN_UNIX_STREAM:
1327 status = dcesrv_add_ep_unix(dce_ctx, e, task->event_ctx, task->model_ops);
1328 if (!NT_STATUS_IS_OK(status)) goto failed;
1332 status = dcesrv_add_ep_ncalrpc(dce_ctx, e, task->event_ctx, task->model_ops);
1333 if (!NT_STATUS_IS_OK(status)) goto failed;
1337 status = dcesrv_add_ep_tcp(dce_ctx, e, task->event_ctx, task->model_ops);
1338 if (!NT_STATUS_IS_OK(status)) goto failed;
1342 /* FIXME: status = dcesrv_add_ep_np(dce_ctx, e, task->event_ctx, task->model_ops);
1343 if (!NT_STATUS_IS_OK(status)) goto failed;
1347 status = NT_STATUS_NOT_SUPPORTED;
1348 if (!NT_STATUS_IS_OK(status)) goto failed;
1354 task_server_terminate(task, "Failed to startup dcerpc server task");
1358 called on startup of the smb server service It's job is to start
1359 listening on all configured sockets
1361 static NTSTATUS dcesrv_init(struct event_context *event_context,
1362 const struct model_ops *model_ops)
1364 return task_server_startup(event_context, model_ops, dcesrv_task_init);
1367 NTSTATUS server_service_rpc_init(void)
1369 init_module_fn static_init[] = STATIC_dcerpc_server_MODULES;
1370 init_module_fn *shared_init = load_samba_modules(NULL, "dcerpc_server");
1372 run_init_functions(static_init);
1373 run_init_functions(shared_init);
1375 talloc_free(shared_init);
1377 return register_server_service("rpc", dcesrv_init);