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 "auth/gensec/gensec.h"
28 #include "lib/util/dlinklist.h"
29 #include "rpc_server/dcerpc_server.h"
30 #include "lib/events/events.h"
31 #include "smbd/service_task.h"
32 #include "smbd/service_stream.h"
33 #include "smbd/service.h"
34 #include "system/filesys.h"
35 #include "libcli/security/security.h"
38 extern const struct dcesrv_interface dcesrv_mgmt_interface;
41 see if two endpoints match
43 static BOOL endpoints_match(const struct dcerpc_binding *ep1,
44 const struct dcerpc_binding *ep2)
46 if (ep1->transport != ep2->transport) {
50 if (!ep1->endpoint || !ep2->endpoint) {
51 return ep1->endpoint == ep2->endpoint;
54 if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
61 find an endpoint in the dcesrv_context
63 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
64 const struct dcerpc_binding *ep_description)
66 struct dcesrv_endpoint *ep;
67 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
68 if (endpoints_match(ep->ep_description, ep_description)) {
76 find a registered context_id from a bind or alter_context
78 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn,
81 struct dcesrv_connection_context *c;
82 for (c=conn->contexts;c;c=c->next) {
83 if (c->context_id == context_id) return c;
89 see if a uuid and if_version match to an interface
91 static BOOL interface_match(const struct dcesrv_interface *if1,
92 const struct dcesrv_interface *if2)
94 return (if1->syntax_id.if_version == if2->syntax_id.if_version &&
95 GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
99 find the interface operations on an endpoint
101 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
102 const struct dcesrv_interface *iface)
104 struct dcesrv_if_list *ifl;
105 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
106 if (interface_match(&(ifl->iface), iface)) {
107 return &(ifl->iface);
114 see if a uuid and if_version match to an interface
116 static BOOL interface_match_by_uuid(const struct dcesrv_interface *iface,
117 const struct GUID *uuid, uint32_t if_version)
119 return (iface->syntax_id.if_version == if_version &&
120 GUID_equal(&iface->syntax_id.uuid, uuid));
124 find the interface operations on an endpoint by uuid
126 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
127 const struct GUID *uuid, uint32_t if_version)
129 struct dcesrv_if_list *ifl;
130 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
131 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
132 return &(ifl->iface);
139 find the earlier parts of a fragmented call awaiting reassembily
141 static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
143 struct dcesrv_call_state *c;
144 for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
145 if (c->pkt.call_id == call_id) {
153 register an interface on an endpoint
155 _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
157 const struct dcesrv_interface *iface,
158 const struct security_descriptor *sd)
160 struct dcesrv_endpoint *ep;
161 struct dcesrv_if_list *ifl;
162 struct dcerpc_binding *binding;
166 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
168 if (NT_STATUS_IS_ERR(status)) {
169 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
173 /* check if this endpoint exists
175 if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
176 ep = talloc(dce_ctx, struct dcesrv_endpoint);
178 return NT_STATUS_NO_MEMORY;
181 ep->ep_description = talloc_reference(ep, binding);
184 /* add mgmt interface */
185 ifl = talloc(dce_ctx, struct dcesrv_if_list);
187 return NT_STATUS_NO_MEMORY;
190 memcpy(&(ifl->iface), &dcesrv_mgmt_interface,
191 sizeof(struct dcesrv_interface));
193 DLIST_ADD(ep->interface_list, ifl);
196 /* see if the interface is already registered on te endpoint */
197 if (find_interface(ep, iface)!=NULL) {
198 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
199 iface->name, ep_name));
200 return NT_STATUS_OBJECT_NAME_COLLISION;
203 /* talloc a new interface list element */
204 ifl = talloc(dce_ctx, struct dcesrv_if_list);
206 return NT_STATUS_NO_MEMORY;
209 /* copy the given interface struct to the one on the endpoints interface list */
210 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
212 /* if we have a security descriptor given,
213 * we should see if we can set it up on the endpoint
216 /* if there's currently no security descriptor given on the endpoint
219 if (ep->sd == NULL) {
220 ep->sd = security_descriptor_copy(dce_ctx, sd);
223 /* if now there's no security descriptor given on the endpoint
224 * something goes wrong, either we failed to copy the security descriptor
225 * or there was already one on the endpoint
227 if (ep->sd != NULL) {
228 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
229 " on endpoint '%s'\n",
230 iface->name, ep_name));
231 if (add_ep) free(ep);
233 return NT_STATUS_OBJECT_NAME_COLLISION;
237 /* finally add the interface on the endpoint */
238 DLIST_ADD(ep->interface_list, ifl);
240 /* if it's a new endpoint add it to the dcesrv_context */
242 DLIST_ADD(dce_ctx->endpoint_list, ep);
245 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
246 iface->name, ep_name));
251 static NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
252 DATA_BLOB *session_key)
254 if (p->auth_state.session_info->session_key.length) {
255 *session_key = p->auth_state.session_info->session_key;
258 return NT_STATUS_NO_USER_SESSION_KEY;
261 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
262 DATA_BLOB *session_key)
264 /* this took quite a few CPU cycles to find ... */
265 session_key->data = discard_const_p(uint8_t, "SystemLibraryDTC");
266 session_key->length = 16;
271 fetch the user session key - may be default (above) or the SMB session key
273 _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
274 DATA_BLOB *session_key)
276 return p->auth_state.session_key(p, session_key);
281 destroy a link to an endpoint
283 static int dcesrv_endpoint_destructor(struct dcesrv_connection *p)
285 while (p->contexts) {
286 struct dcesrv_connection_context *c = p->contexts;
288 DLIST_REMOVE(p->contexts, c);
291 c->iface->unbind(c, c->iface);
300 connect to a dcerpc endpoint
302 NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
304 const struct dcesrv_endpoint *ep,
305 struct auth_session_info *session_info,
306 struct event_context *event_ctx,
307 struct messaging_context *msg_ctx,
308 struct server_id server_id,
309 uint32_t state_flags,
310 struct dcesrv_connection **_p)
312 struct dcesrv_connection *p;
315 return NT_STATUS_ACCESS_DENIED;
318 p = talloc(mem_ctx, struct dcesrv_connection);
319 NT_STATUS_HAVE_NO_MEMORY(p);
321 if (!talloc_reference(p, session_info)) {
323 return NT_STATUS_NO_MEMORY;
326 p->dce_ctx = dce_ctx;
330 p->incoming_fragmented_call_list = NULL;
331 p->pending_call_list = NULL;
332 p->cli_max_recv_frag = 0;
333 p->partial_input = data_blob(NULL, 0);
334 p->auth_state.auth_info = NULL;
335 p->auth_state.gensec_security = NULL;
336 p->auth_state.session_info = session_info;
337 p->auth_state.session_key = dcesrv_generic_session_key;
338 p->event_ctx = event_ctx;
339 p->msg_ctx = msg_ctx;
340 p->server_id = server_id;
341 p->processing = False;
342 p->state_flags = state_flags;
343 ZERO_STRUCT(p->transport);
345 talloc_set_destructor(p, dcesrv_endpoint_destructor);
352 search and connect to a dcerpc endpoint
354 _PUBLIC_ NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
356 const struct dcerpc_binding *ep_description,
357 struct auth_session_info *session_info,
358 struct event_context *event_ctx,
359 struct messaging_context *msg_ctx,
360 struct server_id server_id,
361 uint32_t state_flags,
362 struct dcesrv_connection **dce_conn_p)
365 const struct dcesrv_endpoint *ep;
367 /* make sure this endpoint exists */
368 ep = find_endpoint(dce_ctx, ep_description);
370 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
373 status = dcesrv_endpoint_connect(dce_ctx, mem_ctx, ep, session_info,
374 event_ctx, msg_ctx, server_id,
375 state_flags, dce_conn_p);
376 NT_STATUS_NOT_OK_RETURN(status);
378 (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
380 /* TODO: check security descriptor of the endpoint here
381 * if it's a smb named pipe
382 * if it's failed free dce_conn_p
389 static void dcesrv_init_hdr(struct ncacn_packet *pkt)
392 pkt->rpc_vers_minor = 0;
393 if (lp_rpc_big_endian()) {
396 pkt->drep[0] = DCERPC_DREP_LE;
404 return a dcerpc fault
406 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
408 struct ncacn_packet pkt;
409 struct data_blob_list_item *rep;
412 /* setup a bind_ack */
413 dcesrv_init_hdr(&pkt);
415 pkt.call_id = call->pkt.call_id;
416 pkt.ptype = DCERPC_PKT_FAULT;
417 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
418 pkt.u.fault.alloc_hint = 0;
419 pkt.u.fault.context_id = 0;
420 pkt.u.fault.cancel_count = 0;
421 pkt.u.fault.status = fault_code;
423 rep = talloc(call, struct data_blob_list_item);
425 return NT_STATUS_NO_MEMORY;
428 status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
429 if (!NT_STATUS_IS_OK(status)) {
433 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
435 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
436 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
443 return a dcerpc bind_nak
445 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
447 struct ncacn_packet pkt;
448 struct data_blob_list_item *rep;
451 /* setup a bind_nak */
452 dcesrv_init_hdr(&pkt);
454 pkt.call_id = call->pkt.call_id;
455 pkt.ptype = DCERPC_PKT_BIND_NAK;
456 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
457 pkt.u.bind_nak.reject_reason = reason;
458 if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
459 pkt.u.bind_nak.versions.v.num_versions = 0;
462 rep = talloc(call, struct data_blob_list_item);
464 return NT_STATUS_NO_MEMORY;
467 status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
468 if (!NT_STATUS_IS_OK(status)) {
472 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
474 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
475 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
482 handle a bind request
484 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
486 uint32_t if_version, transfer_syntax_version;
487 struct GUID uuid, *transfer_syntax_uuid;
488 struct ncacn_packet pkt;
489 struct data_blob_list_item *rep;
491 uint32_t result=0, reason=0;
493 const struct dcesrv_interface *iface;
495 if (call->pkt.u.bind.num_contexts < 1 ||
496 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
497 return dcesrv_bind_nak(call, 0);
500 context_id = call->pkt.u.bind.ctx_list[0].context_id;
502 /* you can't bind twice on one context */
503 if (dcesrv_find_context(call->conn, context_id) != NULL) {
504 return dcesrv_bind_nak(call, 0);
507 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
508 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
510 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
511 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
512 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
513 ndr_transfer_syntax.if_version != transfer_syntax_version) {
514 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
515 /* we only do NDR encoded dcerpc */
516 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
517 talloc_free(uuid_str);
518 return dcesrv_bind_nak(call, 0);
521 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
523 char *uuid_str = GUID_string(call, &uuid);
524 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
525 talloc_free(uuid_str);
527 /* we don't know about that interface */
528 result = DCERPC_BIND_PROVIDER_REJECT;
529 reason = DCERPC_BIND_REASON_ASYNTAX;
533 /* add this context to the list of available context_ids */
534 struct dcesrv_connection_context *context = talloc(call->conn,
535 struct dcesrv_connection_context);
536 if (context == NULL) {
537 return dcesrv_bind_nak(call, 0);
539 context->conn = call->conn;
540 context->iface = iface;
541 context->context_id = context_id;
542 context->private = NULL;
543 context->handles = NULL;
544 DLIST_ADD(call->conn->contexts, context);
545 call->context = context;
548 if (call->conn->cli_max_recv_frag == 0) {
549 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
552 /* handle any authentication that is being requested */
553 if (!dcesrv_auth_bind(call)) {
554 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
557 /* setup a bind_ack */
558 dcesrv_init_hdr(&pkt);
560 pkt.call_id = call->pkt.call_id;
561 pkt.ptype = DCERPC_PKT_BIND_ACK;
562 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
563 pkt.u.bind_ack.max_xmit_frag = 0x2000;
564 pkt.u.bind_ack.max_recv_frag = 0x2000;
565 pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
567 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
568 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
570 pkt.u.bind_ack.secondary_address = "";
572 pkt.u.bind_ack.num_results = 1;
573 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
574 if (!pkt.u.bind_ack.ctx_list) {
575 return NT_STATUS_NO_MEMORY;
577 pkt.u.bind_ack.ctx_list[0].result = result;
578 pkt.u.bind_ack.ctx_list[0].reason = reason;
579 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
580 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
582 if (!dcesrv_auth_bind_ack(call, &pkt)) {
583 return dcesrv_bind_nak(call, 0);
587 status = iface->bind(call, iface);
588 if (!NT_STATUS_IS_OK(status)) {
589 char *uuid_str = GUID_string(call, &uuid);
590 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
591 uuid_str, if_version, nt_errstr(status)));
592 talloc_free(uuid_str);
593 return dcesrv_bind_nak(call, 0);
597 rep = talloc(call, struct data_blob_list_item);
599 return NT_STATUS_NO_MEMORY;
602 status = ncacn_push_auth(&rep->blob, call, &pkt,
603 call->conn->auth_state.auth_info);
604 if (!NT_STATUS_IS_OK(status)) {
608 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
610 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
611 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
618 handle a auth3 request
620 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
622 /* handle the auth3 in the auth code */
623 if (!dcesrv_auth_auth3(call)) {
624 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
629 /* we don't send a reply to a auth3 request, except by a
636 handle a bind request
638 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
640 uint32_t if_version, transfer_syntax_version;
641 struct dcesrv_connection_context *context;
642 const struct dcesrv_interface *iface;
643 struct GUID uuid, *transfer_syntax_uuid;
645 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
646 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
648 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
649 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
650 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
651 ndr_transfer_syntax.if_version != transfer_syntax_version) {
652 /* we only do NDR encoded dcerpc */
653 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
656 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
658 char *uuid_str = GUID_string(call, &uuid);
659 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
660 talloc_free(uuid_str);
661 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
664 /* add this context to the list of available context_ids */
665 context = talloc(call->conn, struct dcesrv_connection_context);
666 if (context == NULL) {
667 return NT_STATUS_NO_MEMORY;
669 context->conn = call->conn;
670 context->iface = iface;
671 context->context_id = context_id;
672 context->private = NULL;
673 context->handles = NULL;
674 DLIST_ADD(call->conn->contexts, context);
675 call->context = context;
682 handle a alter context request
684 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
686 struct ncacn_packet pkt;
687 struct data_blob_list_item *rep;
689 uint32_t result=0, reason=0;
692 /* handle any authentication that is being requested */
693 if (!dcesrv_auth_alter(call)) {
694 /* TODO: work out the right reject code */
695 result = DCERPC_BIND_PROVIDER_REJECT;
696 reason = DCERPC_BIND_REASON_ASYNTAX;
699 context_id = call->pkt.u.alter.ctx_list[0].context_id;
701 /* see if they are asking for a new interface */
703 dcesrv_find_context(call->conn, context_id) == NULL) {
704 status = dcesrv_alter_new_context(call, context_id);
705 if (!NT_STATUS_IS_OK(status)) {
706 result = DCERPC_BIND_PROVIDER_REJECT;
707 reason = DCERPC_BIND_REASON_ASYNTAX;
711 /* setup a alter_resp */
712 dcesrv_init_hdr(&pkt);
714 pkt.call_id = call->pkt.call_id;
715 pkt.ptype = DCERPC_PKT_ALTER_RESP;
716 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
717 pkt.u.alter_resp.max_xmit_frag = 0x2000;
718 pkt.u.alter_resp.max_recv_frag = 0x2000;
719 pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
720 pkt.u.alter_resp.num_results = 1;
721 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
722 if (!pkt.u.alter_resp.ctx_list) {
723 return NT_STATUS_NO_MEMORY;
725 pkt.u.alter_resp.ctx_list[0].result = result;
726 pkt.u.alter_resp.ctx_list[0].reason = reason;
727 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
728 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
729 pkt.u.alter_resp.secondary_address = "";
731 if (!dcesrv_auth_alter_ack(call, &pkt)) {
732 return dcesrv_bind_nak(call, 0);
735 rep = talloc(call, struct data_blob_list_item);
737 return NT_STATUS_NO_MEMORY;
740 status = ncacn_push_auth(&rep->blob, call, &pkt,
741 call->conn->auth_state.auth_info);
742 if (!NT_STATUS_IS_OK(status)) {
746 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
748 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
749 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
755 handle a dcerpc request packet
757 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
759 struct ndr_pull *pull;
761 struct dcesrv_connection_context *context;
763 /* if authenticated, and the mech we use can't do async replies, don't use them... */
764 if (call->conn->auth_state.gensec_security &&
765 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
766 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
769 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
770 if (context == NULL) {
771 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
774 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
775 NT_STATUS_HAVE_NO_MEMORY(pull);
777 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
779 call->context = context;
780 call->ndr_pull = pull;
782 if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
783 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
786 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
787 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
790 /* unravel the NDR for the packet */
791 status = context->iface->ndr_pull(call, call, pull, &call->r);
792 if (!NT_STATUS_IS_OK(status)) {
793 return dcesrv_fault(call, call->fault_code);
796 if (pull->offset != pull->data_size) {
797 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
798 pull->data_size - pull->offset));
799 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
802 /* call the dispatch function */
803 status = context->iface->dispatch(call, call, call->r);
804 if (!NT_STATUS_IS_OK(status)) {
805 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
806 context->iface->name,
807 call->pkt.u.request.opnum,
808 dcerpc_errstr(pull, call->fault_code)));
809 return dcesrv_fault(call, call->fault_code);
812 /* add the call to the pending list */
813 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
815 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
819 return dcesrv_reply(call);
822 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
824 struct ndr_push *push;
827 uint32_t total_length;
828 struct dcesrv_connection_context *context = call->context;
830 /* call the reply function */
831 status = context->iface->reply(call, call, call->r);
832 if (!NT_STATUS_IS_OK(status)) {
833 return dcesrv_fault(call, call->fault_code);
836 /* form the reply NDR */
837 push = ndr_push_init_ctx(call);
838 NT_STATUS_HAVE_NO_MEMORY(push);
840 /* carry over the pointer count to the reply in case we are
841 using full pointer. See NDR specification for full
843 push->ptr_count = call->ndr_pull->ptr_count;
845 if (lp_rpc_big_endian()) {
846 push->flags |= LIBNDR_FLAG_BIGENDIAN;
849 status = context->iface->ndr_push(call, call, push, call->r);
850 if (!NT_STATUS_IS_OK(status)) {
851 return dcesrv_fault(call, call->fault_code);
854 stub = ndr_push_blob(push);
856 total_length = stub.length;
860 struct data_blob_list_item *rep;
861 struct ncacn_packet pkt;
863 rep = talloc(call, struct data_blob_list_item);
864 NT_STATUS_HAVE_NO_MEMORY(rep);
866 length = stub.length;
867 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
868 /* the 32 is to cope with signing data */
869 length = call->conn->cli_max_recv_frag -
870 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
873 /* form the dcerpc response packet */
874 dcesrv_init_hdr(&pkt);
876 pkt.call_id = call->pkt.call_id;
877 pkt.ptype = DCERPC_PKT_RESPONSE;
879 if (stub.length == total_length) {
880 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
882 if (length == stub.length) {
883 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
885 pkt.u.response.alloc_hint = stub.length;
886 pkt.u.response.context_id = call->pkt.u.request.context_id;
887 pkt.u.response.cancel_count = 0;
888 pkt.u.response.stub_and_verifier.data = stub.data;
889 pkt.u.response.stub_and_verifier.length = length;
891 if (!dcesrv_auth_response(call, &rep->blob, &pkt)) {
892 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
895 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
897 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
900 stub.length -= length;
901 } while (stub.length != 0);
903 /* move the call from the pending to the finished calls list */
904 DLIST_REMOVE(call->conn->pending_call_list, call);
905 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
907 if (call->conn->call_list && call->conn->call_list->replies) {
908 if (call->conn->transport.report_output_data) {
909 call->conn->transport.report_output_data(call->conn);
916 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
918 if (!conn->transport.get_my_addr) {
922 return conn->transport.get_my_addr(conn, mem_ctx);
925 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
927 if (!conn->transport.get_peer_addr) {
931 return conn->transport.get_peer_addr(conn, mem_ctx);
935 work out if we have a full packet yet
937 static BOOL dce_full_packet(const DATA_BLOB *data)
939 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
942 if (dcerpc_get_frag_length(data) > data->length) {
949 we might have consumed only part of our input - advance past that part
951 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
955 if (dce_conn->partial_input.length == offset) {
956 data_blob_free(&dce_conn->partial_input);
960 blob = dce_conn->partial_input;
961 dce_conn->partial_input = data_blob(blob.data + offset,
962 blob.length - offset);
963 data_blob_free(&blob);
967 process some input to a dcerpc endpoint server.
969 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
971 struct ndr_pull *ndr;
973 struct dcesrv_call_state *call;
976 call = talloc_zero(dce_conn, struct dcesrv_call_state);
978 talloc_free(dce_conn->partial_input.data);
979 return NT_STATUS_NO_MEMORY;
981 call->conn = dce_conn;
982 call->event_ctx = dce_conn->event_ctx;
983 call->msg_ctx = dce_conn->msg_ctx;
984 call->state_flags = call->conn->state_flags;
985 call->time = timeval_current();
987 blob = dce_conn->partial_input;
988 blob.length = dcerpc_get_frag_length(&blob);
990 ndr = ndr_pull_init_blob(&blob, call);
992 talloc_free(dce_conn->partial_input.data);
994 return NT_STATUS_NO_MEMORY;
997 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
998 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
1001 status = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
1002 if (!NT_STATUS_IS_OK(status)) {
1003 talloc_free(dce_conn->partial_input.data);
1008 /* we have to check the signing here, before combining the
1010 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1011 !dcesrv_auth_request(call, &blob)) {
1012 dce_partial_advance(dce_conn, blob.length);
1013 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1016 dce_partial_advance(dce_conn, blob.length);
1018 /* see if this is a continued packet */
1019 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1020 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1021 struct dcesrv_call_state *call2 = call;
1022 uint32_t alloc_size;
1024 /* we only allow fragmented requests, no other packet types */
1025 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1026 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1029 /* this is a continuation of an existing call - find the call then
1030 tack it on the end */
1031 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1033 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1036 if (call->pkt.ptype != call2->pkt.ptype) {
1037 /* trying to play silly buggers are we? */
1038 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1041 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1042 call2->pkt.u.request.stub_and_verifier.length;
1043 if (call->pkt.u.request.alloc_hint > alloc_size) {
1044 alloc_size = call->pkt.u.request.alloc_hint;
1047 call->pkt.u.request.stub_and_verifier.data =
1048 talloc_realloc(call,
1049 call->pkt.u.request.stub_and_verifier.data,
1050 uint8_t, alloc_size);
1051 if (!call->pkt.u.request.stub_and_verifier.data) {
1052 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1054 memcpy(call->pkt.u.request.stub_and_verifier.data +
1055 call->pkt.u.request.stub_and_verifier.length,
1056 call2->pkt.u.request.stub_and_verifier.data,
1057 call2->pkt.u.request.stub_and_verifier.length);
1058 call->pkt.u.request.stub_and_verifier.length +=
1059 call2->pkt.u.request.stub_and_verifier.length;
1061 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1066 /* this may not be the last pdu in the chain - if its isn't then
1067 just put it on the incoming_fragmented_call_list and wait for the rest */
1068 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1069 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1070 DLIST_ADD_END(dce_conn->incoming_fragmented_call_list, call,
1071 struct dcesrv_call_state *);
1072 return NT_STATUS_OK;
1075 /* This removes any fragments we may have had stashed away */
1076 DLIST_REMOVE(dce_conn->incoming_fragmented_call_list, call);
1078 switch (call->pkt.ptype) {
1079 case DCERPC_PKT_BIND:
1080 status = dcesrv_bind(call);
1082 case DCERPC_PKT_AUTH3:
1083 status = dcesrv_auth3(call);
1085 case DCERPC_PKT_ALTER:
1086 status = dcesrv_alter(call);
1088 case DCERPC_PKT_REQUEST:
1089 status = dcesrv_request(call);
1092 status = NT_STATUS_INVALID_PARAMETER;
1096 /* if we are going to be sending a reply then add
1097 it to the list of pending calls. We add it to the end to keep the call
1098 list in the order we will answer */
1099 if (!NT_STATUS_IS_OK(status)) {
1108 provide some input to a dcerpc endpoint server. This passes data
1109 from a dcerpc client into the server
1111 _PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1115 dce_conn->partial_input.data = talloc_realloc(dce_conn,
1116 dce_conn->partial_input.data,
1118 dce_conn->partial_input.length + data->length);
1119 if (!dce_conn->partial_input.data) {
1120 return NT_STATUS_NO_MEMORY;
1122 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1123 data->data, data->length);
1124 dce_conn->partial_input.length += data->length;
1126 while (dce_full_packet(&dce_conn->partial_input)) {
1127 status = dcesrv_input_process(dce_conn);
1128 if (!NT_STATUS_IS_OK(status)) {
1133 return NT_STATUS_OK;
1137 retrieve some output from a dcerpc server
1138 The caller supplies a function that will be called to do the
1141 The first argument to write_fn() will be 'private', the second will
1142 be a pointer to a buffer containing the data to be sent and the 3rd
1143 will be a pointer to a size_t variable that will be set to the
1144 number of bytes that are consumed from the output.
1146 from the current fragment
1148 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
1150 NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1153 struct dcesrv_call_state *call;
1154 struct data_blob_list_item *rep;
1157 call = dce_conn->call_list;
1158 if (!call || !call->replies) {
1159 if (dce_conn->pending_call_list) {
1160 /* TODO: we need to say act async here
1161 * as we know we have pending requests
1162 * which will be finished at a time
1164 return NT_STATUS_FOOBAR;
1166 return NT_STATUS_FOOBAR;
1168 rep = call->replies;
1170 status = write_fn(private_data, &rep->blob, &nwritten);
1171 NT_STATUS_IS_ERR_RETURN(status);
1173 rep->blob.length -= nwritten;
1174 rep->blob.data += nwritten;
1176 if (rep->blob.length == 0) {
1177 /* we're done with this section of the call */
1178 DLIST_REMOVE(call->replies, rep);
1181 if (call->replies == NULL) {
1182 /* we're done with the whole call */
1183 DLIST_REMOVE(dce_conn->call_list, call);
1190 static NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1193 struct dcesrv_context *dce_ctx;
1196 if (!endpoint_servers) {
1197 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1198 return NT_STATUS_INTERNAL_ERROR;
1201 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1202 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1203 dce_ctx->endpoint_list = NULL;
1205 for (i=0;endpoint_servers[i];i++) {
1206 const struct dcesrv_endpoint_server *ep_server;
1208 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1210 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1211 return NT_STATUS_INTERNAL_ERROR;
1214 status = ep_server->init_server(dce_ctx, ep_server);
1215 if (!NT_STATUS_IS_OK(status)) {
1216 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1217 nt_errstr(status)));
1222 *_dce_ctx = dce_ctx;
1223 return NT_STATUS_OK;
1227 initialise the dcerpc server context for ncacn_np based services
1229 _PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **_dce_ctx)
1232 struct dcesrv_context *dce_ctx;
1234 status = dcesrv_init_context(mem_ctx, lp_dcerpc_endpoint_servers(), &dce_ctx);
1235 NT_STATUS_NOT_OK_RETURN(status);
1237 *_dce_ctx = dce_ctx;
1238 return NT_STATUS_OK;
1241 /* the list of currently registered DCERPC endpoint servers.
1243 static struct ep_server {
1244 struct dcesrv_endpoint_server *ep_server;
1245 } *ep_servers = NULL;
1246 static int num_ep_servers;
1249 register a DCERPC endpoint server.
1251 The 'name' can be later used by other backends to find the operations
1252 structure for this backend.
1254 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1256 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1258 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1260 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1261 /* its already registered! */
1262 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1264 return NT_STATUS_OBJECT_NAME_COLLISION;
1267 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1269 smb_panic("out of memory in dcerpc_register");
1272 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1273 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1277 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1280 return NT_STATUS_OK;
1284 return the operations structure for a named backend of the specified type
1286 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1290 for (i=0;i<num_ep_servers;i++) {
1291 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1292 return ep_servers[i].ep_server;
1300 return the DCERPC module version, and the size of some critical types
1301 This can be used by endpoint server modules to either detect compilation errors, or provide
1302 multiple implementations for different smbd compilation options in one module
1304 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1306 static const struct dcesrv_critical_sizes critical_sizes = {
1307 DCERPC_MODULE_VERSION,
1308 sizeof(struct dcesrv_context),
1309 sizeof(struct dcesrv_endpoint),
1310 sizeof(struct dcesrv_endpoint_server),
1311 sizeof(struct dcesrv_interface),
1312 sizeof(struct dcesrv_if_list),
1313 sizeof(struct dcesrv_connection),
1314 sizeof(struct dcesrv_call_state),
1315 sizeof(struct dcesrv_auth),
1316 sizeof(struct dcesrv_handle)
1319 return &critical_sizes;
1323 open the dcerpc server sockets
1325 static void dcesrv_task_init(struct task_server *task)
1328 struct dcesrv_context *dce_ctx;
1329 struct dcesrv_endpoint *e;
1331 task_server_set_title(task, "task[dcesrv]");
1333 status = dcesrv_init_context(task->event_ctx,
1334 lp_dcerpc_endpoint_servers(),
1336 if (!NT_STATUS_IS_OK(status)) goto failed;
1338 /* Make sure the directory for NCALRPC exists */
1339 if (!directory_exist(lp_ncalrpc_dir())) {
1340 mkdir(lp_ncalrpc_dir(), 0755);
1343 for (e=dce_ctx->endpoint_list;e;e=e->next) {
1344 switch (e->ep_description->transport) {
1345 case NCACN_UNIX_STREAM:
1346 status = dcesrv_add_ep_unix(dce_ctx, e, task->event_ctx, task->model_ops);
1347 if (!NT_STATUS_IS_OK(status)) goto failed;
1351 status = dcesrv_add_ep_ncalrpc(dce_ctx, e, task->event_ctx, task->model_ops);
1352 if (!NT_STATUS_IS_OK(status)) goto failed;
1356 status = dcesrv_add_ep_tcp(dce_ctx, e, task->event_ctx, task->model_ops);
1357 if (!NT_STATUS_IS_OK(status)) goto failed;
1361 /* FIXME: status = dcesrv_add_ep_np(dce_ctx, e, task->event_ctx, task->model_ops);
1362 if (!NT_STATUS_IS_OK(status)) goto failed;
1366 status = NT_STATUS_NOT_SUPPORTED;
1367 if (!NT_STATUS_IS_OK(status)) goto failed;
1373 task_server_terminate(task, "Failed to startup dcerpc server task");
1377 called on startup of the smb server service It's job is to start
1378 listening on all configured sockets
1380 static NTSTATUS dcesrv_init(struct event_context *event_context,
1381 const struct model_ops *model_ops)
1383 return task_server_startup(event_context, model_ops, dcesrv_task_init);
1386 NTSTATUS server_service_rpc_init(void)
1388 init_module_fn static_init[] = STATIC_dcerpc_server_MODULES;
1389 init_module_fn *shared_init = load_samba_modules(NULL, "dcerpc_server");
1391 run_init_functions(static_init);
1392 run_init_functions(shared_init);
1394 talloc_free(shared_init);
1396 return register_server_service("rpc", dcesrv_init);