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 /* we need to send a non zero assoc_group_id here to make longhorn happy, it also matches samba3 */
607 pkt.u.bind_ack.assoc_group_id = 0x12345678;
609 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
610 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
612 pkt.u.bind_ack.secondary_address = "";
614 pkt.u.bind_ack.num_results = 1;
615 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
616 if (!pkt.u.bind_ack.ctx_list) {
617 return NT_STATUS_NO_MEMORY;
619 pkt.u.bind_ack.ctx_list[0].result = result;
620 pkt.u.bind_ack.ctx_list[0].reason = reason;
621 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
622 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
624 if (!dcesrv_auth_bind_ack(call, &pkt)) {
625 return dcesrv_bind_nak(call, 0);
629 status = iface->bind(call, iface);
630 if (!NT_STATUS_IS_OK(status)) {
631 char *uuid_str = GUID_string(call, &uuid);
632 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
633 uuid_str, if_version, nt_errstr(status)));
634 talloc_free(uuid_str);
635 return dcesrv_bind_nak(call, 0);
639 rep = talloc(call, struct data_blob_list_item);
641 return NT_STATUS_NO_MEMORY;
644 status = ncacn_push_auth(&rep->blob, call, &pkt,
645 call->conn->auth_state.auth_info);
646 if (!NT_STATUS_IS_OK(status)) {
650 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
652 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
653 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
660 handle a auth3 request
662 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
664 /* handle the auth3 in the auth code */
665 if (!dcesrv_auth_auth3(call)) {
666 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
671 /* we don't send a reply to a auth3 request, except by a
678 handle a bind request
680 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
682 uint32_t if_version, transfer_syntax_version;
683 struct dcesrv_connection_context *context;
684 const struct dcesrv_interface *iface;
685 struct GUID uuid, *transfer_syntax_uuid;
687 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
688 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
690 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
691 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
692 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
693 ndr_transfer_syntax.if_version != transfer_syntax_version) {
694 /* we only do NDR encoded dcerpc */
695 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
698 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
700 char *uuid_str = GUID_string(call, &uuid);
701 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
702 talloc_free(uuid_str);
703 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
706 /* add this context to the list of available context_ids */
707 context = talloc(call->conn, struct dcesrv_connection_context);
708 if (context == NULL) {
709 return NT_STATUS_NO_MEMORY;
711 context->conn = call->conn;
712 context->iface = iface;
713 context->context_id = context_id;
714 context->private = NULL;
715 context->handles = NULL;
716 DLIST_ADD(call->conn->contexts, context);
717 call->context = context;
724 handle a alter context request
726 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
728 struct ncacn_packet pkt;
729 struct data_blob_list_item *rep;
731 uint32_t result=0, reason=0;
734 /* handle any authentication that is being requested */
735 if (!dcesrv_auth_alter(call)) {
736 /* TODO: work out the right reject code */
737 result = DCERPC_BIND_PROVIDER_REJECT;
738 reason = DCERPC_BIND_REASON_ASYNTAX;
741 context_id = call->pkt.u.alter.ctx_list[0].context_id;
743 /* see if they are asking for a new interface */
745 dcesrv_find_context(call->conn, context_id) == NULL) {
746 status = dcesrv_alter_new_context(call, context_id);
747 if (!NT_STATUS_IS_OK(status)) {
748 result = DCERPC_BIND_PROVIDER_REJECT;
749 reason = DCERPC_BIND_REASON_ASYNTAX;
753 /* setup a alter_resp */
754 dcesrv_init_hdr(&pkt);
756 pkt.call_id = call->pkt.call_id;
757 pkt.ptype = DCERPC_PKT_ALTER_RESP;
758 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
759 pkt.u.alter_resp.max_xmit_frag = 0x2000;
760 pkt.u.alter_resp.max_recv_frag = 0x2000;
761 pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
762 pkt.u.alter_resp.num_results = 1;
763 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
764 if (!pkt.u.alter_resp.ctx_list) {
765 return NT_STATUS_NO_MEMORY;
767 pkt.u.alter_resp.ctx_list[0].result = result;
768 pkt.u.alter_resp.ctx_list[0].reason = reason;
769 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
770 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
771 pkt.u.alter_resp.secondary_address = "";
773 if (!dcesrv_auth_alter_ack(call, &pkt)) {
774 return dcesrv_bind_nak(call, 0);
777 rep = talloc(call, struct data_blob_list_item);
779 return NT_STATUS_NO_MEMORY;
782 status = ncacn_push_auth(&rep->blob, call, &pkt,
783 call->conn->auth_state.auth_info);
784 if (!NT_STATUS_IS_OK(status)) {
788 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
790 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
791 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
797 handle a dcerpc request packet
799 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
801 struct ndr_pull *pull;
803 struct dcesrv_connection_context *context;
805 /* if authenticated, and the mech we use can't do async replies, don't use them... */
806 if (call->conn->auth_state.gensec_security &&
807 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
808 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
811 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
812 if (context == NULL) {
813 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
816 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
817 NT_STATUS_HAVE_NO_MEMORY(pull);
819 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
821 call->context = context;
822 call->ndr_pull = pull;
824 if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
825 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
828 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
829 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
832 /* unravel the NDR for the packet */
833 status = context->iface->ndr_pull(call, call, pull, &call->r);
834 if (!NT_STATUS_IS_OK(status)) {
835 return dcesrv_fault(call, call->fault_code);
838 if (pull->offset != pull->data_size) {
839 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
840 pull->data_size - pull->offset));
841 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
844 /* call the dispatch function */
845 status = context->iface->dispatch(call, call, call->r);
846 if (!NT_STATUS_IS_OK(status)) {
847 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
848 context->iface->name,
849 call->pkt.u.request.opnum,
850 dcerpc_errstr(pull, call->fault_code)));
851 return dcesrv_fault(call, call->fault_code);
854 /* add the call to the pending list */
855 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
857 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
861 return dcesrv_reply(call);
864 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
866 struct ndr_push *push;
869 uint32_t total_length;
870 struct dcesrv_connection_context *context = call->context;
872 /* call the reply function */
873 status = context->iface->reply(call, call, call->r);
874 if (!NT_STATUS_IS_OK(status)) {
875 return dcesrv_fault(call, call->fault_code);
878 /* form the reply NDR */
879 push = ndr_push_init_ctx(call);
880 NT_STATUS_HAVE_NO_MEMORY(push);
882 /* carry over the pointer count to the reply in case we are
883 using full pointer. See NDR specification for full
885 push->ptr_count = call->ndr_pull->ptr_count;
887 if (lp_rpc_big_endian()) {
888 push->flags |= LIBNDR_FLAG_BIGENDIAN;
891 status = context->iface->ndr_push(call, call, push, call->r);
892 if (!NT_STATUS_IS_OK(status)) {
893 return dcesrv_fault(call, call->fault_code);
896 stub = ndr_push_blob(push);
898 total_length = stub.length;
902 struct data_blob_list_item *rep;
903 struct ncacn_packet pkt;
905 rep = talloc(call, struct data_blob_list_item);
906 NT_STATUS_HAVE_NO_MEMORY(rep);
908 length = stub.length;
909 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
910 /* the 32 is to cope with signing data */
911 length = call->conn->cli_max_recv_frag -
912 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
915 /* form the dcerpc response packet */
916 dcesrv_init_hdr(&pkt);
918 pkt.call_id = call->pkt.call_id;
919 pkt.ptype = DCERPC_PKT_RESPONSE;
921 if (stub.length == total_length) {
922 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
924 if (length == stub.length) {
925 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
927 pkt.u.response.alloc_hint = stub.length;
928 pkt.u.response.context_id = call->pkt.u.request.context_id;
929 pkt.u.response.cancel_count = 0;
930 pkt.u.response.stub_and_verifier.data = stub.data;
931 pkt.u.response.stub_and_verifier.length = length;
933 if (!dcesrv_auth_response(call, &rep->blob, &pkt)) {
934 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
937 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
939 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
942 stub.length -= length;
943 } while (stub.length != 0);
945 /* move the call from the pending to the finished calls list */
946 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
948 if (call->conn->call_list && call->conn->call_list->replies) {
949 if (call->conn->transport.report_output_data) {
950 call->conn->transport.report_output_data(call->conn);
957 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
959 if (!conn->transport.get_my_addr) {
963 return conn->transport.get_my_addr(conn, mem_ctx);
966 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
968 if (!conn->transport.get_peer_addr) {
972 return conn->transport.get_peer_addr(conn, mem_ctx);
976 work out if we have a full packet yet
978 static BOOL dce_full_packet(const DATA_BLOB *data)
980 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
983 if (dcerpc_get_frag_length(data) > data->length) {
990 we might have consumed only part of our input - advance past that part
992 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
996 if (dce_conn->partial_input.length == offset) {
997 data_blob_free(&dce_conn->partial_input);
1001 blob = dce_conn->partial_input;
1002 dce_conn->partial_input = data_blob(blob.data + offset,
1003 blob.length - offset);
1004 data_blob_free(&blob);
1008 remove the call from the right list when freed
1010 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
1012 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1017 process some input to a dcerpc endpoint server.
1019 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
1021 struct ndr_pull *ndr;
1023 struct dcesrv_call_state *call;
1026 call = talloc_zero(dce_conn, struct dcesrv_call_state);
1028 talloc_free(dce_conn->partial_input.data);
1029 return NT_STATUS_NO_MEMORY;
1031 call->conn = dce_conn;
1032 call->event_ctx = dce_conn->event_ctx;
1033 call->msg_ctx = dce_conn->msg_ctx;
1034 call->state_flags = call->conn->state_flags;
1035 call->time = timeval_current();
1036 call->list = DCESRV_LIST_NONE;
1038 talloc_set_destructor(call, dcesrv_call_dequeue);
1040 blob = dce_conn->partial_input;
1041 blob.length = dcerpc_get_frag_length(&blob);
1043 ndr = ndr_pull_init_blob(&blob, call);
1045 talloc_free(dce_conn->partial_input.data);
1047 return NT_STATUS_NO_MEMORY;
1050 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
1051 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
1054 status = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
1055 if (!NT_STATUS_IS_OK(status)) {
1056 talloc_free(dce_conn->partial_input.data);
1061 /* we have to check the signing here, before combining the
1063 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1064 !dcesrv_auth_request(call, &blob)) {
1065 dce_partial_advance(dce_conn, blob.length);
1066 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1069 dce_partial_advance(dce_conn, blob.length);
1071 /* see if this is a continued packet */
1072 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1073 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1074 struct dcesrv_call_state *call2 = call;
1075 uint32_t alloc_size;
1077 /* we only allow fragmented requests, no other packet types */
1078 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1079 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1082 /* this is a continuation of an existing call - find the call then
1083 tack it on the end */
1084 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1086 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1089 if (call->pkt.ptype != call2->pkt.ptype) {
1090 /* trying to play silly buggers are we? */
1091 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1094 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1095 call2->pkt.u.request.stub_and_verifier.length;
1096 if (call->pkt.u.request.alloc_hint > alloc_size) {
1097 alloc_size = call->pkt.u.request.alloc_hint;
1100 call->pkt.u.request.stub_and_verifier.data =
1101 talloc_realloc(call,
1102 call->pkt.u.request.stub_and_verifier.data,
1103 uint8_t, alloc_size);
1104 if (!call->pkt.u.request.stub_and_verifier.data) {
1105 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1107 memcpy(call->pkt.u.request.stub_and_verifier.data +
1108 call->pkt.u.request.stub_and_verifier.length,
1109 call2->pkt.u.request.stub_and_verifier.data,
1110 call2->pkt.u.request.stub_and_verifier.length);
1111 call->pkt.u.request.stub_and_verifier.length +=
1112 call2->pkt.u.request.stub_and_verifier.length;
1114 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1119 /* this may not be the last pdu in the chain - if its isn't then
1120 just put it on the incoming_fragmented_call_list and wait for the rest */
1121 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1122 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1123 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1124 return NT_STATUS_OK;
1127 /* This removes any fragments we may have had stashed away */
1128 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1130 switch (call->pkt.ptype) {
1131 case DCERPC_PKT_BIND:
1132 status = dcesrv_bind(call);
1134 case DCERPC_PKT_AUTH3:
1135 status = dcesrv_auth3(call);
1137 case DCERPC_PKT_ALTER:
1138 status = dcesrv_alter(call);
1140 case DCERPC_PKT_REQUEST:
1141 status = dcesrv_request(call);
1144 status = NT_STATUS_INVALID_PARAMETER;
1148 /* if we are going to be sending a reply then add
1149 it to the list of pending calls. We add it to the end to keep the call
1150 list in the order we will answer */
1151 if (!NT_STATUS_IS_OK(status)) {
1160 provide some input to a dcerpc endpoint server. This passes data
1161 from a dcerpc client into the server
1163 _PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1167 dce_conn->partial_input.data = talloc_realloc(dce_conn,
1168 dce_conn->partial_input.data,
1170 dce_conn->partial_input.length + data->length);
1171 if (!dce_conn->partial_input.data) {
1172 return NT_STATUS_NO_MEMORY;
1174 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1175 data->data, data->length);
1176 dce_conn->partial_input.length += data->length;
1178 while (dce_full_packet(&dce_conn->partial_input)) {
1179 status = dcesrv_input_process(dce_conn);
1180 if (!NT_STATUS_IS_OK(status)) {
1185 return NT_STATUS_OK;
1189 retrieve some output from a dcerpc server
1190 The caller supplies a function that will be called to do the
1193 The first argument to write_fn() will be 'private', the second will
1194 be a pointer to a buffer containing the data to be sent and the 3rd
1195 will be a pointer to a size_t variable that will be set to the
1196 number of bytes that are consumed from the output.
1198 from the current fragment
1200 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
1202 NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1205 struct dcesrv_call_state *call;
1206 struct data_blob_list_item *rep;
1209 call = dce_conn->call_list;
1210 if (!call || !call->replies) {
1211 if (dce_conn->pending_call_list) {
1212 /* TODO: we need to say act async here
1213 * as we know we have pending requests
1214 * which will be finished at a time
1216 return NT_STATUS_FOOBAR;
1218 return NT_STATUS_FOOBAR;
1220 rep = call->replies;
1222 status = write_fn(private_data, &rep->blob, &nwritten);
1223 NT_STATUS_IS_ERR_RETURN(status);
1225 rep->blob.length -= nwritten;
1226 rep->blob.data += nwritten;
1228 if (rep->blob.length == 0) {
1229 /* we're done with this section of the call */
1230 DLIST_REMOVE(call->replies, rep);
1233 if (call->replies == NULL) {
1234 /* we're done with the whole call */
1235 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1242 static NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1245 struct dcesrv_context *dce_ctx;
1248 if (!endpoint_servers) {
1249 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1250 return NT_STATUS_INTERNAL_ERROR;
1253 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1254 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1255 dce_ctx->endpoint_list = NULL;
1257 for (i=0;endpoint_servers[i];i++) {
1258 const struct dcesrv_endpoint_server *ep_server;
1260 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1262 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1263 return NT_STATUS_INTERNAL_ERROR;
1266 status = ep_server->init_server(dce_ctx, ep_server);
1267 if (!NT_STATUS_IS_OK(status)) {
1268 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1269 nt_errstr(status)));
1274 *_dce_ctx = dce_ctx;
1275 return NT_STATUS_OK;
1279 initialise the dcerpc server context for ncacn_np based services
1281 _PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **_dce_ctx)
1284 struct dcesrv_context *dce_ctx;
1286 status = dcesrv_init_context(mem_ctx, lp_dcerpc_endpoint_servers(), &dce_ctx);
1287 NT_STATUS_NOT_OK_RETURN(status);
1289 *_dce_ctx = dce_ctx;
1290 return NT_STATUS_OK;
1293 /* the list of currently registered DCERPC endpoint servers.
1295 static struct ep_server {
1296 struct dcesrv_endpoint_server *ep_server;
1297 } *ep_servers = NULL;
1298 static int num_ep_servers;
1301 register a DCERPC endpoint server.
1303 The 'name' can be later used by other backends to find the operations
1304 structure for this backend.
1306 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1308 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1310 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1312 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1313 /* its already registered! */
1314 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1316 return NT_STATUS_OBJECT_NAME_COLLISION;
1319 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1321 smb_panic("out of memory in dcerpc_register");
1324 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1325 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1329 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1332 return NT_STATUS_OK;
1336 return the operations structure for a named backend of the specified type
1338 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1342 for (i=0;i<num_ep_servers;i++) {
1343 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1344 return ep_servers[i].ep_server;
1352 return the DCERPC module version, and the size of some critical types
1353 This can be used by endpoint server modules to either detect compilation errors, or provide
1354 multiple implementations for different smbd compilation options in one module
1356 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1358 static const struct dcesrv_critical_sizes critical_sizes = {
1359 DCERPC_MODULE_VERSION,
1360 sizeof(struct dcesrv_context),
1361 sizeof(struct dcesrv_endpoint),
1362 sizeof(struct dcesrv_endpoint_server),
1363 sizeof(struct dcesrv_interface),
1364 sizeof(struct dcesrv_if_list),
1365 sizeof(struct dcesrv_connection),
1366 sizeof(struct dcesrv_call_state),
1367 sizeof(struct dcesrv_auth),
1368 sizeof(struct dcesrv_handle)
1371 return &critical_sizes;
1375 open the dcerpc server sockets
1377 static void dcesrv_task_init(struct task_server *task)
1380 struct dcesrv_context *dce_ctx;
1381 struct dcesrv_endpoint *e;
1383 task_server_set_title(task, "task[dcesrv]");
1385 status = dcesrv_init_context(task->event_ctx,
1386 lp_dcerpc_endpoint_servers(),
1388 if (!NT_STATUS_IS_OK(status)) goto failed;
1390 /* Make sure the directory for NCALRPC exists */
1391 if (!directory_exist(lp_ncalrpc_dir())) {
1392 mkdir(lp_ncalrpc_dir(), 0755);
1395 for (e=dce_ctx->endpoint_list;e;e=e->next) {
1396 switch (e->ep_description->transport) {
1397 case NCACN_UNIX_STREAM:
1398 status = dcesrv_add_ep_unix(dce_ctx, e, task->event_ctx, task->model_ops);
1399 if (!NT_STATUS_IS_OK(status)) goto failed;
1403 status = dcesrv_add_ep_ncalrpc(dce_ctx, e, task->event_ctx, task->model_ops);
1404 if (!NT_STATUS_IS_OK(status)) goto failed;
1408 status = dcesrv_add_ep_tcp(dce_ctx, e, task->event_ctx, task->model_ops);
1409 if (!NT_STATUS_IS_OK(status)) goto failed;
1413 status = dcesrv_add_ep_np(dce_ctx, e, task->event_ctx, task->model_ops);
1414 if (!NT_STATUS_IS_OK(status)) goto failed;
1418 status = NT_STATUS_NOT_SUPPORTED;
1419 if (!NT_STATUS_IS_OK(status)) goto failed;
1425 task_server_terminate(task, "Failed to startup dcerpc server task");
1429 called on startup of the smb server service It's job is to start
1430 listening on all configured sockets
1432 static NTSTATUS dcesrv_init(struct event_context *event_context,
1433 const struct model_ops *model_ops)
1435 return task_server_startup(event_context, model_ops, dcesrv_task_init);
1438 NTSTATUS server_service_rpc_init(void)
1440 init_module_fn static_init[] = STATIC_dcerpc_server_MODULES;
1441 init_module_fn *shared_init = load_samba_modules(NULL, "dcerpc_server");
1443 run_init_functions(static_init);
1444 run_init_functions(shared_init);
1446 talloc_free(shared_init);
1448 return register_server_service("rpc", dcesrv_init);