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 "lib/util/dlinklist.h"
28 #include "rpc_server/dcerpc_server.h"
29 #include "lib/events/events.h"
30 #include "smbd/service_task.h"
31 #include "smbd/service_stream.h"
32 #include "smbd/service.h"
33 #include "system/filesys.h"
34 #include "libcli/security/security.h"
38 see if two endpoints match
40 static BOOL endpoints_match(const struct dcerpc_binding *ep1,
41 const struct dcerpc_binding *ep2)
43 if (ep1->transport != ep2->transport) {
47 if (!ep1->endpoint || !ep2->endpoint) {
48 return ep1->endpoint == ep2->endpoint;
51 if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
58 find an endpoint in the dcesrv_context
60 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
61 const struct dcerpc_binding *ep_description)
63 struct dcesrv_endpoint *ep;
64 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
65 if (endpoints_match(ep->ep_description, ep_description)) {
73 find a registered context_id from a bind or alter_context
75 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn,
78 struct dcesrv_connection_context *c;
79 for (c=conn->contexts;c;c=c->next) {
80 if (c->context_id == context_id) return c;
86 see if a uuid and if_version match to an interface
88 static BOOL interface_match(const struct dcesrv_interface *if1,
89 const struct dcesrv_interface *if2)
91 return (if1->syntax_id.if_version == if2->syntax_id.if_version &&
92 GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
96 find the interface operations on an endpoint
98 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
99 const struct dcesrv_interface *iface)
101 struct dcesrv_if_list *ifl;
102 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
103 if (interface_match(&(ifl->iface), iface)) {
104 return &(ifl->iface);
111 see if a uuid and if_version match to an interface
113 static BOOL interface_match_by_uuid(const struct dcesrv_interface *iface,
114 const struct GUID *uuid, uint32_t if_version)
116 return (iface->syntax_id.if_version == if_version &&
117 GUID_equal(&iface->syntax_id.uuid, uuid));
121 find the interface operations on an endpoint by uuid
123 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
124 const struct GUID *uuid, uint32_t if_version)
126 struct dcesrv_if_list *ifl;
127 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
128 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
129 return &(ifl->iface);
136 find the earlier parts of a fragmented call awaiting reassembily
138 static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
140 struct dcesrv_call_state *c;
141 for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
142 if (c->pkt.call_id == call_id) {
150 register an interface on an endpoint
152 _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
154 const struct dcesrv_interface *iface,
155 const struct security_descriptor *sd)
157 struct dcesrv_endpoint *ep;
158 struct dcesrv_if_list *ifl;
159 struct dcerpc_binding *binding;
163 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
165 if (NT_STATUS_IS_ERR(status)) {
166 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
170 /* check if this endpoint exists
172 if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
173 ep = talloc(dce_ctx, struct dcesrv_endpoint);
175 return NT_STATUS_NO_MEMORY;
178 ep->ep_description = talloc_reference(ep, binding);
182 /* see if the interface is already registered on te endpoint */
183 if (find_interface(ep, iface)!=NULL) {
184 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
185 iface->name, ep_name));
186 return NT_STATUS_OBJECT_NAME_COLLISION;
189 /* talloc a new interface list element */
190 ifl = talloc(dce_ctx, struct dcesrv_if_list);
192 return NT_STATUS_NO_MEMORY;
195 /* copy the given interface struct to the one on the endpoints interface list */
196 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
198 /* if we have a security descriptor given,
199 * we should see if we can set it up on the endpoint
202 /* if there's currently no security descriptor given on the endpoint
205 if (ep->sd == NULL) {
206 ep->sd = security_descriptor_copy(dce_ctx, sd);
209 /* if now there's no security descriptor given on the endpoint
210 * something goes wrong, either we failed to copy the security descriptor
211 * or there was already one on the endpoint
213 if (ep->sd != NULL) {
214 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
215 " on endpoint '%s'\n",
216 iface->name, ep_name));
217 if (add_ep) free(ep);
219 return NT_STATUS_OBJECT_NAME_COLLISION;
223 /* finally add the interface on the endpoint */
224 DLIST_ADD(ep->interface_list, ifl);
226 /* if it's a new endpoint add it to the dcesrv_context */
228 DLIST_ADD(dce_ctx->endpoint_list, ep);
231 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
232 iface->name, ep_name));
237 static NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
238 DATA_BLOB *session_key)
240 if (p->auth_state.session_info->session_key.length) {
241 *session_key = p->auth_state.session_info->session_key;
244 return NT_STATUS_NO_USER_SESSION_KEY;
247 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
248 DATA_BLOB *session_key)
250 /* this took quite a few CPU cycles to find ... */
251 session_key->data = discard_const_p(uint8_t, "SystemLibraryDTC");
252 session_key->length = 16;
257 fetch the user session key - may be default (above) or the SMB session key
259 _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
260 DATA_BLOB *session_key)
262 return p->auth_state.session_key(p, session_key);
267 destroy a link to an endpoint
269 static int dcesrv_endpoint_destructor(struct dcesrv_connection *p)
271 while (p->contexts) {
272 struct dcesrv_connection_context *c = p->contexts;
274 DLIST_REMOVE(p->contexts, c);
277 c->iface->unbind(c, c->iface);
286 connect to a dcerpc endpoint
288 NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
290 const struct dcesrv_endpoint *ep,
291 struct auth_session_info *session_info,
292 struct event_context *event_ctx,
293 struct messaging_context *msg_ctx,
295 uint32_t state_flags,
296 struct dcesrv_connection **_p)
298 struct dcesrv_connection *p;
301 return NT_STATUS_ACCESS_DENIED;
304 p = talloc(mem_ctx, struct dcesrv_connection);
305 NT_STATUS_HAVE_NO_MEMORY(p);
307 if (!talloc_reference(p, session_info)) {
309 return NT_STATUS_NO_MEMORY;
312 p->dce_ctx = dce_ctx;
316 p->incoming_fragmented_call_list = NULL;
317 p->pending_call_list = NULL;
318 p->cli_max_recv_frag = 0;
319 p->partial_input = data_blob(NULL, 0);
320 p->auth_state.auth_info = NULL;
321 p->auth_state.gensec_security = NULL;
322 p->auth_state.session_info = session_info;
323 p->auth_state.session_key = dcesrv_generic_session_key;
324 p->event_ctx = event_ctx;
325 p->msg_ctx = msg_ctx;
326 p->server_id = server_id;
327 p->processing = False;
328 p->state_flags = state_flags;
329 ZERO_STRUCT(p->transport);
331 talloc_set_destructor(p, dcesrv_endpoint_destructor);
338 search and connect to a dcerpc endpoint
340 _PUBLIC_ NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
342 const struct dcerpc_binding *ep_description,
343 struct auth_session_info *session_info,
344 struct event_context *event_ctx,
345 struct messaging_context *msg_ctx,
347 uint32_t state_flags,
348 struct dcesrv_connection **dce_conn_p)
351 const struct dcesrv_endpoint *ep;
353 /* make sure this endpoint exists */
354 ep = find_endpoint(dce_ctx, ep_description);
356 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
359 status = dcesrv_endpoint_connect(dce_ctx, mem_ctx, ep, session_info,
360 event_ctx, msg_ctx, server_id,
361 state_flags, dce_conn_p);
362 NT_STATUS_NOT_OK_RETURN(status);
364 (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
366 /* TODO: check security descriptor of the endpoint here
367 * if it's a smb named pipe
368 * if it's failed free dce_conn_p
375 static void dcesrv_init_hdr(struct ncacn_packet *pkt)
378 pkt->rpc_vers_minor = 0;
379 if (lp_rpc_big_endian()) {
382 pkt->drep[0] = DCERPC_DREP_LE;
390 return a dcerpc fault
392 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
394 struct ncacn_packet pkt;
395 struct data_blob_list_item *rep;
398 /* setup a bind_ack */
399 dcesrv_init_hdr(&pkt);
401 pkt.call_id = call->pkt.call_id;
402 pkt.ptype = DCERPC_PKT_FAULT;
403 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
404 pkt.u.fault.alloc_hint = 0;
405 pkt.u.fault.context_id = 0;
406 pkt.u.fault.cancel_count = 0;
407 pkt.u.fault.status = fault_code;
409 rep = talloc(call, struct data_blob_list_item);
411 return NT_STATUS_NO_MEMORY;
414 status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
415 if (!NT_STATUS_IS_OK(status)) {
419 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
421 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
422 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
429 return a dcerpc bind_nak
431 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
433 struct ncacn_packet pkt;
434 struct data_blob_list_item *rep;
437 /* setup a bind_nak */
438 dcesrv_init_hdr(&pkt);
440 pkt.call_id = call->pkt.call_id;
441 pkt.ptype = DCERPC_PKT_BIND_NAK;
442 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
443 pkt.u.bind_nak.reject_reason = reason;
444 if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
445 pkt.u.bind_nak.versions.v.num_versions = 0;
448 rep = talloc(call, struct data_blob_list_item);
450 return NT_STATUS_NO_MEMORY;
453 status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
454 if (!NT_STATUS_IS_OK(status)) {
458 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
460 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
461 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
468 handle a bind request
470 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
472 uint32_t if_version, transfer_syntax_version;
473 struct GUID uuid, *transfer_syntax_uuid;
474 struct ncacn_packet pkt;
475 struct data_blob_list_item *rep;
477 uint32_t result=0, reason=0;
479 const struct dcesrv_interface *iface;
481 if (call->pkt.u.bind.num_contexts < 1 ||
482 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
483 return dcesrv_bind_nak(call, 0);
486 context_id = call->pkt.u.bind.ctx_list[0].context_id;
488 /* you can't bind twice on one context */
489 if (dcesrv_find_context(call->conn, context_id) != NULL) {
490 return dcesrv_bind_nak(call, 0);
493 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
494 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
496 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
497 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
498 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
499 ndr_transfer_syntax.if_version != transfer_syntax_version) {
500 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
501 /* we only do NDR encoded dcerpc */
502 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
503 talloc_free(uuid_str);
504 return dcesrv_bind_nak(call, 0);
507 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
509 char *uuid_str = GUID_string(call, &uuid);
510 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
511 talloc_free(uuid_str);
513 /* we don't know about that interface */
514 result = DCERPC_BIND_PROVIDER_REJECT;
515 reason = DCERPC_BIND_REASON_ASYNTAX;
519 /* add this context to the list of available context_ids */
520 struct dcesrv_connection_context *context = talloc(call->conn,
521 struct dcesrv_connection_context);
522 if (context == NULL) {
523 return dcesrv_bind_nak(call, 0);
525 context->conn = call->conn;
526 context->iface = iface;
527 context->context_id = context_id;
528 context->private = NULL;
529 context->handles = NULL;
530 DLIST_ADD(call->conn->contexts, context);
531 call->context = context;
534 if (call->conn->cli_max_recv_frag == 0) {
535 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
538 /* handle any authentication that is being requested */
539 if (!dcesrv_auth_bind(call)) {
540 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
543 /* setup a bind_ack */
544 dcesrv_init_hdr(&pkt);
546 pkt.call_id = call->pkt.call_id;
547 pkt.ptype = DCERPC_PKT_BIND_ACK;
548 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
549 pkt.u.bind_ack.max_xmit_frag = 0x2000;
550 pkt.u.bind_ack.max_recv_frag = 0x2000;
551 pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
553 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
554 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
556 pkt.u.bind_ack.secondary_address = "";
558 pkt.u.bind_ack.num_results = 1;
559 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
560 if (!pkt.u.bind_ack.ctx_list) {
561 return NT_STATUS_NO_MEMORY;
563 pkt.u.bind_ack.ctx_list[0].result = result;
564 pkt.u.bind_ack.ctx_list[0].reason = reason;
565 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
566 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
568 if (!dcesrv_auth_bind_ack(call, &pkt)) {
569 return dcesrv_bind_nak(call, 0);
573 status = iface->bind(call, iface);
574 if (!NT_STATUS_IS_OK(status)) {
575 char *uuid_str = GUID_string(call, &uuid);
576 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
577 uuid_str, if_version, nt_errstr(status)));
578 talloc_free(uuid_str);
579 return dcesrv_bind_nak(call, 0);
583 rep = talloc(call, struct data_blob_list_item);
585 return NT_STATUS_NO_MEMORY;
588 status = ncacn_push_auth(&rep->blob, call, &pkt,
589 call->conn->auth_state.auth_info);
590 if (!NT_STATUS_IS_OK(status)) {
594 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
596 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
597 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
604 handle a auth3 request
606 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
608 /* handle the auth3 in the auth code */
609 if (!dcesrv_auth_auth3(call)) {
610 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
615 /* we don't send a reply to a auth3 request, except by a
622 handle a bind request
624 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
626 uint32_t if_version, transfer_syntax_version;
627 struct dcesrv_connection_context *context;
628 const struct dcesrv_interface *iface;
629 struct GUID uuid, *transfer_syntax_uuid;
631 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
632 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
634 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
635 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
636 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
637 ndr_transfer_syntax.if_version != transfer_syntax_version) {
638 /* we only do NDR encoded dcerpc */
639 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
642 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
644 char *uuid_str = GUID_string(call, &uuid);
645 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
646 talloc_free(uuid_str);
647 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
650 /* add this context to the list of available context_ids */
651 context = talloc(call->conn, struct dcesrv_connection_context);
652 if (context == NULL) {
653 return NT_STATUS_NO_MEMORY;
655 context->conn = call->conn;
656 context->iface = iface;
657 context->context_id = context_id;
658 context->private = NULL;
659 context->handles = NULL;
660 DLIST_ADD(call->conn->contexts, context);
661 call->context = context;
668 handle a alter context request
670 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
672 struct ncacn_packet pkt;
673 struct data_blob_list_item *rep;
675 uint32_t result=0, reason=0;
678 /* handle any authentication that is being requested */
679 if (!dcesrv_auth_alter(call)) {
680 /* TODO: work out the right reject code */
681 result = DCERPC_BIND_PROVIDER_REJECT;
682 reason = DCERPC_BIND_REASON_ASYNTAX;
685 context_id = call->pkt.u.alter.ctx_list[0].context_id;
687 /* see if they are asking for a new interface */
689 dcesrv_find_context(call->conn, context_id) == NULL) {
690 status = dcesrv_alter_new_context(call, context_id);
691 if (!NT_STATUS_IS_OK(status)) {
692 result = DCERPC_BIND_PROVIDER_REJECT;
693 reason = DCERPC_BIND_REASON_ASYNTAX;
697 /* setup a alter_resp */
698 dcesrv_init_hdr(&pkt);
700 pkt.call_id = call->pkt.call_id;
701 pkt.ptype = DCERPC_PKT_ALTER_RESP;
702 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
703 pkt.u.alter_resp.max_xmit_frag = 0x2000;
704 pkt.u.alter_resp.max_recv_frag = 0x2000;
705 pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
706 pkt.u.alter_resp.num_results = 1;
707 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
708 if (!pkt.u.alter_resp.ctx_list) {
709 return NT_STATUS_NO_MEMORY;
711 pkt.u.alter_resp.ctx_list[0].result = result;
712 pkt.u.alter_resp.ctx_list[0].reason = reason;
713 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
714 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
715 pkt.u.alter_resp.secondary_address = "";
717 if (!dcesrv_auth_alter_ack(call, &pkt)) {
718 return dcesrv_bind_nak(call, 0);
721 rep = talloc(call, struct data_blob_list_item);
723 return NT_STATUS_NO_MEMORY;
726 status = ncacn_push_auth(&rep->blob, call, &pkt,
727 call->conn->auth_state.auth_info);
728 if (!NT_STATUS_IS_OK(status)) {
732 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
734 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
735 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
741 handle a dcerpc request packet
743 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
745 struct ndr_pull *pull;
747 struct dcesrv_connection_context *context;
749 /* if authenticated, and the mech we use can't do async replies, don't use them... */
750 if (call->conn->auth_state.gensec_security &&
751 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
752 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
755 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
756 if (context == NULL) {
757 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
760 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
761 NT_STATUS_HAVE_NO_MEMORY(pull);
763 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
765 call->context = context;
766 call->ndr_pull = pull;
768 if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_ORPC) {
769 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
772 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
773 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
776 /* unravel the NDR for the packet */
777 status = context->iface->ndr_pull(call, call, pull, &call->r);
778 if (!NT_STATUS_IS_OK(status)) {
779 return dcesrv_fault(call, call->fault_code);
782 if (pull->offset != pull->data_size) {
783 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
784 pull->data_size - pull->offset));
785 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
788 /* call the dispatch function */
789 status = context->iface->dispatch(call, call, call->r);
790 if (!NT_STATUS_IS_OK(status)) {
791 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
792 context->iface->name,
793 call->pkt.u.request.opnum,
794 dcerpc_errstr(pull, call->fault_code)));
795 return dcesrv_fault(call, call->fault_code);
798 /* add the call to the pending list */
799 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
801 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
805 return dcesrv_reply(call);
808 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
810 struct ndr_push *push;
813 uint32_t total_length;
814 struct dcesrv_connection_context *context = call->context;
816 /* call the reply function */
817 status = context->iface->reply(call, call, call->r);
818 if (!NT_STATUS_IS_OK(status)) {
819 return dcesrv_fault(call, call->fault_code);
822 /* form the reply NDR */
823 push = ndr_push_init_ctx(call);
824 NT_STATUS_HAVE_NO_MEMORY(push);
826 /* carry over the pointer count to the reply in case we are
827 using full pointer. See NDR specification for full
829 push->ptr_count = call->ndr_pull->ptr_count;
831 if (lp_rpc_big_endian()) {
832 push->flags |= LIBNDR_FLAG_BIGENDIAN;
835 status = context->iface->ndr_push(call, call, push, call->r);
836 if (!NT_STATUS_IS_OK(status)) {
837 return dcesrv_fault(call, call->fault_code);
840 stub = ndr_push_blob(push);
842 total_length = stub.length;
846 struct data_blob_list_item *rep;
847 struct ncacn_packet pkt;
849 rep = talloc(call, struct data_blob_list_item);
850 NT_STATUS_HAVE_NO_MEMORY(rep);
852 length = stub.length;
853 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
854 /* the 32 is to cope with signing data */
855 length = call->conn->cli_max_recv_frag -
856 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
859 /* form the dcerpc response packet */
860 dcesrv_init_hdr(&pkt);
862 pkt.call_id = call->pkt.call_id;
863 pkt.ptype = DCERPC_PKT_RESPONSE;
865 if (stub.length == total_length) {
866 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
868 if (length == stub.length) {
869 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
871 pkt.u.response.alloc_hint = stub.length;
872 pkt.u.response.context_id = call->pkt.u.request.context_id;
873 pkt.u.response.cancel_count = 0;
874 pkt.u.response.stub_and_verifier.data = stub.data;
875 pkt.u.response.stub_and_verifier.length = length;
877 if (!dcesrv_auth_response(call, &rep->blob, &pkt)) {
878 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
881 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
883 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
886 stub.length -= length;
887 } while (stub.length != 0);
889 /* move the call from the pending to the finished calls list */
890 DLIST_REMOVE(call->conn->pending_call_list, call);
891 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
893 if (call->conn->call_list && call->conn->call_list->replies) {
894 if (call->conn->transport.report_output_data) {
895 call->conn->transport.report_output_data(call->conn);
902 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
904 if (!conn->transport.get_my_addr) {
908 return conn->transport.get_my_addr(conn, mem_ctx);
911 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
913 if (!conn->transport.get_peer_addr) {
917 return conn->transport.get_peer_addr(conn, mem_ctx);
921 work out if we have a full packet yet
923 static BOOL dce_full_packet(const DATA_BLOB *data)
925 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
928 if (dcerpc_get_frag_length(data) > data->length) {
935 we might have consumed only part of our input - advance past that part
937 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
941 if (dce_conn->partial_input.length == offset) {
942 data_blob_free(&dce_conn->partial_input);
946 blob = dce_conn->partial_input;
947 dce_conn->partial_input = data_blob(blob.data + offset,
948 blob.length - offset);
949 data_blob_free(&blob);
953 process some input to a dcerpc endpoint server.
955 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
957 struct ndr_pull *ndr;
959 struct dcesrv_call_state *call;
962 call = talloc_zero(dce_conn, struct dcesrv_call_state);
964 talloc_free(dce_conn->partial_input.data);
965 return NT_STATUS_NO_MEMORY;
967 call->conn = dce_conn;
968 call->event_ctx = dce_conn->event_ctx;
969 call->msg_ctx = dce_conn->msg_ctx;
970 call->state_flags = call->conn->state_flags;
971 call->time = timeval_current();
973 blob = dce_conn->partial_input;
974 blob.length = dcerpc_get_frag_length(&blob);
976 ndr = ndr_pull_init_blob(&blob, call);
978 talloc_free(dce_conn->partial_input.data);
980 return NT_STATUS_NO_MEMORY;
983 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
984 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
987 status = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
988 if (!NT_STATUS_IS_OK(status)) {
989 talloc_free(dce_conn->partial_input.data);
994 /* we have to check the signing here, before combining the
996 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
997 !dcesrv_auth_request(call, &blob)) {
998 dce_partial_advance(dce_conn, blob.length);
999 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
1002 dce_partial_advance(dce_conn, blob.length);
1004 /* see if this is a continued packet */
1005 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1006 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1007 struct dcesrv_call_state *call2 = call;
1008 uint32_t alloc_size;
1010 /* we only allow fragmented requests, no other packet types */
1011 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1012 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1015 /* this is a continuation of an existing call - find the call then
1016 tack it on the end */
1017 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1019 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1022 if (call->pkt.ptype != call2->pkt.ptype) {
1023 /* trying to play silly buggers are we? */
1024 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1027 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1028 call2->pkt.u.request.stub_and_verifier.length;
1029 if (call->pkt.u.request.alloc_hint > alloc_size) {
1030 alloc_size = call->pkt.u.request.alloc_hint;
1033 call->pkt.u.request.stub_and_verifier.data =
1034 talloc_realloc(call,
1035 call->pkt.u.request.stub_and_verifier.data,
1036 uint8_t, alloc_size);
1037 if (!call->pkt.u.request.stub_and_verifier.data) {
1038 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1040 memcpy(call->pkt.u.request.stub_and_verifier.data +
1041 call->pkt.u.request.stub_and_verifier.length,
1042 call2->pkt.u.request.stub_and_verifier.data,
1043 call2->pkt.u.request.stub_and_verifier.length);
1044 call->pkt.u.request.stub_and_verifier.length +=
1045 call2->pkt.u.request.stub_and_verifier.length;
1047 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1052 /* this may not be the last pdu in the chain - if its isn't then
1053 just put it on the incoming_fragmented_call_list and wait for the rest */
1054 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1055 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1056 DLIST_ADD_END(dce_conn->incoming_fragmented_call_list, call,
1057 struct dcesrv_call_state *);
1058 return NT_STATUS_OK;
1061 switch (call->pkt.ptype) {
1062 case DCERPC_PKT_BIND:
1063 status = dcesrv_bind(call);
1065 case DCERPC_PKT_AUTH3:
1066 status = dcesrv_auth3(call);
1068 case DCERPC_PKT_ALTER:
1069 status = dcesrv_alter(call);
1071 case DCERPC_PKT_REQUEST:
1072 status = dcesrv_request(call);
1075 status = NT_STATUS_INVALID_PARAMETER;
1079 /* if we are going to be sending a reply then add
1080 it to the list of pending calls. We add it to the end to keep the call
1081 list in the order we will answer */
1082 if (!NT_STATUS_IS_OK(status)) {
1091 provide some input to a dcerpc endpoint server. This passes data
1092 from a dcerpc client into the server
1094 _PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1098 dce_conn->partial_input.data = talloc_realloc(dce_conn,
1099 dce_conn->partial_input.data,
1101 dce_conn->partial_input.length + data->length);
1102 if (!dce_conn->partial_input.data) {
1103 return NT_STATUS_NO_MEMORY;
1105 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1106 data->data, data->length);
1107 dce_conn->partial_input.length += data->length;
1109 while (dce_full_packet(&dce_conn->partial_input)) {
1110 status = dcesrv_input_process(dce_conn);
1111 if (!NT_STATUS_IS_OK(status)) {
1116 return NT_STATUS_OK;
1120 retrieve some output from a dcerpc server
1121 The caller supplies a function that will be called to do the
1124 The first argument to write_fn() will be 'private', the second will
1125 be a pointer to a buffer containing the data to be sent and the 3rd
1126 will be a pointer to a size_t variable that will be set to the
1127 number of bytes that are consumed from the output.
1129 from the current fragment
1131 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
1133 NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1136 struct dcesrv_call_state *call;
1137 struct data_blob_list_item *rep;
1140 call = dce_conn->call_list;
1141 if (!call || !call->replies) {
1142 if (dce_conn->pending_call_list) {
1143 /* TODO: we need to say act async here
1144 * as we know we have pending requests
1145 * which will be finished at a time
1147 return NT_STATUS_FOOBAR;
1149 return NT_STATUS_FOOBAR;
1151 rep = call->replies;
1153 status = write_fn(private_data, &rep->blob, &nwritten);
1154 NT_STATUS_IS_ERR_RETURN(status);
1156 rep->blob.length -= nwritten;
1157 rep->blob.data += nwritten;
1159 if (rep->blob.length == 0) {
1160 /* we're done with this section of the call */
1161 DLIST_REMOVE(call->replies, rep);
1164 if (call->replies == NULL) {
1165 /* we're done with the whole call */
1166 DLIST_REMOVE(dce_conn->call_list, call);
1173 static NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1176 struct dcesrv_context *dce_ctx;
1179 if (!endpoint_servers) {
1180 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1181 return NT_STATUS_INTERNAL_ERROR;
1184 dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1185 NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1186 dce_ctx->endpoint_list = NULL;
1188 for (i=0;endpoint_servers[i];i++) {
1189 const struct dcesrv_endpoint_server *ep_server;
1191 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1193 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1194 return NT_STATUS_INTERNAL_ERROR;
1197 status = ep_server->init_server(dce_ctx, ep_server);
1198 if (!NT_STATUS_IS_OK(status)) {
1199 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1200 nt_errstr(status)));
1205 *_dce_ctx = dce_ctx;
1206 return NT_STATUS_OK;
1210 initialise the dcerpc server context for ncacn_np based services
1212 _PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **_dce_ctx)
1215 struct dcesrv_context *dce_ctx;
1217 status = dcesrv_init_context(mem_ctx, lp_dcerpc_endpoint_servers(), &dce_ctx);
1218 NT_STATUS_NOT_OK_RETURN(status);
1220 *_dce_ctx = dce_ctx;
1221 return NT_STATUS_OK;
1224 /* the list of currently registered DCERPC endpoint servers.
1226 static struct ep_server {
1227 struct dcesrv_endpoint_server *ep_server;
1228 } *ep_servers = NULL;
1229 static int num_ep_servers;
1232 register a DCERPC endpoint server.
1234 The 'name' can be later used by other backends to find the operations
1235 structure for this backend.
1237 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1239 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1241 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1243 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1244 /* its already registered! */
1245 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1247 return NT_STATUS_OBJECT_NAME_COLLISION;
1250 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1252 smb_panic("out of memory in dcerpc_register");
1255 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1256 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1260 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1263 return NT_STATUS_OK;
1267 return the operations structure for a named backend of the specified type
1269 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1273 for (i=0;i<num_ep_servers;i++) {
1274 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1275 return ep_servers[i].ep_server;
1283 return the DCERPC module version, and the size of some critical types
1284 This can be used by endpoint server modules to either detect compilation errors, or provide
1285 multiple implementations for different smbd compilation options in one module
1287 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1289 static const struct dcesrv_critical_sizes critical_sizes = {
1290 DCERPC_MODULE_VERSION,
1291 sizeof(struct dcesrv_context),
1292 sizeof(struct dcesrv_endpoint),
1293 sizeof(struct dcesrv_endpoint_server),
1294 sizeof(struct dcesrv_interface),
1295 sizeof(struct dcesrv_if_list),
1296 sizeof(struct dcesrv_connection),
1297 sizeof(struct dcesrv_call_state),
1298 sizeof(struct dcesrv_auth),
1299 sizeof(struct dcesrv_handle)
1302 return &critical_sizes;
1306 open the dcerpc server sockets
1308 static void dcesrv_task_init(struct task_server *task)
1311 struct dcesrv_context *dce_ctx;
1312 struct dcesrv_endpoint *e;
1314 task_server_set_title(task, "task[dcesrv]");
1316 status = dcesrv_init_context(task->event_ctx,
1317 lp_dcerpc_endpoint_servers(),
1319 if (!NT_STATUS_IS_OK(status)) goto failed;
1321 /* Make sure the directory for NCALRPC exists */
1322 if (!directory_exist(lp_ncalrpc_dir())) {
1323 mkdir(lp_ncalrpc_dir(), 0755);
1326 for (e=dce_ctx->endpoint_list;e;e=e->next) {
1327 switch (e->ep_description->transport) {
1328 case NCACN_UNIX_STREAM:
1329 status = dcesrv_add_ep_unix(dce_ctx, e, task->event_ctx, task->model_ops);
1330 if (!NT_STATUS_IS_OK(status)) goto failed;
1334 status = dcesrv_add_ep_ncalrpc(dce_ctx, e, task->event_ctx, task->model_ops);
1335 if (!NT_STATUS_IS_OK(status)) goto failed;
1339 status = dcesrv_add_ep_tcp(dce_ctx, e, task->event_ctx, task->model_ops);
1340 if (!NT_STATUS_IS_OK(status)) goto failed;
1344 /* FIXME: status = dcesrv_add_ep_np(dce_ctx, e, task->event_ctx, task->model_ops);
1345 if (!NT_STATUS_IS_OK(status)) goto failed;
1349 status = NT_STATUS_NOT_SUPPORTED;
1350 if (!NT_STATUS_IS_OK(status)) goto failed;
1356 task_server_terminate(task, "Failed to startup dcerpc server task");
1360 called on startup of the smb server service It's job is to start
1361 listening on all configured sockets
1363 static NTSTATUS dcesrv_init(struct event_context *event_context,
1364 const struct model_ops *model_ops)
1366 return task_server_startup(event_context, model_ops, dcesrv_task_init);
1369 NTSTATUS server_service_rpc_init(void)
1371 init_module_fn static_init[] = STATIC_dcerpc_server_MODULES;
1372 init_module_fn *shared_init = load_samba_modules(NULL, "dcerpc_server");
1374 run_init_functions(static_init);
1375 run_init_functions(shared_init);
1377 talloc_free(shared_init);
1379 return register_server_service("rpc", dcesrv_init);