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 stream_connection *srv_conn,
293 uint32_t state_flags,
294 struct dcesrv_connection **_p)
296 struct dcesrv_connection *p;
298 p = talloc(mem_ctx, struct dcesrv_connection);
299 NT_STATUS_HAVE_NO_MEMORY(p);
301 p->dce_ctx = dce_ctx;
305 p->pending_call_list = NULL;
306 p->cli_max_recv_frag = 0;
307 p->partial_input = data_blob(NULL, 0);
308 p->auth_state.auth_info = NULL;
309 p->auth_state.gensec_security = NULL;
310 p->auth_state.session_info = NULL;
311 p->auth_state.session_key = dcesrv_generic_session_key;
312 p->srv_conn = srv_conn;
313 p->processing = False;
314 p->state_flags = state_flags;
316 talloc_set_destructor(p, dcesrv_endpoint_destructor);
323 search and connect to a dcerpc endpoint
325 NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
327 const struct dcerpc_binding *ep_description,
328 struct auth_session_info *session_info,
329 struct stream_connection *srv_conn,
330 uint32_t state_flags,
331 struct dcesrv_connection **dce_conn_p)
334 const struct dcesrv_endpoint *ep;
336 /* make sure this endpoint exists */
337 ep = find_endpoint(dce_ctx, ep_description);
339 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
342 status = dcesrv_endpoint_connect(dce_ctx, mem_ctx, ep, srv_conn, state_flags, dce_conn_p);
343 if (!NT_STATUS_IS_OK(status)) {
347 (*dce_conn_p)->auth_state.session_info = talloc_reference((*dce_conn_p), session_info);
348 (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
350 /* TODO: check security descriptor of the endpoint here
351 * if it's a smb named pipe
352 * if it's failed free dce_conn_p
359 static void dcesrv_init_hdr(struct ncacn_packet *pkt)
362 pkt->rpc_vers_minor = 0;
363 if (lp_rpc_big_endian()) {
366 pkt->drep[0] = DCERPC_DREP_LE;
374 return a dcerpc fault
376 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
378 struct ncacn_packet pkt;
379 struct data_blob_list_item *rep;
382 /* setup a bind_ack */
383 dcesrv_init_hdr(&pkt);
385 pkt.call_id = call->pkt.call_id;
386 pkt.ptype = DCERPC_PKT_FAULT;
387 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
388 pkt.u.fault.alloc_hint = 0;
389 pkt.u.fault.context_id = 0;
390 pkt.u.fault.cancel_count = 0;
391 pkt.u.fault.status = fault_code;
393 rep = talloc(call, struct data_blob_list_item);
395 return NT_STATUS_NO_MEMORY;
398 status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
399 if (!NT_STATUS_IS_OK(status)) {
403 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
405 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
406 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
413 return a dcerpc bind_nak
415 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
417 struct ncacn_packet pkt;
418 struct data_blob_list_item *rep;
421 /* setup a bind_nak */
422 dcesrv_init_hdr(&pkt);
424 pkt.call_id = call->pkt.call_id;
425 pkt.ptype = DCERPC_PKT_BIND_NAK;
426 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
427 pkt.u.bind_nak.reject_reason = reason;
428 pkt.u.bind_nak.num_versions = 0;
430 rep = talloc(call, struct data_blob_list_item);
432 return NT_STATUS_NO_MEMORY;
435 status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
436 if (!NT_STATUS_IS_OK(status)) {
440 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
442 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
443 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
450 handle a bind request
452 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
454 uint32_t if_version, transfer_syntax_version;
455 struct GUID uuid, *transfer_syntax_uuid;
456 struct ncacn_packet pkt;
457 struct data_blob_list_item *rep;
459 uint32_t result=0, reason=0;
461 const struct dcesrv_interface *iface;
463 if (call->pkt.u.bind.num_contexts < 1 ||
464 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
465 return dcesrv_bind_nak(call, 0);
468 context_id = call->pkt.u.bind.ctx_list[0].context_id;
470 /* you can't bind twice on one context */
471 if (dcesrv_find_context(call->conn, context_id) != NULL) {
472 return dcesrv_bind_nak(call, 0);
475 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
476 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
478 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
479 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
480 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
481 ndr_transfer_syntax.if_version != transfer_syntax_version) {
482 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
483 /* we only do NDR encoded dcerpc */
484 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
485 talloc_free(uuid_str);
486 return dcesrv_bind_nak(call, 0);
489 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
491 char *uuid_str = GUID_string(call, &uuid);
492 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
493 talloc_free(uuid_str);
495 /* we don't know about that interface */
496 result = DCERPC_BIND_PROVIDER_REJECT;
497 reason = DCERPC_BIND_REASON_ASYNTAX;
501 /* add this context to the list of available context_ids */
502 struct dcesrv_connection_context *context = talloc(call->conn,
503 struct dcesrv_connection_context);
504 if (context == NULL) {
505 return dcesrv_bind_nak(call, 0);
507 context->conn = call->conn;
508 context->iface = iface;
509 context->context_id = context_id;
510 context->private = NULL;
511 context->handles = NULL;
512 DLIST_ADD(call->conn->contexts, context);
513 call->context = context;
516 if (call->conn->cli_max_recv_frag == 0) {
517 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
520 /* handle any authentication that is being requested */
521 if (!dcesrv_auth_bind(call)) {
522 /* TODO: work out the right reject code */
523 return dcesrv_bind_nak(call, 0);
526 /* setup a bind_ack */
527 dcesrv_init_hdr(&pkt);
529 pkt.call_id = call->pkt.call_id;
530 pkt.ptype = DCERPC_PKT_BIND_ACK;
531 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
532 pkt.u.bind_ack.max_xmit_frag = 0x2000;
533 pkt.u.bind_ack.max_recv_frag = 0x2000;
534 pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
536 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
537 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
539 pkt.u.bind_ack.secondary_address = "";
541 pkt.u.bind_ack.num_results = 1;
542 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
543 if (!pkt.u.bind_ack.ctx_list) {
544 return NT_STATUS_NO_MEMORY;
546 pkt.u.bind_ack.ctx_list[0].result = result;
547 pkt.u.bind_ack.ctx_list[0].reason = reason;
548 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
549 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
551 if (!dcesrv_auth_bind_ack(call, &pkt)) {
552 return dcesrv_bind_nak(call, 0);
556 status = iface->bind(call, iface);
557 if (!NT_STATUS_IS_OK(status)) {
558 char *uuid_str = GUID_string(call, &uuid);
559 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
560 uuid_str, if_version, nt_errstr(status)));
561 talloc_free(uuid_str);
562 return dcesrv_bind_nak(call, 0);
566 rep = talloc(call, struct data_blob_list_item);
568 return NT_STATUS_NO_MEMORY;
571 status = ncacn_push_auth(&rep->blob, call, &pkt,
572 call->conn->auth_state.auth_info);
573 if (!NT_STATUS_IS_OK(status)) {
577 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
579 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
580 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
587 handle a auth3 request
589 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
591 /* handle the auth3 in the auth code */
592 if (!dcesrv_auth_auth3(call)) {
593 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
598 /* we don't send a reply to a auth3 request, except by a
605 handle a bind request
607 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
609 uint32_t if_version, transfer_syntax_version;
610 struct dcesrv_connection_context *context;
611 const struct dcesrv_interface *iface;
612 struct GUID uuid, *transfer_syntax_uuid;
614 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
615 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
617 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
618 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
619 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
620 ndr_transfer_syntax.if_version != transfer_syntax_version) {
621 /* we only do NDR encoded dcerpc */
622 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
625 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
627 char *uuid_str = GUID_string(call, &uuid);
628 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
629 talloc_free(uuid_str);
630 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
633 /* add this context to the list of available context_ids */
634 context = talloc(call->conn, struct dcesrv_connection_context);
635 if (context == NULL) {
636 return NT_STATUS_NO_MEMORY;
638 context->conn = call->conn;
639 context->iface = iface;
640 context->context_id = context_id;
641 context->private = NULL;
642 context->handles = NULL;
643 DLIST_ADD(call->conn->contexts, context);
644 call->context = context;
651 handle a alter context request
653 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
655 struct ncacn_packet pkt;
656 struct data_blob_list_item *rep;
658 uint32_t result=0, reason=0;
661 /* handle any authentication that is being requested */
662 if (!dcesrv_auth_alter(call)) {
663 /* TODO: work out the right reject code */
664 result = DCERPC_BIND_PROVIDER_REJECT;
665 reason = DCERPC_BIND_REASON_ASYNTAX;
668 context_id = call->pkt.u.alter.ctx_list[0].context_id;
670 /* see if they are asking for a new interface */
672 dcesrv_find_context(call->conn, context_id) == NULL) {
673 status = dcesrv_alter_new_context(call, context_id);
674 if (!NT_STATUS_IS_OK(status)) {
675 result = DCERPC_BIND_PROVIDER_REJECT;
676 reason = DCERPC_BIND_REASON_ASYNTAX;
680 /* setup a alter_resp */
681 dcesrv_init_hdr(&pkt);
683 pkt.call_id = call->pkt.call_id;
684 pkt.ptype = DCERPC_PKT_ALTER_RESP;
685 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
686 pkt.u.alter_resp.max_xmit_frag = 0x2000;
687 pkt.u.alter_resp.max_recv_frag = 0x2000;
688 pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
689 pkt.u.alter_resp.num_results = 1;
690 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
691 if (!pkt.u.alter_resp.ctx_list) {
692 return NT_STATUS_NO_MEMORY;
694 pkt.u.alter_resp.ctx_list[0].result = result;
695 pkt.u.alter_resp.ctx_list[0].reason = reason;
696 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
697 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
698 pkt.u.alter_resp.secondary_address = "";
700 if (!dcesrv_auth_alter_ack(call, &pkt)) {
701 return dcesrv_bind_nak(call, 0);
704 rep = talloc(call, struct data_blob_list_item);
706 return NT_STATUS_NO_MEMORY;
709 status = ncacn_push_auth(&rep->blob, call, &pkt,
710 call->conn->auth_state.auth_info);
711 if (!NT_STATUS_IS_OK(status)) {
715 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
717 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
718 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
724 handle a dcerpc request packet
726 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
728 struct ndr_pull *pull;
730 struct dcesrv_connection_context *context;
732 call->fault_code = 0;
733 call->state_flags = call->conn->state_flags;
734 call->time = timeval_current();
736 /* if authenticated, and the mech we use can't do async replies, don't use them... */
737 if (call->conn->auth_state.gensec_security &&
738 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
739 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
742 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
743 if (context == NULL) {
744 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
747 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
748 NT_STATUS_HAVE_NO_MEMORY(pull);
750 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
752 call->context = context;
753 call->event_ctx = context->conn->srv_conn->event.ctx;
754 call->ndr_pull = pull;
756 if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_ORPC) {
757 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
760 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
761 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
764 /* unravel the NDR for the packet */
765 status = context->iface->ndr_pull(call, call, pull, &call->r);
766 if (!NT_STATUS_IS_OK(status)) {
767 return dcesrv_fault(call, call->fault_code);
770 if (pull->offset != pull->data_size) {
771 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
772 pull->data_size - pull->offset));
773 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
776 /* call the dispatch function */
777 status = context->iface->dispatch(call, call, call->r);
778 if (!NT_STATUS_IS_OK(status)) {
779 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
780 context->iface->name,
781 call->pkt.u.request.opnum,
782 dcerpc_errstr(pull, call->fault_code)));
783 return dcesrv_fault(call, call->fault_code);
786 /* add the call to the pending list */
787 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
789 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
793 return dcesrv_reply(call);
796 NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
798 struct ndr_push *push;
801 uint32_t total_length;
802 struct dcesrv_connection_context *context = call->context;
804 /* call the reply function */
805 status = context->iface->reply(call, call, call->r);
806 if (!NT_STATUS_IS_OK(status)) {
807 return dcesrv_fault(call, call->fault_code);
810 /* form the reply NDR */
811 push = ndr_push_init_ctx(call);
812 NT_STATUS_HAVE_NO_MEMORY(push);
814 /* carry over the pointer count to the reply in case we are
815 using full pointer. See NDR specification for full
817 push->ptr_count = call->ndr_pull->ptr_count;
819 if (lp_rpc_big_endian()) {
820 push->flags |= LIBNDR_FLAG_BIGENDIAN;
823 status = context->iface->ndr_push(call, call, push, call->r);
824 if (!NT_STATUS_IS_OK(status)) {
825 return dcesrv_fault(call, call->fault_code);
828 stub = ndr_push_blob(push);
830 total_length = stub.length;
834 struct data_blob_list_item *rep;
835 struct ncacn_packet pkt;
837 rep = talloc(call, struct data_blob_list_item);
838 NT_STATUS_HAVE_NO_MEMORY(rep);
840 length = stub.length;
841 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
842 /* the 32 is to cope with signing data */
843 length = call->conn->cli_max_recv_frag -
844 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
847 /* form the dcerpc response packet */
848 dcesrv_init_hdr(&pkt);
850 pkt.call_id = call->pkt.call_id;
851 pkt.ptype = DCERPC_PKT_RESPONSE;
853 if (stub.length == total_length) {
854 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
856 if (length == stub.length) {
857 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
859 pkt.u.response.alloc_hint = stub.length;
860 pkt.u.response.context_id = call->pkt.u.request.context_id;
861 pkt.u.response.cancel_count = 0;
862 pkt.u.response.stub_and_verifier.data = stub.data;
863 pkt.u.response.stub_and_verifier.length = length;
865 if (!dcesrv_auth_response(call, &rep->blob, &pkt)) {
866 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
869 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
871 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
874 stub.length -= length;
875 } while (stub.length != 0);
877 /* move the call from the pending to the finished calls list */
878 DLIST_REMOVE(call->conn->pending_call_list, call);
879 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
881 if (call->conn->call_list && call->conn->call_list->replies) {
882 if (call->conn->srv_conn &&
883 call->conn->srv_conn->event.fde) {
884 EVENT_FD_WRITEABLE(call->conn->srv_conn->event.fde);
893 work out if we have a full packet yet
895 static BOOL dce_full_packet(const DATA_BLOB *data)
897 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
900 if (dcerpc_get_frag_length(data) > data->length) {
907 we might have consumed only part of our input - advance past that part
909 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
913 if (dce_conn->partial_input.length == offset) {
914 data_blob_free(&dce_conn->partial_input);
918 blob = dce_conn->partial_input;
919 dce_conn->partial_input = data_blob(blob.data + offset,
920 blob.length - offset);
921 data_blob_free(&blob);
925 process some input to a dcerpc endpoint server.
927 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
929 struct ndr_pull *ndr;
931 struct dcesrv_call_state *call;
934 call = talloc(dce_conn, struct dcesrv_call_state);
936 talloc_free(dce_conn->partial_input.data);
937 return NT_STATUS_NO_MEMORY;
939 call->conn = dce_conn;
940 call->replies = NULL;
941 call->context = NULL;
942 call->event_ctx = dce_conn->srv_conn->event.ctx;
944 blob = dce_conn->partial_input;
945 blob.length = dcerpc_get_frag_length(&blob);
947 ndr = ndr_pull_init_blob(&blob, call);
949 talloc_free(dce_conn->partial_input.data);
951 return NT_STATUS_NO_MEMORY;
954 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
955 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
958 status = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
959 if (!NT_STATUS_IS_OK(status)) {
960 talloc_free(dce_conn->partial_input.data);
965 /* we have to check the signing here, before combining the
967 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
968 !dcesrv_auth_request(call, &blob)) {
969 dce_partial_advance(dce_conn, blob.length);
970 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
973 dce_partial_advance(dce_conn, blob.length);
975 /* see if this is a continued packet */
976 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
977 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
978 struct dcesrv_call_state *call2 = call;
981 /* we only allow fragmented requests, no other packet types */
982 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
983 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
986 /* this is a continuation of an existing call - find the call then
987 tack it on the end */
988 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
990 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
993 if (call->pkt.ptype != call2->pkt.ptype) {
994 /* trying to play silly buggers are we? */
995 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
998 alloc_size = call->pkt.u.request.stub_and_verifier.length +
999 call2->pkt.u.request.stub_and_verifier.length;
1000 if (call->pkt.u.request.alloc_hint > alloc_size) {
1001 alloc_size = call->pkt.u.request.alloc_hint;
1004 call->pkt.u.request.stub_and_verifier.data =
1005 talloc_realloc(call,
1006 call->pkt.u.request.stub_and_verifier.data,
1007 uint8_t, alloc_size);
1008 if (!call->pkt.u.request.stub_and_verifier.data) {
1009 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1011 memcpy(call->pkt.u.request.stub_and_verifier.data +
1012 call->pkt.u.request.stub_and_verifier.length,
1013 call2->pkt.u.request.stub_and_verifier.data,
1014 call2->pkt.u.request.stub_and_verifier.length);
1015 call->pkt.u.request.stub_and_verifier.length +=
1016 call2->pkt.u.request.stub_and_verifier.length;
1018 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1023 /* this may not be the last pdu in the chain - if its isn't then
1024 just put it on the call_list and wait for the rest */
1025 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1026 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1027 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
1028 return NT_STATUS_OK;
1031 switch (call->pkt.ptype) {
1032 case DCERPC_PKT_BIND:
1033 status = dcesrv_bind(call);
1035 case DCERPC_PKT_AUTH3:
1036 status = dcesrv_auth3(call);
1038 case DCERPC_PKT_ALTER:
1039 status = dcesrv_alter(call);
1041 case DCERPC_PKT_REQUEST:
1042 status = dcesrv_request(call);
1045 status = NT_STATUS_INVALID_PARAMETER;
1049 /* if we are going to be sending a reply then add
1050 it to the list of pending calls. We add it to the end to keep the call
1051 list in the order we will answer */
1052 if (!NT_STATUS_IS_OK(status)) {
1061 provide some input to a dcerpc endpoint server. This passes data
1062 from a dcerpc client into the server
1064 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1068 dce_conn->partial_input.data = talloc_realloc(dce_conn,
1069 dce_conn->partial_input.data,
1071 dce_conn->partial_input.length + data->length);
1072 if (!dce_conn->partial_input.data) {
1073 return NT_STATUS_NO_MEMORY;
1075 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1076 data->data, data->length);
1077 dce_conn->partial_input.length += data->length;
1079 while (dce_full_packet(&dce_conn->partial_input)) {
1080 status = dcesrv_input_process(dce_conn);
1081 if (!NT_STATUS_IS_OK(status)) {
1086 return NT_STATUS_OK;
1090 retrieve some output from a dcerpc server
1091 The caller supplies a function that will be called to do the
1094 The first argument to write_fn() will be 'private', the second will
1095 be a pointer to a buffer containing the data to be sent and the 3rd
1096 will be a pointer to a size_t variable that will be set to the
1097 number of bytes that are consumed from the output.
1099 from the current fragment
1101 NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
1103 NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1106 struct dcesrv_call_state *call;
1107 struct data_blob_list_item *rep;
1110 call = dce_conn->call_list;
1111 if (!call || !call->replies) {
1112 if (dce_conn->pending_call_list) {
1113 /* TODO: we need to say act async here
1114 * as we know we have pending requests
1115 * which will be finished at a time
1117 return NT_STATUS_FOOBAR;
1119 return NT_STATUS_FOOBAR;
1121 rep = call->replies;
1123 status = write_fn(private_data, &rep->blob, &nwritten);
1124 NT_STATUS_IS_ERR_RETURN(status);
1126 rep->blob.length -= nwritten;
1127 rep->blob.data += nwritten;
1129 if (rep->blob.length == 0) {
1130 /* we're done with this section of the call */
1131 DLIST_REMOVE(call->replies, rep);
1134 if (call->replies == NULL) {
1135 /* we're done with the whole call */
1136 DLIST_REMOVE(dce_conn->call_list, call);
1143 static NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1146 struct dcesrv_context *dce_ctx;
1149 if (!endpoint_servers) {
1150 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1151 return NT_STATUS_INTERNAL_ERROR;
1154 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1155 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1156 dce_ctx->endpoint_list = NULL;
1158 for (i=0;endpoint_servers[i];i++) {
1159 const struct dcesrv_endpoint_server *ep_server;
1161 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1163 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1164 return NT_STATUS_INTERNAL_ERROR;
1167 status = ep_server->init_server(dce_ctx, ep_server);
1168 if (!NT_STATUS_IS_OK(status)) {
1169 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1170 nt_errstr(status)));
1175 *_dce_ctx = dce_ctx;
1176 return NT_STATUS_OK;
1180 initialise the dcerpc server context for ncacn_np based services
1182 NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **_dce_ctx)
1185 struct dcesrv_context *dce_ctx;
1187 status = dcesrv_init_context(mem_ctx, lp_dcerpc_endpoint_servers(), &dce_ctx);
1188 NT_STATUS_NOT_OK_RETURN(status);
1190 *_dce_ctx = dce_ctx;
1191 return NT_STATUS_OK;
1194 /* the list of currently registered DCERPC endpoint servers.
1196 static struct ep_server {
1197 struct dcesrv_endpoint_server *ep_server;
1198 } *ep_servers = NULL;
1199 static int num_ep_servers;
1202 register a DCERPC endpoint server.
1204 The 'name' can be later used by other backends to find the operations
1205 structure for this backend.
1207 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1209 NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1211 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1213 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1214 /* its already registered! */
1215 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1217 return NT_STATUS_OBJECT_NAME_COLLISION;
1220 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1222 smb_panic("out of memory in dcerpc_register");
1225 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1226 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1230 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1233 return NT_STATUS_OK;
1237 return the operations structure for a named backend of the specified type
1239 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1243 for (i=0;i<num_ep_servers;i++) {
1244 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1245 return ep_servers[i].ep_server;
1253 return the DCERPC module version, and the size of some critical types
1254 This can be used by endpoint server modules to either detect compilation errors, or provide
1255 multiple implementations for different smbd compilation options in one module
1257 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1259 static const struct dcesrv_critical_sizes critical_sizes = {
1260 DCERPC_MODULE_VERSION,
1261 sizeof(struct dcesrv_context),
1262 sizeof(struct dcesrv_endpoint),
1263 sizeof(struct dcesrv_endpoint_server),
1264 sizeof(struct dcesrv_interface),
1265 sizeof(struct dcesrv_if_list),
1266 sizeof(struct dcesrv_connection),
1267 sizeof(struct dcesrv_call_state),
1268 sizeof(struct dcesrv_auth),
1269 sizeof(struct dcesrv_handle)
1272 return &critical_sizes;
1276 open the dcerpc server sockets
1278 static void dcesrv_task_init(struct task_server *task)
1281 struct dcesrv_context *dce_ctx;
1282 struct dcesrv_endpoint *e;
1284 task_server_set_title(task, "task[dcesrv]");
1286 status = dcesrv_init_context(task->event_ctx,
1287 lp_dcerpc_endpoint_servers(),
1289 if (!NT_STATUS_IS_OK(status)) goto failed;
1291 /* Make sure the directory for NCALRPC exists */
1292 if (!directory_exist(lp_ncalrpc_dir())) {
1293 mkdir(lp_ncalrpc_dir(), 0755);
1296 for (e=dce_ctx->endpoint_list;e;e=e->next) {
1297 switch (e->ep_description->transport) {
1298 case NCACN_UNIX_STREAM:
1299 status = dcesrv_add_ep_unix(dce_ctx, e, task->event_ctx, task->model_ops);
1300 if (!NT_STATUS_IS_OK(status)) goto failed;
1304 status = dcesrv_add_ep_ncalrpc(dce_ctx, e, task->event_ctx, task->model_ops);
1305 if (!NT_STATUS_IS_OK(status)) goto failed;
1309 status = dcesrv_add_ep_tcp(dce_ctx, e, task->event_ctx, task->model_ops);
1310 if (!NT_STATUS_IS_OK(status)) goto failed;
1314 /* FIXME: status = dcesrv_add_ep_np(dce_ctx, e, task->event_ctx, task->model_ops);
1315 if (!NT_STATUS_IS_OK(status)) goto failed;
1319 status = NT_STATUS_NOT_SUPPORTED;
1320 if (!NT_STATUS_IS_OK(status)) goto failed;
1326 task_server_terminate(task, "Failed to startup dcerpc server task");
1330 called on startup of the smb server service It's job is to start
1331 listening on all configured sockets
1333 static NTSTATUS dcesrv_init(struct event_context *event_context,
1334 const struct model_ops *model_ops)
1336 return task_server_startup(event_context, model_ops, dcesrv_task_init);
1339 NTSTATUS server_service_rpc_init(void)
1341 init_module_fn static_init[] = STATIC_dcerpc_server_MODULES;
1342 init_module_fn *shared_init = load_samba_modules(NULL, "rpc_server");
1344 run_init_functions(static_init);
1345 run_init_functions(shared_init);
1347 talloc_free(shared_init);
1349 return register_server_service("rpc", dcesrv_init);