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 event_context *event_ctx,
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->event_ctx = event_ctx;
313 p->processing = False;
314 p->state_flags = state_flags;
315 ZERO_STRUCT(p->transport);
317 talloc_set_destructor(p, dcesrv_endpoint_destructor);
324 search and connect to a dcerpc endpoint
326 NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
328 const struct dcerpc_binding *ep_description,
329 struct auth_session_info *session_info,
330 struct event_context *event_ctx,
331 uint32_t state_flags,
332 struct dcesrv_connection **dce_conn_p)
335 const struct dcesrv_endpoint *ep;
337 /* make sure this endpoint exists */
338 ep = find_endpoint(dce_ctx, ep_description);
340 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
343 status = dcesrv_endpoint_connect(dce_ctx, mem_ctx, ep, event_ctx, state_flags, dce_conn_p);
344 if (!NT_STATUS_IS_OK(status)) {
348 (*dce_conn_p)->auth_state.session_info = talloc_reference((*dce_conn_p), session_info);
349 (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
351 /* TODO: check security descriptor of the endpoint here
352 * if it's a smb named pipe
353 * if it's failed free dce_conn_p
360 static void dcesrv_init_hdr(struct ncacn_packet *pkt)
363 pkt->rpc_vers_minor = 0;
364 if (lp_rpc_big_endian()) {
367 pkt->drep[0] = DCERPC_DREP_LE;
375 return a dcerpc fault
377 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
379 struct ncacn_packet pkt;
380 struct data_blob_list_item *rep;
383 /* setup a bind_ack */
384 dcesrv_init_hdr(&pkt);
386 pkt.call_id = call->pkt.call_id;
387 pkt.ptype = DCERPC_PKT_FAULT;
388 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
389 pkt.u.fault.alloc_hint = 0;
390 pkt.u.fault.context_id = 0;
391 pkt.u.fault.cancel_count = 0;
392 pkt.u.fault.status = fault_code;
394 rep = talloc(call, struct data_blob_list_item);
396 return NT_STATUS_NO_MEMORY;
399 status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
400 if (!NT_STATUS_IS_OK(status)) {
404 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
406 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
407 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
414 return a dcerpc bind_nak
416 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
418 struct ncacn_packet pkt;
419 struct data_blob_list_item *rep;
422 /* setup a bind_nak */
423 dcesrv_init_hdr(&pkt);
425 pkt.call_id = call->pkt.call_id;
426 pkt.ptype = DCERPC_PKT_BIND_NAK;
427 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
428 pkt.u.bind_nak.reject_reason = reason;
429 pkt.u.bind_nak.num_versions = 0;
431 rep = talloc(call, struct data_blob_list_item);
433 return NT_STATUS_NO_MEMORY;
436 status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
437 if (!NT_STATUS_IS_OK(status)) {
441 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
443 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
444 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
451 handle a bind request
453 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
455 uint32_t if_version, transfer_syntax_version;
456 struct GUID uuid, *transfer_syntax_uuid;
457 struct ncacn_packet pkt;
458 struct data_blob_list_item *rep;
460 uint32_t result=0, reason=0;
462 const struct dcesrv_interface *iface;
464 if (call->pkt.u.bind.num_contexts < 1 ||
465 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
466 return dcesrv_bind_nak(call, 0);
469 context_id = call->pkt.u.bind.ctx_list[0].context_id;
471 /* you can't bind twice on one context */
472 if (dcesrv_find_context(call->conn, context_id) != NULL) {
473 return dcesrv_bind_nak(call, 0);
476 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
477 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
479 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
480 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
481 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
482 ndr_transfer_syntax.if_version != transfer_syntax_version) {
483 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
484 /* we only do NDR encoded dcerpc */
485 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
486 talloc_free(uuid_str);
487 return dcesrv_bind_nak(call, 0);
490 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
492 char *uuid_str = GUID_string(call, &uuid);
493 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
494 talloc_free(uuid_str);
496 /* we don't know about that interface */
497 result = DCERPC_BIND_PROVIDER_REJECT;
498 reason = DCERPC_BIND_REASON_ASYNTAX;
502 /* add this context to the list of available context_ids */
503 struct dcesrv_connection_context *context = talloc(call->conn,
504 struct dcesrv_connection_context);
505 if (context == NULL) {
506 return dcesrv_bind_nak(call, 0);
508 context->conn = call->conn;
509 context->iface = iface;
510 context->context_id = context_id;
511 context->private = NULL;
512 context->handles = NULL;
513 DLIST_ADD(call->conn->contexts, context);
514 call->context = context;
517 if (call->conn->cli_max_recv_frag == 0) {
518 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
521 /* handle any authentication that is being requested */
522 if (!dcesrv_auth_bind(call)) {
523 /* TODO: work out the right reject code */
524 return dcesrv_bind_nak(call, 0);
527 /* setup a bind_ack */
528 dcesrv_init_hdr(&pkt);
530 pkt.call_id = call->pkt.call_id;
531 pkt.ptype = DCERPC_PKT_BIND_ACK;
532 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
533 pkt.u.bind_ack.max_xmit_frag = 0x2000;
534 pkt.u.bind_ack.max_recv_frag = 0x2000;
535 pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
537 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
538 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
540 pkt.u.bind_ack.secondary_address = "";
542 pkt.u.bind_ack.num_results = 1;
543 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
544 if (!pkt.u.bind_ack.ctx_list) {
545 return NT_STATUS_NO_MEMORY;
547 pkt.u.bind_ack.ctx_list[0].result = result;
548 pkt.u.bind_ack.ctx_list[0].reason = reason;
549 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
550 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
552 if (!dcesrv_auth_bind_ack(call, &pkt)) {
553 return dcesrv_bind_nak(call, 0);
557 status = iface->bind(call, iface);
558 if (!NT_STATUS_IS_OK(status)) {
559 char *uuid_str = GUID_string(call, &uuid);
560 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
561 uuid_str, if_version, nt_errstr(status)));
562 talloc_free(uuid_str);
563 return dcesrv_bind_nak(call, 0);
567 rep = talloc(call, struct data_blob_list_item);
569 return NT_STATUS_NO_MEMORY;
572 status = ncacn_push_auth(&rep->blob, call, &pkt,
573 call->conn->auth_state.auth_info);
574 if (!NT_STATUS_IS_OK(status)) {
578 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
580 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
581 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
588 handle a auth3 request
590 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
592 /* handle the auth3 in the auth code */
593 if (!dcesrv_auth_auth3(call)) {
594 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
599 /* we don't send a reply to a auth3 request, except by a
606 handle a bind request
608 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
610 uint32_t if_version, transfer_syntax_version;
611 struct dcesrv_connection_context *context;
612 const struct dcesrv_interface *iface;
613 struct GUID uuid, *transfer_syntax_uuid;
615 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
616 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
618 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
619 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
620 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
621 ndr_transfer_syntax.if_version != transfer_syntax_version) {
622 /* we only do NDR encoded dcerpc */
623 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
626 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
628 char *uuid_str = GUID_string(call, &uuid);
629 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
630 talloc_free(uuid_str);
631 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
634 /* add this context to the list of available context_ids */
635 context = talloc(call->conn, struct dcesrv_connection_context);
636 if (context == NULL) {
637 return NT_STATUS_NO_MEMORY;
639 context->conn = call->conn;
640 context->iface = iface;
641 context->context_id = context_id;
642 context->private = NULL;
643 context->handles = NULL;
644 DLIST_ADD(call->conn->contexts, context);
645 call->context = context;
652 handle a alter context request
654 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
656 struct ncacn_packet pkt;
657 struct data_blob_list_item *rep;
659 uint32_t result=0, reason=0;
662 /* handle any authentication that is being requested */
663 if (!dcesrv_auth_alter(call)) {
664 /* TODO: work out the right reject code */
665 result = DCERPC_BIND_PROVIDER_REJECT;
666 reason = DCERPC_BIND_REASON_ASYNTAX;
669 context_id = call->pkt.u.alter.ctx_list[0].context_id;
671 /* see if they are asking for a new interface */
673 dcesrv_find_context(call->conn, context_id) == NULL) {
674 status = dcesrv_alter_new_context(call, context_id);
675 if (!NT_STATUS_IS_OK(status)) {
676 result = DCERPC_BIND_PROVIDER_REJECT;
677 reason = DCERPC_BIND_REASON_ASYNTAX;
681 /* setup a alter_resp */
682 dcesrv_init_hdr(&pkt);
684 pkt.call_id = call->pkt.call_id;
685 pkt.ptype = DCERPC_PKT_ALTER_RESP;
686 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
687 pkt.u.alter_resp.max_xmit_frag = 0x2000;
688 pkt.u.alter_resp.max_recv_frag = 0x2000;
689 pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
690 pkt.u.alter_resp.num_results = 1;
691 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
692 if (!pkt.u.alter_resp.ctx_list) {
693 return NT_STATUS_NO_MEMORY;
695 pkt.u.alter_resp.ctx_list[0].result = result;
696 pkt.u.alter_resp.ctx_list[0].reason = reason;
697 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
698 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
699 pkt.u.alter_resp.secondary_address = "";
701 if (!dcesrv_auth_alter_ack(call, &pkt)) {
702 return dcesrv_bind_nak(call, 0);
705 rep = talloc(call, struct data_blob_list_item);
707 return NT_STATUS_NO_MEMORY;
710 status = ncacn_push_auth(&rep->blob, call, &pkt,
711 call->conn->auth_state.auth_info);
712 if (!NT_STATUS_IS_OK(status)) {
716 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
718 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
719 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
725 handle a dcerpc request packet
727 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
729 struct ndr_pull *pull;
731 struct dcesrv_connection_context *context;
733 call->fault_code = 0;
734 call->state_flags = call->conn->state_flags;
735 call->time = timeval_current();
737 /* if authenticated, and the mech we use can't do async replies, don't use them... */
738 if (call->conn->auth_state.gensec_security &&
739 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
740 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
743 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
744 if (context == NULL) {
745 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
748 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
749 NT_STATUS_HAVE_NO_MEMORY(pull);
751 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
753 call->context = context;
754 call->event_ctx = context->conn->event_ctx;
755 call->ndr_pull = pull;
757 if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_ORPC) {
758 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
761 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
762 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
765 /* unravel the NDR for the packet */
766 status = context->iface->ndr_pull(call, call, pull, &call->r);
767 if (!NT_STATUS_IS_OK(status)) {
768 return dcesrv_fault(call, call->fault_code);
771 if (pull->offset != pull->data_size) {
772 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
773 pull->data_size - pull->offset));
774 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
777 /* call the dispatch function */
778 status = context->iface->dispatch(call, call, call->r);
779 if (!NT_STATUS_IS_OK(status)) {
780 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
781 context->iface->name,
782 call->pkt.u.request.opnum,
783 dcerpc_errstr(pull, call->fault_code)));
784 return dcesrv_fault(call, call->fault_code);
787 /* add the call to the pending list */
788 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
790 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
794 return dcesrv_reply(call);
797 NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
799 struct ndr_push *push;
802 uint32_t total_length;
803 struct dcesrv_connection_context *context = call->context;
805 /* call the reply function */
806 status = context->iface->reply(call, call, call->r);
807 if (!NT_STATUS_IS_OK(status)) {
808 return dcesrv_fault(call, call->fault_code);
811 /* form the reply NDR */
812 push = ndr_push_init_ctx(call);
813 NT_STATUS_HAVE_NO_MEMORY(push);
815 /* carry over the pointer count to the reply in case we are
816 using full pointer. See NDR specification for full
818 push->ptr_count = call->ndr_pull->ptr_count;
820 if (lp_rpc_big_endian()) {
821 push->flags |= LIBNDR_FLAG_BIGENDIAN;
824 status = context->iface->ndr_push(call, call, push, call->r);
825 if (!NT_STATUS_IS_OK(status)) {
826 return dcesrv_fault(call, call->fault_code);
829 stub = ndr_push_blob(push);
831 total_length = stub.length;
835 struct data_blob_list_item *rep;
836 struct ncacn_packet pkt;
838 rep = talloc(call, struct data_blob_list_item);
839 NT_STATUS_HAVE_NO_MEMORY(rep);
841 length = stub.length;
842 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
843 /* the 32 is to cope with signing data */
844 length = call->conn->cli_max_recv_frag -
845 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
848 /* form the dcerpc response packet */
849 dcesrv_init_hdr(&pkt);
851 pkt.call_id = call->pkt.call_id;
852 pkt.ptype = DCERPC_PKT_RESPONSE;
854 if (stub.length == total_length) {
855 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
857 if (length == stub.length) {
858 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
860 pkt.u.response.alloc_hint = stub.length;
861 pkt.u.response.context_id = call->pkt.u.request.context_id;
862 pkt.u.response.cancel_count = 0;
863 pkt.u.response.stub_and_verifier.data = stub.data;
864 pkt.u.response.stub_and_verifier.length = length;
866 if (!dcesrv_auth_response(call, &rep->blob, &pkt)) {
867 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
870 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
872 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
875 stub.length -= length;
876 } while (stub.length != 0);
878 /* move the call from the pending to the finished calls list */
879 DLIST_REMOVE(call->conn->pending_call_list, call);
880 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
882 if (call->conn->call_list && call->conn->call_list->replies) {
883 if (call->conn->transport.report_output_data) {
884 call->conn->transport.report_output_data(call->conn);
891 struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
893 if (!conn->transport.get_my_addr) {
897 return conn->transport.get_my_addr(conn, mem_ctx);
900 struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
902 if (!conn->transport.get_peer_addr) {
906 return conn->transport.get_peer_addr(conn, mem_ctx);
910 work out if we have a full packet yet
912 static BOOL dce_full_packet(const DATA_BLOB *data)
914 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
917 if (dcerpc_get_frag_length(data) > data->length) {
924 we might have consumed only part of our input - advance past that part
926 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
930 if (dce_conn->partial_input.length == offset) {
931 data_blob_free(&dce_conn->partial_input);
935 blob = dce_conn->partial_input;
936 dce_conn->partial_input = data_blob(blob.data + offset,
937 blob.length - offset);
938 data_blob_free(&blob);
942 process some input to a dcerpc endpoint server.
944 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
946 struct ndr_pull *ndr;
948 struct dcesrv_call_state *call;
951 call = talloc(dce_conn, struct dcesrv_call_state);
953 talloc_free(dce_conn->partial_input.data);
954 return NT_STATUS_NO_MEMORY;
956 call->conn = dce_conn;
957 call->replies = NULL;
958 call->context = NULL;
959 call->event_ctx = dce_conn->event_ctx;
961 blob = dce_conn->partial_input;
962 blob.length = dcerpc_get_frag_length(&blob);
964 ndr = ndr_pull_init_blob(&blob, call);
966 talloc_free(dce_conn->partial_input.data);
968 return NT_STATUS_NO_MEMORY;
971 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
972 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
975 status = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
976 if (!NT_STATUS_IS_OK(status)) {
977 talloc_free(dce_conn->partial_input.data);
982 /* we have to check the signing here, before combining the
984 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
985 !dcesrv_auth_request(call, &blob)) {
986 dce_partial_advance(dce_conn, blob.length);
987 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
990 dce_partial_advance(dce_conn, blob.length);
992 /* see if this is a continued packet */
993 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
994 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
995 struct dcesrv_call_state *call2 = call;
998 /* we only allow fragmented requests, no other packet types */
999 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1000 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1003 /* this is a continuation of an existing call - find the call then
1004 tack it on the end */
1005 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
1007 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1010 if (call->pkt.ptype != call2->pkt.ptype) {
1011 /* trying to play silly buggers are we? */
1012 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1015 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1016 call2->pkt.u.request.stub_and_verifier.length;
1017 if (call->pkt.u.request.alloc_hint > alloc_size) {
1018 alloc_size = call->pkt.u.request.alloc_hint;
1021 call->pkt.u.request.stub_and_verifier.data =
1022 talloc_realloc(call,
1023 call->pkt.u.request.stub_and_verifier.data,
1024 uint8_t, alloc_size);
1025 if (!call->pkt.u.request.stub_and_verifier.data) {
1026 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1028 memcpy(call->pkt.u.request.stub_and_verifier.data +
1029 call->pkt.u.request.stub_and_verifier.length,
1030 call2->pkt.u.request.stub_and_verifier.data,
1031 call2->pkt.u.request.stub_and_verifier.length);
1032 call->pkt.u.request.stub_and_verifier.length +=
1033 call2->pkt.u.request.stub_and_verifier.length;
1035 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1040 /* this may not be the last pdu in the chain - if its isn't then
1041 just put it on the call_list and wait for the rest */
1042 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1043 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1044 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
1045 return NT_STATUS_OK;
1048 switch (call->pkt.ptype) {
1049 case DCERPC_PKT_BIND:
1050 status = dcesrv_bind(call);
1052 case DCERPC_PKT_AUTH3:
1053 status = dcesrv_auth3(call);
1055 case DCERPC_PKT_ALTER:
1056 status = dcesrv_alter(call);
1058 case DCERPC_PKT_REQUEST:
1059 status = dcesrv_request(call);
1062 status = NT_STATUS_INVALID_PARAMETER;
1066 /* if we are going to be sending a reply then add
1067 it to the list of pending calls. We add it to the end to keep the call
1068 list in the order we will answer */
1069 if (!NT_STATUS_IS_OK(status)) {
1078 provide some input to a dcerpc endpoint server. This passes data
1079 from a dcerpc client into the server
1081 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1085 dce_conn->partial_input.data = talloc_realloc(dce_conn,
1086 dce_conn->partial_input.data,
1088 dce_conn->partial_input.length + data->length);
1089 if (!dce_conn->partial_input.data) {
1090 return NT_STATUS_NO_MEMORY;
1092 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1093 data->data, data->length);
1094 dce_conn->partial_input.length += data->length;
1096 while (dce_full_packet(&dce_conn->partial_input)) {
1097 status = dcesrv_input_process(dce_conn);
1098 if (!NT_STATUS_IS_OK(status)) {
1103 return NT_STATUS_OK;
1107 retrieve some output from a dcerpc server
1108 The caller supplies a function that will be called to do the
1111 The first argument to write_fn() will be 'private', the second will
1112 be a pointer to a buffer containing the data to be sent and the 3rd
1113 will be a pointer to a size_t variable that will be set to the
1114 number of bytes that are consumed from the output.
1116 from the current fragment
1118 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
1120 NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1123 struct dcesrv_call_state *call;
1124 struct data_blob_list_item *rep;
1127 call = dce_conn->call_list;
1128 if (!call || !call->replies) {
1129 if (dce_conn->pending_call_list) {
1130 /* TODO: we need to say act async here
1131 * as we know we have pending requests
1132 * which will be finished at a time
1134 return NT_STATUS_FOOBAR;
1136 return NT_STATUS_FOOBAR;
1138 rep = call->replies;
1140 status = write_fn(private_data, &rep->blob, &nwritten);
1141 NT_STATUS_IS_ERR_RETURN(status);
1143 rep->blob.length -= nwritten;
1144 rep->blob.data += nwritten;
1146 if (rep->blob.length == 0) {
1147 /* we're done with this section of the call */
1148 DLIST_REMOVE(call->replies, rep);
1151 if (call->replies == NULL) {
1152 /* we're done with the whole call */
1153 DLIST_REMOVE(dce_conn->call_list, call);
1160 static NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1163 struct dcesrv_context *dce_ctx;
1166 if (!endpoint_servers) {
1167 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1168 return NT_STATUS_INTERNAL_ERROR;
1171 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1172 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1173 dce_ctx->endpoint_list = NULL;
1175 for (i=0;endpoint_servers[i];i++) {
1176 const struct dcesrv_endpoint_server *ep_server;
1178 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1180 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1181 return NT_STATUS_INTERNAL_ERROR;
1184 status = ep_server->init_server(dce_ctx, ep_server);
1185 if (!NT_STATUS_IS_OK(status)) {
1186 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1187 nt_errstr(status)));
1192 *_dce_ctx = dce_ctx;
1193 return NT_STATUS_OK;
1197 initialise the dcerpc server context for ncacn_np based services
1199 NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **_dce_ctx)
1202 struct dcesrv_context *dce_ctx;
1204 status = dcesrv_init_context(mem_ctx, lp_dcerpc_endpoint_servers(), &dce_ctx);
1205 NT_STATUS_NOT_OK_RETURN(status);
1207 *_dce_ctx = dce_ctx;
1208 return NT_STATUS_OK;
1211 /* the list of currently registered DCERPC endpoint servers.
1213 static struct ep_server {
1214 struct dcesrv_endpoint_server *ep_server;
1215 } *ep_servers = NULL;
1216 static int num_ep_servers;
1219 register a DCERPC endpoint server.
1221 The 'name' can be later used by other backends to find the operations
1222 structure for this backend.
1224 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1226 NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1228 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1230 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1231 /* its already registered! */
1232 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1234 return NT_STATUS_OBJECT_NAME_COLLISION;
1237 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1239 smb_panic("out of memory in dcerpc_register");
1242 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1243 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1247 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1250 return NT_STATUS_OK;
1254 return the operations structure for a named backend of the specified type
1256 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1260 for (i=0;i<num_ep_servers;i++) {
1261 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1262 return ep_servers[i].ep_server;
1270 return the DCERPC module version, and the size of some critical types
1271 This can be used by endpoint server modules to either detect compilation errors, or provide
1272 multiple implementations for different smbd compilation options in one module
1274 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1276 static const struct dcesrv_critical_sizes critical_sizes = {
1277 DCERPC_MODULE_VERSION,
1278 sizeof(struct dcesrv_context),
1279 sizeof(struct dcesrv_endpoint),
1280 sizeof(struct dcesrv_endpoint_server),
1281 sizeof(struct dcesrv_interface),
1282 sizeof(struct dcesrv_if_list),
1283 sizeof(struct dcesrv_connection),
1284 sizeof(struct dcesrv_call_state),
1285 sizeof(struct dcesrv_auth),
1286 sizeof(struct dcesrv_handle)
1289 return &critical_sizes;
1293 open the dcerpc server sockets
1295 static void dcesrv_task_init(struct task_server *task)
1298 struct dcesrv_context *dce_ctx;
1299 struct dcesrv_endpoint *e;
1301 task_server_set_title(task, "task[dcesrv]");
1303 status = dcesrv_init_context(task->event_ctx,
1304 lp_dcerpc_endpoint_servers(),
1306 if (!NT_STATUS_IS_OK(status)) goto failed;
1308 /* Make sure the directory for NCALRPC exists */
1309 if (!directory_exist(lp_ncalrpc_dir())) {
1310 mkdir(lp_ncalrpc_dir(), 0755);
1313 for (e=dce_ctx->endpoint_list;e;e=e->next) {
1314 switch (e->ep_description->transport) {
1315 case NCACN_UNIX_STREAM:
1316 status = dcesrv_add_ep_unix(dce_ctx, e, task->event_ctx, task->model_ops);
1317 if (!NT_STATUS_IS_OK(status)) goto failed;
1321 status = dcesrv_add_ep_ncalrpc(dce_ctx, e, task->event_ctx, task->model_ops);
1322 if (!NT_STATUS_IS_OK(status)) goto failed;
1326 status = dcesrv_add_ep_tcp(dce_ctx, e, task->event_ctx, task->model_ops);
1327 if (!NT_STATUS_IS_OK(status)) goto failed;
1331 /* FIXME: status = dcesrv_add_ep_np(dce_ctx, e, task->event_ctx, task->model_ops);
1332 if (!NT_STATUS_IS_OK(status)) goto failed;
1336 status = NT_STATUS_NOT_SUPPORTED;
1337 if (!NT_STATUS_IS_OK(status)) goto failed;
1343 task_server_terminate(task, "Failed to startup dcerpc server task");
1347 called on startup of the smb server service It's job is to start
1348 listening on all configured sockets
1350 static NTSTATUS dcesrv_init(struct event_context *event_context,
1351 const struct model_ops *model_ops)
1353 return task_server_startup(event_context, model_ops, dcesrv_task_init);
1356 NTSTATUS server_service_rpc_init(void)
1358 init_module_fn static_init[] = STATIC_dcerpc_server_MODULES;
1359 init_module_fn *shared_init = load_samba_modules(NULL, "dcerpc_server");
1361 run_init_functions(static_init);
1362 run_init_functions(shared_init);
1364 talloc_free(shared_init);
1366 return register_server_service("rpc", dcesrv_init);