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 move a call from an existing linked list to the specified list. This
405 prevents bugs where we forget to remove the call from a previous
408 static void dcesrv_call_set_list(struct dcesrv_call_state *call,
409 enum dcesrv_call_list list)
411 switch (call->list) {
412 case DCESRV_LIST_NONE:
414 case DCESRV_LIST_CALL_LIST:
415 DLIST_REMOVE(call->conn->call_list, call);
417 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
418 DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
420 case DCESRV_LIST_PENDING_CALL_LIST:
421 DLIST_REMOVE(call->conn->pending_call_list, call);
426 case DCESRV_LIST_NONE:
428 case DCESRV_LIST_CALL_LIST:
429 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
431 case DCESRV_LIST_FRAGMENTED_CALL_LIST:
432 DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
434 case DCESRV_LIST_PENDING_CALL_LIST:
435 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
441 return a dcerpc fault
443 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
445 struct ncacn_packet pkt;
446 struct data_blob_list_item *rep;
449 /* setup a bind_ack */
450 dcesrv_init_hdr(&pkt);
452 pkt.call_id = call->pkt.call_id;
453 pkt.ptype = DCERPC_PKT_FAULT;
454 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
455 pkt.u.fault.alloc_hint = 0;
456 pkt.u.fault.context_id = 0;
457 pkt.u.fault.cancel_count = 0;
458 pkt.u.fault.status = fault_code;
460 rep = talloc(call, struct data_blob_list_item);
462 return NT_STATUS_NO_MEMORY;
465 status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
466 if (!NT_STATUS_IS_OK(status)) {
470 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
472 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
473 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
480 return a dcerpc bind_nak
482 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
484 struct ncacn_packet pkt;
485 struct data_blob_list_item *rep;
488 /* setup a bind_nak */
489 dcesrv_init_hdr(&pkt);
491 pkt.call_id = call->pkt.call_id;
492 pkt.ptype = DCERPC_PKT_BIND_NAK;
493 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
494 pkt.u.bind_nak.reject_reason = reason;
495 if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
496 pkt.u.bind_nak.versions.v.num_versions = 0;
499 rep = talloc(call, struct data_blob_list_item);
501 return NT_STATUS_NO_MEMORY;
504 status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
505 if (!NT_STATUS_IS_OK(status)) {
509 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
511 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
512 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
519 handle a bind request
521 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
523 uint32_t if_version, transfer_syntax_version;
524 struct GUID uuid, *transfer_syntax_uuid;
525 struct ncacn_packet pkt;
526 struct data_blob_list_item *rep;
528 uint32_t result=0, reason=0;
530 const struct dcesrv_interface *iface;
532 if (call->pkt.u.bind.assoc_group_id != 0) {
533 return dcesrv_bind_nak(call, 0);
536 if (call->pkt.u.bind.num_contexts < 1 ||
537 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
538 return dcesrv_bind_nak(call, 0);
541 context_id = call->pkt.u.bind.ctx_list[0].context_id;
543 /* you can't bind twice on one context */
544 if (dcesrv_find_context(call->conn, context_id) != NULL) {
545 return dcesrv_bind_nak(call, 0);
548 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
549 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
551 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
552 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
553 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
554 ndr_transfer_syntax.if_version != transfer_syntax_version) {
555 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
556 /* we only do NDR encoded dcerpc */
557 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
558 talloc_free(uuid_str);
559 return dcesrv_bind_nak(call, 0);
562 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
564 char *uuid_str = GUID_string(call, &uuid);
565 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
566 talloc_free(uuid_str);
568 /* we don't know about that interface */
569 result = DCERPC_BIND_PROVIDER_REJECT;
570 reason = DCERPC_BIND_REASON_ASYNTAX;
574 /* add this context to the list of available context_ids */
575 struct dcesrv_connection_context *context = talloc(call->conn,
576 struct dcesrv_connection_context);
577 if (context == NULL) {
578 return dcesrv_bind_nak(call, 0);
580 context->conn = call->conn;
581 context->iface = iface;
582 context->context_id = context_id;
583 context->private = NULL;
584 context->handles = NULL;
585 DLIST_ADD(call->conn->contexts, context);
586 call->context = context;
589 if (call->conn->cli_max_recv_frag == 0) {
590 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
593 /* handle any authentication that is being requested */
594 if (!dcesrv_auth_bind(call)) {
595 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
598 /* setup a bind_ack */
599 dcesrv_init_hdr(&pkt);
601 pkt.call_id = call->pkt.call_id;
602 pkt.ptype = DCERPC_PKT_BIND_ACK;
603 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
604 pkt.u.bind_ack.max_xmit_frag = 0x2000;
605 pkt.u.bind_ack.max_recv_frag = 0x2000;
606 pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
608 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
609 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
611 pkt.u.bind_ack.secondary_address = "";
613 pkt.u.bind_ack.num_results = 1;
614 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
615 if (!pkt.u.bind_ack.ctx_list) {
616 return NT_STATUS_NO_MEMORY;
618 pkt.u.bind_ack.ctx_list[0].result = result;
619 pkt.u.bind_ack.ctx_list[0].reason = reason;
620 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
621 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
623 if (!dcesrv_auth_bind_ack(call, &pkt)) {
624 return dcesrv_bind_nak(call, 0);
628 status = iface->bind(call, iface);
629 if (!NT_STATUS_IS_OK(status)) {
630 char *uuid_str = GUID_string(call, &uuid);
631 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
632 uuid_str, if_version, nt_errstr(status)));
633 talloc_free(uuid_str);
634 return dcesrv_bind_nak(call, 0);
638 rep = talloc(call, struct data_blob_list_item);
640 return NT_STATUS_NO_MEMORY;
643 status = ncacn_push_auth(&rep->blob, call, &pkt,
644 call->conn->auth_state.auth_info);
645 if (!NT_STATUS_IS_OK(status)) {
649 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
651 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
652 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
659 handle a auth3 request
661 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
663 /* handle the auth3 in the auth code */
664 if (!dcesrv_auth_auth3(call)) {
665 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
670 /* we don't send a reply to a auth3 request, except by a
677 handle a bind request
679 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
681 uint32_t if_version, transfer_syntax_version;
682 struct dcesrv_connection_context *context;
683 const struct dcesrv_interface *iface;
684 struct GUID uuid, *transfer_syntax_uuid;
686 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
687 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
689 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
690 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
691 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
692 ndr_transfer_syntax.if_version != transfer_syntax_version) {
693 /* we only do NDR encoded dcerpc */
694 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
697 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
699 char *uuid_str = GUID_string(call, &uuid);
700 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
701 talloc_free(uuid_str);
702 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
705 /* add this context to the list of available context_ids */
706 context = talloc(call->conn, struct dcesrv_connection_context);
707 if (context == NULL) {
708 return NT_STATUS_NO_MEMORY;
710 context->conn = call->conn;
711 context->iface = iface;
712 context->context_id = context_id;
713 context->private = NULL;
714 context->handles = NULL;
715 DLIST_ADD(call->conn->contexts, context);
716 call->context = context;
723 handle a alter context request
725 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
727 struct ncacn_packet pkt;
728 struct data_blob_list_item *rep;
730 uint32_t result=0, reason=0;
733 /* handle any authentication that is being requested */
734 if (!dcesrv_auth_alter(call)) {
735 /* TODO: work out the right reject code */
736 result = DCERPC_BIND_PROVIDER_REJECT;
737 reason = DCERPC_BIND_REASON_ASYNTAX;
740 context_id = call->pkt.u.alter.ctx_list[0].context_id;
742 /* see if they are asking for a new interface */
744 dcesrv_find_context(call->conn, context_id) == NULL) {
745 status = dcesrv_alter_new_context(call, context_id);
746 if (!NT_STATUS_IS_OK(status)) {
747 result = DCERPC_BIND_PROVIDER_REJECT;
748 reason = DCERPC_BIND_REASON_ASYNTAX;
752 /* setup a alter_resp */
753 dcesrv_init_hdr(&pkt);
755 pkt.call_id = call->pkt.call_id;
756 pkt.ptype = DCERPC_PKT_ALTER_RESP;
757 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
758 pkt.u.alter_resp.max_xmit_frag = 0x2000;
759 pkt.u.alter_resp.max_recv_frag = 0x2000;
760 pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
761 pkt.u.alter_resp.num_results = 1;
762 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
763 if (!pkt.u.alter_resp.ctx_list) {
764 return NT_STATUS_NO_MEMORY;
766 pkt.u.alter_resp.ctx_list[0].result = result;
767 pkt.u.alter_resp.ctx_list[0].reason = reason;
768 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
769 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
770 pkt.u.alter_resp.secondary_address = "";
772 if (!dcesrv_auth_alter_ack(call, &pkt)) {
773 return dcesrv_bind_nak(call, 0);
776 rep = talloc(call, struct data_blob_list_item);
778 return NT_STATUS_NO_MEMORY;
781 status = ncacn_push_auth(&rep->blob, call, &pkt,
782 call->conn->auth_state.auth_info);
783 if (!NT_STATUS_IS_OK(status)) {
787 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
789 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
790 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
796 handle a dcerpc request packet
798 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
800 struct ndr_pull *pull;
802 struct dcesrv_connection_context *context;
804 /* if authenticated, and the mech we use can't do async replies, don't use them... */
805 if (call->conn->auth_state.gensec_security &&
806 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
807 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
810 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
811 if (context == NULL) {
812 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
815 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
816 NT_STATUS_HAVE_NO_MEMORY(pull);
818 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
820 call->context = context;
821 call->ndr_pull = pull;
823 if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
824 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
827 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
828 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
831 /* unravel the NDR for the packet */
832 status = context->iface->ndr_pull(call, call, pull, &call->r);
833 if (!NT_STATUS_IS_OK(status)) {
834 return dcesrv_fault(call, call->fault_code);
837 if (pull->offset != pull->data_size) {
838 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
839 pull->data_size - pull->offset));
840 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
843 /* call the dispatch function */
844 status = context->iface->dispatch(call, call, call->r);
845 if (!NT_STATUS_IS_OK(status)) {
846 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
847 context->iface->name,
848 call->pkt.u.request.opnum,
849 dcerpc_errstr(pull, call->fault_code)));
850 return dcesrv_fault(call, call->fault_code);
853 /* add the call to the pending list */
854 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
856 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
860 return dcesrv_reply(call);
863 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
865 struct ndr_push *push;
868 uint32_t total_length;
869 struct dcesrv_connection_context *context = call->context;
871 /* call the reply function */
872 status = context->iface->reply(call, call, call->r);
873 if (!NT_STATUS_IS_OK(status)) {
874 return dcesrv_fault(call, call->fault_code);
877 /* form the reply NDR */
878 push = ndr_push_init_ctx(call);
879 NT_STATUS_HAVE_NO_MEMORY(push);
881 /* carry over the pointer count to the reply in case we are
882 using full pointer. See NDR specification for full
884 push->ptr_count = call->ndr_pull->ptr_count;
886 if (lp_rpc_big_endian()) {
887 push->flags |= LIBNDR_FLAG_BIGENDIAN;
890 status = context->iface->ndr_push(call, call, push, call->r);
891 if (!NT_STATUS_IS_OK(status)) {
892 return dcesrv_fault(call, call->fault_code);
895 stub = ndr_push_blob(push);
897 total_length = stub.length;
901 struct data_blob_list_item *rep;
902 struct ncacn_packet pkt;
904 rep = talloc(call, struct data_blob_list_item);
905 NT_STATUS_HAVE_NO_MEMORY(rep);
907 length = stub.length;
908 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
909 /* the 32 is to cope with signing data */
910 length = call->conn->cli_max_recv_frag -
911 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
914 /* form the dcerpc response packet */
915 dcesrv_init_hdr(&pkt);
917 pkt.call_id = call->pkt.call_id;
918 pkt.ptype = DCERPC_PKT_RESPONSE;
920 if (stub.length == total_length) {
921 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
923 if (length == stub.length) {
924 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
926 pkt.u.response.alloc_hint = stub.length;
927 pkt.u.response.context_id = call->pkt.u.request.context_id;
928 pkt.u.response.cancel_count = 0;
929 pkt.u.response.stub_and_verifier.data = stub.data;
930 pkt.u.response.stub_and_verifier.length = length;
932 if (!dcesrv_auth_response(call, &rep->blob, &pkt)) {
933 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
936 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
938 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
941 stub.length -= length;
942 } while (stub.length != 0);
944 /* move the call from the pending to the finished calls list */
945 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
947 if (call->conn->call_list && call->conn->call_list->replies) {
948 if (call->conn->transport.report_output_data) {
949 call->conn->transport.report_output_data(call->conn);
956 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
958 if (!conn->transport.get_my_addr) {
962 return conn->transport.get_my_addr(conn, mem_ctx);
965 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
967 if (!conn->transport.get_peer_addr) {
971 return conn->transport.get_peer_addr(conn, mem_ctx);
975 work out if we have a full packet yet
977 static BOOL dce_full_packet(const DATA_BLOB *data)
979 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
982 if (dcerpc_get_frag_length(data) > data->length) {
989 we might have consumed only part of our input - advance past that part
991 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
995 if (dce_conn->partial_input.length == offset) {
996 data_blob_free(&dce_conn->partial_input);
1000 blob = dce_conn->partial_input;
1001 dce_conn->partial_input = data_blob(blob.data + offset,
1002 blob.length - offset);
1003 data_blob_free(&blob);
1007 remove the call from the right list when freed
1009 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1011 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1016 process some input to a dcerpc endpoint server.
1018 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
1020 struct ndr_pull *ndr;
1022 struct dcesrv_call_state *call;
1025 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1027 talloc_free(dce_conn->partial_input.data);
1028 return NT_STATUS_NO_MEMORY;
1030 call->conn = dce_conn;
1031 call->event_ctx = dce_conn->event_ctx;
1032 call->msg_ctx = dce_conn->msg_ctx;
1033 call->state_flags = call->conn->state_flags;
1034 call->time = timeval_current();
1035 call->list = DCESRV_LIST_NONE;
1037 talloc_set_destructor(call, dcesrv_call_dequeue);
1039 blob = dce_conn->partial_input;
1040 blob.length = dcerpc_get_frag_length(&blob);
1042 ndr = ndr_pull_init_blob(&blob, call);
1044 talloc_free(dce_conn->partial_input.data);
1046 return NT_STATUS_NO_MEMORY;
1049 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
1050 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
1053 status = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
1054 if (!NT_STATUS_IS_OK(status)) {
1055 talloc_free(dce_conn->partial_input.data);
1060 /* we have to check the signing here, before combining the
1062 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1063 !dcesrv_auth_request(call, &blob)) {
1064 dce_partial_advance(dce_conn, blob.length);
1065 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1068 dce_partial_advance(dce_conn, blob.length);
1070 /* see if this is a continued packet */
1071 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1072 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1073 struct dcesrv_call_state *call2 = call;
1074 uint32_t alloc_size;
1076 /* we only allow fragmented requests, no other packet types */
1077 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1078 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1081 /* this is a continuation of an existing call - find the call then
1082 tack it on the end */
1083 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1085 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1088 if (call->pkt.ptype != call2->pkt.ptype) {
1089 /* trying to play silly buggers are we? */
1090 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1093 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1094 call2->pkt.u.request.stub_and_verifier.length;
1095 if (call->pkt.u.request.alloc_hint > alloc_size) {
1096 alloc_size = call->pkt.u.request.alloc_hint;
1099 call->pkt.u.request.stub_and_verifier.data =
1100 talloc_realloc(call,
1101 call->pkt.u.request.stub_and_verifier.data,
1102 uint8_t, alloc_size);
1103 if (!call->pkt.u.request.stub_and_verifier.data) {
1104 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1106 memcpy(call->pkt.u.request.stub_and_verifier.data +
1107 call->pkt.u.request.stub_and_verifier.length,
1108 call2->pkt.u.request.stub_and_verifier.data,
1109 call2->pkt.u.request.stub_and_verifier.length);
1110 call->pkt.u.request.stub_and_verifier.length +=
1111 call2->pkt.u.request.stub_and_verifier.length;
1113 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1118 /* this may not be the last pdu in the chain - if its isn't then
1119 just put it on the incoming_fragmented_call_list and wait for the rest */
1120 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1121 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1122 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1123 return NT_STATUS_OK;
1126 /* This removes any fragments we may have had stashed away */
1127 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1129 switch (call->pkt.ptype) {
1130 case DCERPC_PKT_BIND:
1131 status = dcesrv_bind(call);
1133 case DCERPC_PKT_AUTH3:
1134 status = dcesrv_auth3(call);
1136 case DCERPC_PKT_ALTER:
1137 status = dcesrv_alter(call);
1139 case DCERPC_PKT_REQUEST:
1140 status = dcesrv_request(call);
1143 status = NT_STATUS_INVALID_PARAMETER;
1147 /* if we are going to be sending a reply then add
1148 it to the list of pending calls. We add it to the end to keep the call
1149 list in the order we will answer */
1150 if (!NT_STATUS_IS_OK(status)) {
1159 provide some input to a dcerpc endpoint server. This passes data
1160 from a dcerpc client into the server
1162 _PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1166 dce_conn->partial_input.data = talloc_realloc(dce_conn,
1167 dce_conn->partial_input.data,
1169 dce_conn->partial_input.length + data->length);
1170 if (!dce_conn->partial_input.data) {
1171 return NT_STATUS_NO_MEMORY;
1173 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1174 data->data, data->length);
1175 dce_conn->partial_input.length += data->length;
1177 while (dce_full_packet(&dce_conn->partial_input)) {
1178 status = dcesrv_input_process(dce_conn);
1179 if (!NT_STATUS_IS_OK(status)) {
1184 return NT_STATUS_OK;
1188 retrieve some output from a dcerpc server
1189 The caller supplies a function that will be called to do the
1192 The first argument to write_fn() will be 'private', the second will
1193 be a pointer to a buffer containing the data to be sent and the 3rd
1194 will be a pointer to a size_t variable that will be set to the
1195 number of bytes that are consumed from the output.
1197 from the current fragment
1199 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
1201 NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1204 struct dcesrv_call_state *call;
1205 struct data_blob_list_item *rep;
1208 call = dce_conn->call_list;
1209 if (!call || !call->replies) {
1210 if (dce_conn->pending_call_list) {
1211 /* TODO: we need to say act async here
1212 * as we know we have pending requests
1213 * which will be finished at a time
1215 return NT_STATUS_FOOBAR;
1217 return NT_STATUS_FOOBAR;
1219 rep = call->replies;
1221 status = write_fn(private_data, &rep->blob, &nwritten);
1222 NT_STATUS_IS_ERR_RETURN(status);
1224 rep->blob.length -= nwritten;
1225 rep->blob.data += nwritten;
1227 if (rep->blob.length == 0) {
1228 /* we're done with this section of the call */
1229 DLIST_REMOVE(call->replies, rep);
1232 if (call->replies == NULL) {
1233 /* we're done with the whole call */
1234 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1241 static NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1244 struct dcesrv_context *dce_ctx;
1247 if (!endpoint_servers) {
1248 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1249 return NT_STATUS_INTERNAL_ERROR;
1252 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1253 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1254 dce_ctx->endpoint_list = NULL;
1256 for (i=0;endpoint_servers[i];i++) {
1257 const struct dcesrv_endpoint_server *ep_server;
1259 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1261 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1262 return NT_STATUS_INTERNAL_ERROR;
1265 status = ep_server->init_server(dce_ctx, ep_server);
1266 if (!NT_STATUS_IS_OK(status)) {
1267 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1268 nt_errstr(status)));
1273 *_dce_ctx = dce_ctx;
1274 return NT_STATUS_OK;
1278 initialise the dcerpc server context for ncacn_np based services
1280 _PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **_dce_ctx)
1283 struct dcesrv_context *dce_ctx;
1285 status = dcesrv_init_context(mem_ctx, lp_dcerpc_endpoint_servers(), &dce_ctx);
1286 NT_STATUS_NOT_OK_RETURN(status);
1288 *_dce_ctx = dce_ctx;
1289 return NT_STATUS_OK;
1292 /* the list of currently registered DCERPC endpoint servers.
1294 static struct ep_server {
1295 struct dcesrv_endpoint_server *ep_server;
1296 } *ep_servers = NULL;
1297 static int num_ep_servers;
1300 register a DCERPC endpoint server.
1302 The 'name' can be later used by other backends to find the operations
1303 structure for this backend.
1305 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1307 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1309 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1311 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1312 /* its already registered! */
1313 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1315 return NT_STATUS_OBJECT_NAME_COLLISION;
1318 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1320 smb_panic("out of memory in dcerpc_register");
1323 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1324 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1328 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1331 return NT_STATUS_OK;
1335 return the operations structure for a named backend of the specified type
1337 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1341 for (i=0;i<num_ep_servers;i++) {
1342 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1343 return ep_servers[i].ep_server;
1351 return the DCERPC module version, and the size of some critical types
1352 This can be used by endpoint server modules to either detect compilation errors, or provide
1353 multiple implementations for different smbd compilation options in one module
1355 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1357 static const struct dcesrv_critical_sizes critical_sizes = {
1358 DCERPC_MODULE_VERSION,
1359 sizeof(struct dcesrv_context),
1360 sizeof(struct dcesrv_endpoint),
1361 sizeof(struct dcesrv_endpoint_server),
1362 sizeof(struct dcesrv_interface),
1363 sizeof(struct dcesrv_if_list),
1364 sizeof(struct dcesrv_connection),
1365 sizeof(struct dcesrv_call_state),
1366 sizeof(struct dcesrv_auth),
1367 sizeof(struct dcesrv_handle)
1370 return &critical_sizes;
1374 open the dcerpc server sockets
1376 static void dcesrv_task_init(struct task_server *task)
1379 struct dcesrv_context *dce_ctx;
1380 struct dcesrv_endpoint *e;
1382 task_server_set_title(task, "task[dcesrv]");
1384 status = dcesrv_init_context(task->event_ctx,
1385 lp_dcerpc_endpoint_servers(),
1387 if (!NT_STATUS_IS_OK(status)) goto failed;
1389 /* Make sure the directory for NCALRPC exists */
1390 if (!directory_exist(lp_ncalrpc_dir())) {
1391 mkdir(lp_ncalrpc_dir(), 0755);
1394 for (e=dce_ctx->endpoint_list;e;e=e->next) {
1395 switch (e->ep_description->transport) {
1396 case NCACN_UNIX_STREAM:
1397 status = dcesrv_add_ep_unix(dce_ctx, e, task->event_ctx, task->model_ops);
1398 if (!NT_STATUS_IS_OK(status)) goto failed;
1402 status = dcesrv_add_ep_ncalrpc(dce_ctx, e, task->event_ctx, task->model_ops);
1403 if (!NT_STATUS_IS_OK(status)) goto failed;
1407 status = dcesrv_add_ep_tcp(dce_ctx, e, task->event_ctx, task->model_ops);
1408 if (!NT_STATUS_IS_OK(status)) goto failed;
1412 /* FIXME: status = dcesrv_add_ep_np(dce_ctx, e, task->event_ctx, task->model_ops);
1413 if (!NT_STATUS_IS_OK(status)) goto failed;
1417 status = NT_STATUS_NOT_SUPPORTED;
1418 if (!NT_STATUS_IS_OK(status)) goto failed;
1424 task_server_terminate(task, "Failed to startup dcerpc server task");
1428 called on startup of the smb server service It's job is to start
1429 listening on all configured sockets
1431 static NTSTATUS dcesrv_init(struct event_context *event_context,
1432 const struct model_ops *model_ops)
1434 return task_server_startup(event_context, model_ops, dcesrv_task_init);
1437 NTSTATUS server_service_rpc_init(void)
1439 init_module_fn static_init[] = STATIC_dcerpc_server_MODULES;
1440 init_module_fn *shared_init = load_samba_modules(NULL, "dcerpc_server");
1442 run_init_functions(static_init);
1443 run_init_functions(shared_init);
1445 talloc_free(shared_init);
1447 return register_server_service("rpc", dcesrv_init);