2 Unix SMB/CIFS implementation.
4 server side dcerpc core code
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Stefan (metze) Metzmacher 2004
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_epmapper.h"
26 #include "librpc/gen_ndr/ndr_oxidresolver.h"
27 #include "auth/auth.h"
28 #include "dlinklist.h"
29 #include "rpc_server/dcerpc_server.h"
32 see if two endpoints match
34 static BOOL endpoints_match(const struct dcerpc_binding *ep1,
35 const struct dcerpc_binding *ep2)
37 if (ep1->transport != ep2->transport) {
41 if (!ep1->endpoint || !ep2->endpoint) {
42 return ep1->endpoint == ep2->endpoint;
45 if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
52 find an endpoint in the dcesrv_context
54 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
55 const struct dcerpc_binding *ep_description)
57 struct dcesrv_endpoint *ep;
58 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
59 if (endpoints_match(&ep->ep_description, ep_description)) {
67 find a registered context_id from a bind or alter_context
69 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn,
72 struct dcesrv_connection_context *c;
73 for (c=conn->contexts;c;c=c->next) {
74 if (c->context_id == context_id) return c;
80 see if a uuid and if_version match to an interface
82 static BOOL interface_match(const struct dcesrv_interface *if1,
83 const struct dcesrv_interface *if2)
85 if (if1->if_version != if2->if_version) {
89 if (strcmp(if1->uuid, if2->uuid)==0) {
97 find the interface operations on an endpoint
99 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
100 const struct dcesrv_interface *iface)
102 struct dcesrv_if_list *ifl;
103 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
104 if (interface_match(&(ifl->iface), iface)) {
105 return &(ifl->iface);
112 see if a uuid and if_version match to an interface
114 static BOOL interface_match_by_uuid(const struct dcesrv_interface *iface,
115 const char *uuid, uint32_t if_version)
117 if (iface->if_version != if_version) {
121 if (strcmp(iface->uuid, uuid)==0) {
129 find the interface operations on an endpoint by uuid
131 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
132 const char *uuid, uint32_t if_version)
134 struct dcesrv_if_list *ifl;
135 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
136 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
137 return &(ifl->iface);
144 find a call that is pending in our call list
146 static struct dcesrv_call_state *dcesrv_find_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
148 struct dcesrv_call_state *c;
149 for (c=dce_conn->call_list;c;c=c->next) {
150 if (c->pkt.call_id == call_id) {
158 register an interface on an endpoint
160 NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
162 const struct dcesrv_interface *iface,
163 const struct security_descriptor *sd)
165 struct dcesrv_endpoint *ep;
166 struct dcesrv_if_list *ifl;
167 struct dcerpc_binding binding;
171 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
173 if (NT_STATUS_IS_ERR(status)) {
174 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
178 /* check if this endpoint exists
180 if ((ep=find_endpoint(dce_ctx, &binding))==NULL) {
181 ep = talloc_p(dce_ctx, struct dcesrv_endpoint);
183 return NT_STATUS_NO_MEMORY;
186 ep->ep_description = binding;
190 /* see if the interface is already registered on te endpoint */
191 if (find_interface(ep, iface)!=NULL) {
192 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
193 iface->name, ep_name));
194 return NT_STATUS_OBJECT_NAME_COLLISION;
197 /* talloc a new interface list element */
198 ifl = talloc_p(dce_ctx, struct dcesrv_if_list);
200 return NT_STATUS_NO_MEMORY;
203 /* copy the given interface struct to the one on the endpoints interface list */
204 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
206 /* if we have a security descriptor given,
207 * we should see if we can set it up on the endpoint
210 /* if there's currently no security descriptor given on the endpoint
213 if (ep->sd == NULL) {
214 ep->sd = security_descriptor_copy(dce_ctx, sd);
217 /* if now there's no security descriptor given on the endpoint
218 * something goes wrong, either we failed to copy the security descriptor
219 * or there was already one on the endpoint
221 if (ep->sd != NULL) {
222 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
223 " on endpoint '%s'\n",
224 iface->name, ep_name));
225 if (add_ep) free(ep);
227 return NT_STATUS_OBJECT_NAME_COLLISION;
231 /* finally add the interface on the endpoint */
232 DLIST_ADD(ep->interface_list, ifl);
234 /* if it's a new endpoint add it to the dcesrv_context */
236 DLIST_ADD(dce_ctx->endpoint_list, ep);
239 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
240 iface->name, ep_name));
245 static NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
246 DATA_BLOB *session_key)
248 if (p->auth_state.session_info->session_key.length) {
249 *session_key = p->auth_state.session_info->session_key;
252 return NT_STATUS_NO_USER_SESSION_KEY;
255 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
256 DATA_BLOB *session_key)
258 /* this took quite a few CPU cycles to find ... */
259 session_key->data = discard_const_p(uint8_t, "SystemLibraryDTC");
260 session_key->length = 16;
265 fetch the user session key - may be default (above) or the SMB session key
267 NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
268 DATA_BLOB *session_key)
270 return p->auth_state.session_key(p, session_key);
275 destroy a link to an endpoint
277 static int dcesrv_endpoint_destructor(void *ptr)
279 struct dcesrv_connection *p = ptr;
281 while (p->contexts) {
282 struct dcesrv_connection_context *c = p->contexts;
284 DLIST_REMOVE(p->contexts, c);
287 c->iface->unbind(c, c->iface);
298 connect to a dcerpc endpoint
300 NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
301 const struct dcesrv_endpoint *ep,
302 struct dcesrv_connection **p)
304 *p = talloc_p(dce_ctx, struct dcesrv_connection);
306 return NT_STATUS_NO_MEMORY;
309 (*p)->dce_ctx = dce_ctx;
311 (*p)->contexts = NULL;
312 (*p)->call_list = NULL;
313 (*p)->cli_max_recv_frag = 0;
314 (*p)->partial_input = data_blob(NULL, 0);
315 (*p)->auth_state.auth_info = NULL;
316 (*p)->auth_state.gensec_security = NULL;
317 (*p)->auth_state.session_info = NULL;
318 (*p)->auth_state.session_key = dcesrv_generic_session_key;
319 (*p)->srv_conn = NULL;
321 talloc_set_destructor(*p, dcesrv_endpoint_destructor);
327 search and connect to a dcerpc endpoint
329 NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
330 const struct dcerpc_binding *ep_description,
331 struct auth_session_info *session_info,
332 struct dcesrv_connection **dce_conn_p)
335 const struct dcesrv_endpoint *ep;
337 /* make sure this endpoint exists */
338 ep = find_endpoint(dce_ctx, ep_description);
340 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
343 status = dcesrv_endpoint_connect(dce_ctx, ep, dce_conn_p);
344 if (!NT_STATUS_IS_OK(status)) {
348 (*dce_conn_p)->auth_state.session_info = talloc_reference((*dce_conn_p), session_info);
349 (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
351 /* TODO: check security descriptor of the endpoint here
352 * if it's a smb named pipe
353 * if it's failed free dce_conn_p
360 static void dcesrv_init_hdr(struct dcerpc_packet *pkt)
363 pkt->rpc_vers_minor = 0;
364 if (lp_rpc_big_endian()) {
367 pkt->drep[0] = DCERPC_DREP_LE;
375 return a dcerpc fault
377 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
379 struct dcerpc_packet pkt;
380 struct dcesrv_call_reply *rep;
383 /* setup a bind_ack */
384 dcesrv_init_hdr(&pkt);
386 pkt.call_id = call->pkt.call_id;
387 pkt.ptype = DCERPC_PKT_FAULT;
388 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
389 pkt.u.fault.alloc_hint = 0;
390 pkt.u.fault.context_id = 0;
391 pkt.u.fault.cancel_count = 0;
392 pkt.u.fault.status = fault_code;
394 rep = talloc_p(call, struct dcesrv_call_reply);
396 return NT_STATUS_NO_MEMORY;
399 status = dcerpc_push_auth(&rep->data, call, &pkt, NULL);
400 if (!NT_STATUS_IS_OK(status)) {
404 dcerpc_set_frag_length(&rep->data, rep->data.length);
406 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
407 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
414 return a dcerpc bind_nak
416 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
418 struct dcerpc_packet pkt;
419 struct dcesrv_call_reply *rep;
422 /* setup a bind_nak */
423 dcesrv_init_hdr(&pkt);
425 pkt.call_id = call->pkt.call_id;
426 pkt.ptype = DCERPC_PKT_BIND_NAK;
427 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
428 pkt.u.bind_nak.reject_reason = reason;
429 pkt.u.bind_nak.num_versions = 0;
431 rep = talloc_p(call, struct dcesrv_call_reply);
433 return NT_STATUS_NO_MEMORY;
436 status = dcerpc_push_auth(&rep->data, call, &pkt, NULL);
437 if (!NT_STATUS_IS_OK(status)) {
441 dcerpc_set_frag_length(&rep->data, rep->data.length);
443 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
444 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
451 handle a bind request
453 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
455 const char *uuid, *transfer_syntax;
456 uint32_t if_version, transfer_syntax_version;
457 struct dcerpc_packet pkt;
458 struct dcesrv_call_reply *rep;
460 uint32_t result=0, reason=0;
462 const struct dcesrv_interface *iface;
464 if (call->pkt.u.bind.num_contexts != 1 ||
465 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
466 return dcesrv_bind_nak(call, 0);
469 context_id = call->pkt.u.bind.ctx_list[0].context_id;
471 /* you can't bind twice on one context */
472 if (dcesrv_find_context(call->conn, context_id) != NULL) {
473 return dcesrv_bind_nak(call, 0);
476 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
477 uuid = GUID_string(call, &call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid);
479 return dcesrv_bind_nak(call, 0);
482 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
483 transfer_syntax = GUID_string(call,
484 &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid);
485 if (!transfer_syntax ||
486 strcasecmp(NDR_GUID, transfer_syntax) != 0 ||
487 NDR_GUID_VERSION != transfer_syntax_version) {
488 /* we only do NDR encoded dcerpc */
489 return dcesrv_bind_nak(call, 0);
492 iface = find_interface_by_uuid(call->conn->endpoint, uuid, if_version);
494 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
495 /* we don't know about that interface */
496 result = DCERPC_BIND_PROVIDER_REJECT;
497 reason = DCERPC_BIND_REASON_ASYNTAX;
501 /* add this context to the list of available context_ids */
502 struct dcesrv_connection_context *context = talloc(call->conn,
503 struct dcesrv_connection_context);
504 if (context == NULL) {
505 return dcesrv_bind_nak(call, 0);
507 context->conn = call->conn;
508 context->iface = iface;
509 context->context_id = context_id;
510 context->private = NULL;
511 context->handles = NULL;
512 DLIST_ADD(call->conn->contexts, context);
513 call->context = context;
516 if (call->conn->cli_max_recv_frag == 0) {
517 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
520 /* handle any authentication that is being requested */
521 if (!dcesrv_auth_bind(call)) {
522 /* TODO: work out the right reject code */
523 return dcesrv_bind_nak(call, 0);
526 /* setup a bind_ack */
527 dcesrv_init_hdr(&pkt);
529 pkt.call_id = call->pkt.call_id;
530 pkt.ptype = DCERPC_PKT_BIND_ACK;
531 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
532 pkt.u.bind_ack.max_xmit_frag = 0x2000;
533 pkt.u.bind_ack.max_recv_frag = 0x2000;
534 pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
536 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
537 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
539 pkt.u.bind_ack.secondary_address = "";
541 pkt.u.bind_ack.num_results = 1;
542 pkt.u.bind_ack.ctx_list = talloc_p(call, struct dcerpc_ack_ctx);
543 if (!pkt.u.bind_ack.ctx_list) {
544 return NT_STATUS_NO_MEMORY;
546 pkt.u.bind_ack.ctx_list[0].result = result;
547 pkt.u.bind_ack.ctx_list[0].reason = reason;
548 GUID_from_string(NDR_GUID, &pkt.u.bind_ack.ctx_list[0].syntax.uuid);
549 pkt.u.bind_ack.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
550 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
552 if (!dcesrv_auth_bind_ack(call, &pkt)) {
553 return dcesrv_bind_nak(call, 0);
557 status = iface->bind(call, iface);
558 if (!NT_STATUS_IS_OK(status)) {
559 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
560 uuid, if_version, nt_errstr(status)));
561 return dcesrv_bind_nak(call, 0);
565 rep = talloc(call, struct dcesrv_call_reply);
567 return NT_STATUS_NO_MEMORY;
570 status = dcerpc_push_auth(&rep->data, call, &pkt,
571 call->conn->auth_state.auth_info);
572 if (!NT_STATUS_IS_OK(status)) {
576 dcerpc_set_frag_length(&rep->data, rep->data.length);
578 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
579 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
586 handle a auth3 request
588 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
590 /* handle the auth3 in the auth code */
591 if (!dcesrv_auth_auth3(call)) {
592 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
597 /* we don't send a reply to a auth3 request, except by a
604 handle a bind request
606 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32 context_id)
608 uint32_t if_version, transfer_syntax_version;
609 const char *uuid, *transfer_syntax;
610 struct dcesrv_connection_context *context;
611 const struct dcesrv_interface *iface;
613 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
614 uuid = GUID_string(call, &call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid);
616 return NT_STATUS_NO_MEMORY;
619 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
620 transfer_syntax = GUID_string(call,
621 &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid);
622 if (!transfer_syntax ||
623 strcasecmp(NDR_GUID, transfer_syntax) != 0 ||
624 NDR_GUID_VERSION != transfer_syntax_version) {
625 /* we only do NDR encoded dcerpc */
626 return NT_STATUS_NO_MEMORY;
629 iface = find_interface_by_uuid(call->conn->endpoint, uuid, if_version);
631 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
632 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
635 /* add this context to the list of available context_ids */
636 context = talloc(call->conn, struct dcesrv_connection_context);
637 if (context == NULL) {
638 return NT_STATUS_NO_MEMORY;
640 context->conn = call->conn;
641 context->iface = iface;
642 context->context_id = context_id;
643 context->private = NULL;
644 context->handles = NULL;
645 DLIST_ADD(call->conn->contexts, context);
646 call->context = context;
653 handle a bind request
655 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
657 struct dcerpc_packet pkt;
658 struct dcesrv_call_reply *rep;
660 uint32_t result=0, reason=0;
663 /* handle any authentication that is being requested */
664 if (!dcesrv_auth_alter(call)) {
665 /* TODO: work out the right reject code */
666 result = DCERPC_BIND_PROVIDER_REJECT;
667 reason = DCERPC_BIND_REASON_ASYNTAX;
670 context_id = call->pkt.u.alter.ctx_list[0].context_id;
672 /* see if they are asking for a new interface */
674 dcesrv_find_context(call->conn, context_id) == NULL) {
675 status = dcesrv_alter_new_context(call, context_id);
676 if (!NT_STATUS_IS_OK(status)) {
677 result = DCERPC_BIND_PROVIDER_REJECT;
678 reason = DCERPC_BIND_REASON_ASYNTAX;
682 /* setup a alter_resp */
683 dcesrv_init_hdr(&pkt);
685 pkt.call_id = call->pkt.call_id;
686 pkt.ptype = DCERPC_PKT_ALTER_RESP;
687 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
688 pkt.u.alter_resp.max_xmit_frag = 0x2000;
689 pkt.u.alter_resp.max_recv_frag = 0x2000;
690 pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
691 pkt.u.alter_resp.secondary_address = NULL;
692 pkt.u.alter_resp.num_results = 1;
693 pkt.u.alter_resp.ctx_list = talloc_p(call, struct dcerpc_ack_ctx);
694 if (!pkt.u.alter_resp.ctx_list) {
695 return NT_STATUS_NO_MEMORY;
697 pkt.u.alter_resp.ctx_list[0].result = result;
698 pkt.u.alter_resp.ctx_list[0].reason = reason;
699 GUID_from_string(NDR_GUID, &pkt.u.alter_resp.ctx_list[0].syntax.uuid);
700 pkt.u.alter_resp.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
701 pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
702 pkt.u.alter_resp.secondary_address = "";
704 if (!dcesrv_auth_alter_ack(call, &pkt)) {
705 return dcesrv_bind_nak(call, 0);
708 rep = talloc_p(call, struct dcesrv_call_reply);
710 return NT_STATUS_NO_MEMORY;
713 status = dcerpc_push_auth(&rep->data, call, &pkt,
714 call->conn->auth_state.auth_info);
715 if (!NT_STATUS_IS_OK(status)) {
719 dcerpc_set_frag_length(&rep->data, rep->data.length);
721 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
722 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
728 handle a dcerpc request packet
730 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
732 struct ndr_pull *pull;
733 struct ndr_push *push;
737 uint32_t total_length;
738 struct dcesrv_connection_context *context;
740 call->fault_code = 0;
742 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
743 if (context == NULL) {
744 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
747 call->context = context;
749 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
751 return NT_STATUS_NO_MEMORY;
754 if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_ORPC) {
755 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
758 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
759 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
762 /* unravel the NDR for the packet */
763 status = context->iface->ndr_pull(call, call, pull, &r);
764 if (!NT_STATUS_IS_OK(status)) {
765 return dcesrv_fault(call, call->fault_code);
768 if (pull->offset != pull->data_size) {
769 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
770 pull->data_size - pull->offset));
771 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
774 /* call the dispatch function */
775 status = context->iface->dispatch(call, call, r);
776 if (!NT_STATUS_IS_OK(status)) {
777 return dcesrv_fault(call, call->fault_code);
780 /* form the reply NDR */
781 push = ndr_push_init_ctx(call);
783 return NT_STATUS_NO_MEMORY;
786 /* carry over the pointer count to the reply in case we are
787 using full pointer. See NDR specification for full
789 push->ptr_count = pull->ptr_count;
791 if (lp_rpc_big_endian()) {
792 push->flags |= LIBNDR_FLAG_BIGENDIAN;
795 status = context->iface->ndr_push(call, call, push, r);
796 if (!NT_STATUS_IS_OK(status)) {
797 return dcesrv_fault(call, call->fault_code);
800 stub = ndr_push_blob(push);
802 total_length = stub.length;
806 struct dcesrv_call_reply *rep;
807 struct dcerpc_packet pkt;
809 rep = talloc(call, struct dcesrv_call_reply);
811 return NT_STATUS_NO_MEMORY;
814 length = stub.length;
815 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
816 /* the 32 is to cope with signing data */
817 length = call->conn->cli_max_recv_frag -
818 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
821 /* form the dcerpc response packet */
822 dcesrv_init_hdr(&pkt);
824 pkt.call_id = call->pkt.call_id;
825 pkt.ptype = DCERPC_PKT_RESPONSE;
827 if (stub.length == total_length) {
828 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
830 if (length == stub.length) {
831 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
833 pkt.u.response.alloc_hint = stub.length;
834 pkt.u.response.context_id = call->pkt.u.request.context_id;
835 pkt.u.response.cancel_count = 0;
836 pkt.u.response.stub_and_verifier.data = stub.data;
837 pkt.u.response.stub_and_verifier.length = length;
839 if (!dcesrv_auth_response(call, &rep->data, &pkt)) {
840 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
843 dcerpc_set_frag_length(&rep->data, rep->data.length);
845 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
848 stub.length -= length;
849 } while (stub.length != 0);
851 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
858 work out if we have a full packet yet
860 static BOOL dce_full_packet(const DATA_BLOB *data)
862 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
865 if (dcerpc_get_frag_length(data) > data->length) {
872 we might have consumed only part of our input - advance past that part
874 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
878 if (dce_conn->partial_input.length == offset) {
879 data_blob_free(&dce_conn->partial_input);
883 blob = dce_conn->partial_input;
884 dce_conn->partial_input = data_blob(blob.data + offset,
885 blob.length - offset);
886 data_blob_free(&blob);
890 process some input to a dcerpc endpoint server.
892 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
894 struct ndr_pull *ndr;
896 struct dcesrv_call_state *call;
899 call = talloc(dce_conn, struct dcesrv_call_state);
901 talloc_free(dce_conn->partial_input.data);
902 return NT_STATUS_NO_MEMORY;
904 call->conn = dce_conn;
905 call->replies = NULL;
906 call->context = NULL;
908 blob = dce_conn->partial_input;
909 blob.length = dcerpc_get_frag_length(&blob);
911 ndr = ndr_pull_init_blob(&blob, call);
913 talloc_free(dce_conn->partial_input.data);
915 return NT_STATUS_NO_MEMORY;
918 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
919 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
922 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
923 if (!NT_STATUS_IS_OK(status)) {
924 talloc_free(dce_conn->partial_input.data);
929 /* we have to check the signing here, before combining the
931 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
932 !dcesrv_auth_request(call, &blob)) {
933 dce_partial_advance(dce_conn, blob.length);
934 return dcesrv_fault(call, DCERPC_FAULT_LOGON_FAILURE);
937 dce_partial_advance(dce_conn, blob.length);
939 /* see if this is a continued packet */
940 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
941 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
942 struct dcesrv_call_state *call2 = call;
945 /* we only allow fragmented requests, no other packet types */
946 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
947 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
950 /* this is a continuation of an existing call - find the call then
951 tack it on the end */
952 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
954 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
957 if (call->pkt.ptype != call2->pkt.ptype) {
958 /* trying to play silly buggers are we? */
959 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
962 alloc_size = call->pkt.u.request.stub_and_verifier.length +
963 call2->pkt.u.request.stub_and_verifier.length;
964 if (call->pkt.u.request.alloc_hint > alloc_size) {
965 alloc_size = call->pkt.u.request.alloc_hint;
968 call->pkt.u.request.stub_and_verifier.data =
970 call->pkt.u.request.stub_and_verifier.data,
971 uint8_t, alloc_size);
972 if (!call->pkt.u.request.stub_and_verifier.data) {
973 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
975 memcpy(call->pkt.u.request.stub_and_verifier.data +
976 call->pkt.u.request.stub_and_verifier.length,
977 call2->pkt.u.request.stub_and_verifier.data,
978 call2->pkt.u.request.stub_and_verifier.length);
979 call->pkt.u.request.stub_and_verifier.length +=
980 call2->pkt.u.request.stub_and_verifier.length;
982 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
987 /* this may not be the last pdu in the chain - if its isn't then
988 just put it on the call_list and wait for the rest */
989 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
990 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
991 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
995 switch (call->pkt.ptype) {
996 case DCERPC_PKT_BIND:
997 status = dcesrv_bind(call);
999 case DCERPC_PKT_AUTH3:
1000 status = dcesrv_auth3(call);
1002 case DCERPC_PKT_ALTER:
1003 status = dcesrv_alter(call);
1005 case DCERPC_PKT_REQUEST:
1006 status = dcesrv_request(call);
1009 status = NT_STATUS_INVALID_PARAMETER;
1013 /* if we are going to be sending a reply then add
1014 it to the list of pending calls. We add it to the end to keep the call
1015 list in the order we will answer */
1016 if (!NT_STATUS_IS_OK(status)) {
1025 provide some input to a dcerpc endpoint server. This passes data
1026 from a dcerpc client into the server
1028 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
1032 dce_conn->partial_input.data = talloc_realloc(dce_conn,
1033 dce_conn->partial_input.data,
1035 dce_conn->partial_input.length + data->length);
1036 if (!dce_conn->partial_input.data) {
1037 return NT_STATUS_NO_MEMORY;
1039 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1040 data->data, data->length);
1041 dce_conn->partial_input.length += data->length;
1043 while (dce_full_packet(&dce_conn->partial_input)) {
1044 status = dcesrv_input_process(dce_conn);
1045 if (!NT_STATUS_IS_OK(status)) {
1050 return NT_STATUS_OK;
1054 retrieve some output from a dcerpc server
1055 The caller supplies a function that will be called to do the
1058 The first argument to write_fn() will be 'private', the second will
1059 be a pointer to a buffer containing the data to be sent and the 3rd
1060 will be the number of bytes to be sent.
1062 write_fn() should return the number of bytes successfully written.
1064 this will return STATUS_BUFFER_OVERFLOW if there is more to be read
1065 from the current fragment
1067 NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
1069 ssize_t (*write_fn)(void *, DATA_BLOB *))
1071 struct dcesrv_call_state *call;
1072 struct dcesrv_call_reply *rep;
1075 call = dce_conn->call_list;
1076 if (!call || !call->replies) {
1077 return NT_STATUS_FOOBAR;
1079 rep = call->replies;
1081 nwritten = write_fn(private, &rep->data);
1082 if (nwritten == -1) {
1083 /* TODO: hmm, how do we cope with this? destroy the
1084 connection perhaps? */
1085 return NT_STATUS_UNSUCCESSFUL;
1088 rep->data.length -= nwritten;
1089 rep->data.data += nwritten;
1091 if (rep->data.length == 0) {
1092 /* we're done with this section of the call */
1093 DLIST_REMOVE(call->replies, rep);
1095 return STATUS_BUFFER_OVERFLOW;
1098 if (call->replies == NULL) {
1099 /* we're done with the whole call */
1100 DLIST_REMOVE(dce_conn->call_list, call);
1104 return NT_STATUS_OK;
1109 write_fn() for dcesrv_output_blob()
1111 static ssize_t dcesrv_output_blob_write_fn(void *private, DATA_BLOB *out)
1113 DATA_BLOB *blob = private;
1114 if (out->length < blob->length) {
1115 blob->length = out->length;
1117 memcpy(blob->data, out->data, blob->length);
1118 return blob->length;
1122 a simple wrapper for dcesrv_output() for when we want to output
1125 NTSTATUS dcesrv_output_blob(struct dcesrv_connection *dce_conn,
1128 return dcesrv_output(dce_conn, blob, dcesrv_output_blob_write_fn);
1132 initialise the dcerpc server context
1134 NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **dce_ctx)
1137 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
1139 (*dce_ctx) = talloc_p(mem_ctx, struct dcesrv_context);
1141 return NT_STATUS_NO_MEMORY;
1144 (*dce_ctx)->endpoint_list = NULL;
1146 if (!endpoint_servers) {
1147 DEBUG(3,("dcesrv_init_context: no endpoint servers configured\n"));
1148 return NT_STATUS_OK;
1151 for (i=0;endpoint_servers[i];i++) {
1153 const struct dcesrv_endpoint_server *ep_server;
1155 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1157 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1158 return NT_STATUS_UNSUCCESSFUL;
1161 ret = ep_server->init_server(*dce_ctx, ep_server);
1162 if (!NT_STATUS_IS_OK(ret)) {
1163 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1168 return NT_STATUS_OK;
1171 static void dcesrv_init(struct server_service *service, const struct model_ops *model_ops)
1173 struct dcesrv_context *dce_ctx;
1175 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
1177 DEBUG(1,("dcesrv_init\n"));
1179 if (!endpoint_servers) {
1180 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1184 dce_ctx = talloc_p(service, struct dcesrv_context);
1186 DEBUG(0,("talloc_p(mem_ctx, struct dcesrv_context) failed\n"));
1190 ZERO_STRUCTP(dce_ctx);
1191 dce_ctx->endpoint_list = NULL;
1193 for (i=0;endpoint_servers[i];i++) {
1195 const struct dcesrv_endpoint_server *ep_server;
1197 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1199 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1203 ret = ep_server->init_server(dce_ctx, ep_server);
1204 if (!NT_STATUS_IS_OK(ret)) {
1205 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1210 dcesrv_sock_init(service, model_ops, dce_ctx);
1215 static void dcesrv_accept(struct server_connection *srv_conn)
1217 dcesrv_sock_accept(srv_conn);
1220 static void dcesrv_recv(struct server_connection *srv_conn,
1221 struct timeval t, uint16_t flags)
1223 dcesrv_sock_recv(srv_conn, t, flags);
1226 static void dcesrv_send(struct server_connection *srv_conn,
1227 struct timeval t, uint16_t flags)
1229 dcesrv_sock_send(srv_conn, t, flags);
1232 static void dcesrv_close(struct server_connection *srv_conn, const char *reason)
1234 dcesrv_sock_close(srv_conn, reason);
1238 static void dcesrv_exit(struct server_service *service, const char *reason)
1240 dcesrv_sock_exit(service, reason);
1244 /* the list of currently registered DCERPC endpoint servers.
1246 static struct ep_server {
1247 struct dcesrv_endpoint_server *ep_server;
1248 } *ep_servers = NULL;
1249 static int num_ep_servers;
1252 register a DCERPC endpoint server.
1254 The 'name' can be later used by other backends to find the operations
1255 structure for this backend.
1257 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1259 NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1261 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1263 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1264 /* its already registered! */
1265 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1267 return NT_STATUS_OBJECT_NAME_COLLISION;
1270 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1272 smb_panic("out of memory in dcerpc_register");
1275 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1276 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1280 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1283 return NT_STATUS_OK;
1287 return the operations structure for a named backend of the specified type
1289 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1293 for (i=0;i<num_ep_servers;i++) {
1294 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1295 return ep_servers[i].ep_server;
1303 return the DCERPC module version, and the size of some critical types
1304 This can be used by endpoint server modules to either detect compilation errors, or provide
1305 multiple implementations for different smbd compilation options in one module
1307 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1309 static const struct dcesrv_critical_sizes critical_sizes = {
1310 DCERPC_MODULE_VERSION,
1311 sizeof(struct dcesrv_context),
1312 sizeof(struct dcesrv_endpoint),
1313 sizeof(struct dcesrv_endpoint_server),
1314 sizeof(struct dcesrv_interface),
1315 sizeof(struct dcesrv_if_list),
1316 sizeof(struct dcesrv_connection),
1317 sizeof(struct dcesrv_call_state),
1318 sizeof(struct dcesrv_auth),
1319 sizeof(struct dcesrv_handle)
1322 return &critical_sizes;
1325 static const struct server_service_ops dcesrv_ops = {
1327 .service_init = dcesrv_init,
1328 .accept_connection = dcesrv_accept,
1329 .recv_handler = dcesrv_recv,
1330 .send_handler = dcesrv_send,
1331 .idle_handler = NULL,
1332 .close_connection = dcesrv_close,
1333 .service_exit = dcesrv_exit,
1336 const struct server_service_ops *dcesrv_get_ops(void)
1341 NTSTATUS server_service_rpc_init(void)
1343 return NT_STATUS_OK;