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 see if a uuid and if_version match to an interface
69 static BOOL interface_match(const struct dcesrv_interface *if1,
70 const struct dcesrv_interface *if2)
72 if (if1->ndr->if_version != if2->ndr->if_version) {
76 if (strcmp(if1->ndr->uuid, if2->ndr->uuid)==0) {
84 find the interface operations on an endpoint
86 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
87 const struct dcesrv_interface *iface)
89 struct dcesrv_if_list *ifl;
90 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
91 if (interface_match(&(ifl->iface), iface)) {
99 see if a uuid and if_version match to an interface
101 static BOOL interface_match_by_uuid(const struct dcesrv_interface *iface,
102 const char *uuid, uint32_t if_version)
104 if (iface->ndr->if_version != if_version) {
108 if (strcmp(iface->ndr->uuid, uuid)==0) {
116 find the interface operations on an endpoint by uuid
118 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
119 const char *uuid, uint32_t if_version)
121 struct dcesrv_if_list *ifl;
122 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
123 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
124 return &(ifl->iface);
131 find a call that is pending in our call list
133 static struct dcesrv_call_state *dcesrv_find_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
135 struct dcesrv_call_state *c;
136 for (c=dce_conn->call_list;c;c=c->next) {
137 if (c->pkt.call_id == call_id) {
145 register an interface on an endpoint
147 NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
149 const struct dcesrv_interface *iface,
150 const struct security_descriptor *sd)
152 struct dcesrv_endpoint *ep;
153 struct dcesrv_if_list *ifl;
154 struct dcerpc_binding binding;
158 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
160 if (NT_STATUS_IS_ERR(status)) {
161 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
165 /* check if this endpoint exists
167 if ((ep=find_endpoint(dce_ctx, &binding))==NULL) {
168 ep = talloc_p(dce_ctx, struct dcesrv_endpoint);
170 return NT_STATUS_NO_MEMORY;
173 ep->ep_description = binding;
177 /* see if the interface is already registered on te endpoint */
178 if (find_interface(ep, iface)!=NULL) {
179 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
180 iface->ndr->name, ep_name));
181 return NT_STATUS_OBJECT_NAME_COLLISION;
184 /* talloc a new interface list element */
185 ifl = talloc_p(dce_ctx, struct dcesrv_if_list);
187 return NT_STATUS_NO_MEMORY;
190 /* copy the given interface struct to the one on the endpoints interface list */
191 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
193 /* if we have a security descriptor given,
194 * we should see if we can set it up on the endpoint
197 /* if there's currently no security descriptor given on the endpoint
200 if (ep->sd == NULL) {
201 ep->sd = security_descriptor_copy(dce_ctx, sd);
204 /* if now there's no security descriptor given on the endpoint
205 * something goes wrong, either we failed to copy the security descriptor
206 * or there was already one on the endpoint
208 if (ep->sd != NULL) {
209 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
210 " on endpoint '%s'\n",
211 iface->ndr->name, ep_name));
212 if (add_ep) free(ep);
214 return NT_STATUS_OBJECT_NAME_COLLISION;
218 /* finally add the interface on the endpoint */
219 DLIST_ADD(ep->interface_list, ifl);
221 /* if it's a new endpoint add it to the dcesrv_context */
223 DLIST_ADD(dce_ctx->endpoint_list, ep);
226 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
227 iface->ndr->name, ep_name));
232 static NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
233 DATA_BLOB *session_key)
235 if (p->auth_state.session_info->session_key.length) {
236 *session_key = p->auth_state.session_info->session_key;
239 return NT_STATUS_NO_USER_SESSION_KEY;
242 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
243 DATA_BLOB *session_key)
245 /* this took quite a few CPU cycles to find ... */
246 session_key->data = discard_const_p(uint8_t, "SystemLibraryDTC");
247 session_key->length = 16;
252 fetch the user session key - may be default (above) or the SMB session key
254 NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
255 DATA_BLOB *session_key)
257 return p->auth_state.session_key(p, session_key);
262 destroy a link to an endpoint
264 static int dcesrv_endpoint_destructor(void *ptr)
266 struct dcesrv_connection *p = ptr;
268 p->iface->unbind(p, p->iface);
271 /* destroy any handles */
273 dcesrv_handle_destroy(p, p->handles);
276 if (p->auth_state.gensec_security) {
277 gensec_end(&p->auth_state.gensec_security);
285 connect to a dcerpc endpoint
287 NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
288 const struct dcesrv_endpoint *ep,
289 struct dcesrv_connection **p)
291 *p = talloc_p(dce_ctx, struct dcesrv_connection);
293 return NT_STATUS_NO_MEMORY;
296 (*p)->dce_ctx = dce_ctx;
299 (*p)->private = NULL;
300 (*p)->call_list = NULL;
301 (*p)->cli_max_recv_frag = 0;
302 (*p)->handles = NULL;
303 (*p)->partial_input = data_blob(NULL, 0);
304 (*p)->auth_state.auth_info = NULL;
305 (*p)->auth_state.gensec_security = NULL;
306 (*p)->auth_state.session_info = NULL;
307 (*p)->auth_state.session_key = dcesrv_generic_session_key;
308 (*p)->srv_conn = NULL;
310 talloc_set_destructor(*p, dcesrv_endpoint_destructor);
316 search and connect to a dcerpc endpoint
318 NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
319 const struct dcerpc_binding *ep_description,
320 struct auth_session_info *session_info,
321 struct dcesrv_connection **dce_conn_p)
324 const struct dcesrv_endpoint *ep;
326 /* make sure this endpoint exists */
327 ep = find_endpoint(dce_ctx, ep_description);
329 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
332 status = dcesrv_endpoint_connect(dce_ctx, ep, dce_conn_p);
333 if (!NT_STATUS_IS_OK(status)) {
337 session_info->refcount++;
338 (*dce_conn_p)->auth_state.session_info = session_info;
339 (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
341 /* TODO: check security descriptor of the endpoint here
342 * if it's a smb named pipe
343 * if it's failed free dce_conn_p
350 static void dcesrv_init_hdr(struct dcerpc_packet *pkt)
353 pkt->rpc_vers_minor = 0;
354 if (lp_rpc_big_endian()) {
357 pkt->drep[0] = DCERPC_DREP_LE;
365 return a dcerpc fault
367 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
369 struct dcerpc_packet pkt;
370 struct dcesrv_call_reply *rep;
373 /* setup a bind_ack */
374 dcesrv_init_hdr(&pkt);
376 pkt.call_id = call->pkt.call_id;
377 pkt.ptype = DCERPC_PKT_FAULT;
378 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
379 pkt.u.fault.alloc_hint = 0;
380 pkt.u.fault.context_id = 0;
381 pkt.u.fault.cancel_count = 0;
382 pkt.u.fault.status = fault_code;
384 rep = talloc_p(call, struct dcesrv_call_reply);
386 return NT_STATUS_NO_MEMORY;
389 status = dcerpc_push_auth(&rep->data, call, &pkt, NULL);
390 if (!NT_STATUS_IS_OK(status)) {
394 dcerpc_set_frag_length(&rep->data, rep->data.length);
396 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
397 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
404 return a dcerpc bind_nak
406 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
408 struct dcerpc_packet pkt;
409 struct dcesrv_call_reply *rep;
412 /* setup a bind_nak */
413 dcesrv_init_hdr(&pkt);
415 pkt.call_id = call->pkt.call_id;
416 pkt.ptype = DCERPC_PKT_BIND_NAK;
417 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
418 pkt.u.bind_nak.reject_reason = reason;
419 pkt.u.bind_nak.num_versions = 0;
421 rep = talloc_p(call, struct dcesrv_call_reply);
423 return NT_STATUS_NO_MEMORY;
426 status = dcerpc_push_auth(&rep->data, call, &pkt, NULL);
427 if (!NT_STATUS_IS_OK(status)) {
431 dcerpc_set_frag_length(&rep->data, rep->data.length);
433 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
434 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
441 handle a bind request
443 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
445 const char *uuid, *transfer_syntax;
446 uint32_t if_version, transfer_syntax_version;
447 struct dcerpc_packet pkt;
448 struct dcesrv_call_reply *rep;
450 uint32_t result=0, reason=0;
452 if (call->pkt.u.bind.num_contexts != 1 ||
453 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
454 return dcesrv_bind_nak(call, 0);
457 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
458 uuid = GUID_string(call, &call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid);
460 return dcesrv_bind_nak(call, 0);
463 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
464 transfer_syntax = GUID_string(call,
465 &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid);
466 if (!transfer_syntax ||
467 strcasecmp(NDR_GUID, transfer_syntax) != 0 ||
468 NDR_GUID_VERSION != transfer_syntax_version) {
469 /* we only do NDR encoded dcerpc */
470 return dcesrv_bind_nak(call, 0);
473 call->conn->iface = find_interface_by_uuid(call->conn->endpoint, uuid, if_version);
474 if (!call->conn->iface) {
475 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
476 /* we don't know about that interface */
477 result = DCERPC_BIND_PROVIDER_REJECT;
478 reason = DCERPC_BIND_REASON_ASYNTAX;
481 if (call->conn->cli_max_recv_frag == 0) {
482 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
485 /* handle any authentication that is being requested */
486 if (!dcesrv_auth_bind(call)) {
487 /* TODO: work out the right reject code */
488 return dcesrv_bind_nak(call, 0);
491 /* setup a bind_ack */
492 dcesrv_init_hdr(&pkt);
494 pkt.call_id = call->pkt.call_id;
495 pkt.ptype = DCERPC_PKT_BIND_ACK;
496 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
497 pkt.u.bind_ack.max_xmit_frag = 0x2000;
498 pkt.u.bind_ack.max_recv_frag = 0x2000;
499 pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
500 if (call->conn->iface && call->conn->iface->ndr) {
501 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
502 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s",
503 call->conn->iface->ndr->name);
505 pkt.u.bind_ack.secondary_address = "";
507 pkt.u.bind_ack.num_results = 1;
508 pkt.u.bind_ack.ctx_list = talloc_p(call, struct dcerpc_ack_ctx);
509 if (!pkt.u.bind_ack.ctx_list) {
510 return NT_STATUS_NO_MEMORY;
512 pkt.u.bind_ack.ctx_list[0].result = result;
513 pkt.u.bind_ack.ctx_list[0].reason = reason;
514 GUID_from_string(NDR_GUID, &pkt.u.bind_ack.ctx_list[0].syntax.uuid);
515 pkt.u.bind_ack.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
516 pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
518 if (!dcesrv_auth_bind_ack(call, &pkt)) {
519 return dcesrv_bind_nak(call, 0);
522 if (call->conn->iface) {
523 status = call->conn->iface->bind(call, call->conn->iface);
524 if (!NT_STATUS_IS_OK(status)) {
525 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n", uuid, if_version, nt_errstr(status)));
526 return dcesrv_bind_nak(call, 0);
530 rep = talloc_p(call, struct dcesrv_call_reply);
532 return NT_STATUS_NO_MEMORY;
535 status = dcerpc_push_auth(&rep->data, call, &pkt,
536 call->conn->auth_state.auth_info);
537 if (!NT_STATUS_IS_OK(status)) {
541 dcerpc_set_frag_length(&rep->data, rep->data.length);
543 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
544 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
551 handle a auth3 request
553 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
555 /* handle the auth3 in the auth code */
556 if (!dcesrv_auth_auth3(call)) {
557 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
562 /* we don't send a reply to a auth3 request, except by a
568 handle a bind request
570 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
572 struct dcerpc_packet pkt;
573 struct dcesrv_call_reply *rep;
575 uint32_t result=0, reason=0;
577 /* handle any authentication that is being requested */
578 if (!dcesrv_auth_alter(call)) {
579 /* TODO: work out the right reject code */
580 return dcesrv_bind_nak(call, 0);
583 /* setup a alter_ack */
584 dcesrv_init_hdr(&pkt);
586 pkt.call_id = call->pkt.call_id;
587 pkt.ptype = DCERPC_PKT_ALTER_ACK;
588 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
589 pkt.u.alter_ack.max_xmit_frag = 0x2000;
590 pkt.u.alter_ack.max_recv_frag = 0x2000;
591 pkt.u.alter_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
592 pkt.u.alter_ack.secondary_address = NULL;
593 pkt.u.alter_ack.num_results = 1;
594 pkt.u.alter_ack.ctx_list = talloc_p(call, struct dcerpc_ack_ctx);
595 if (!pkt.u.alter_ack.ctx_list) {
596 return NT_STATUS_NO_MEMORY;
598 pkt.u.alter_ack.ctx_list[0].result = result;
599 pkt.u.alter_ack.ctx_list[0].reason = reason;
600 GUID_from_string(NDR_GUID, &pkt.u.alter_ack.ctx_list[0].syntax.uuid);
601 pkt.u.alter_ack.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
602 pkt.u.alter_ack.auth_info = data_blob(NULL, 0);
604 if (!dcesrv_auth_alter_ack(call, &pkt)) {
605 return dcesrv_bind_nak(call, 0);
608 rep = talloc_p(call, struct dcesrv_call_reply);
610 return NT_STATUS_NO_MEMORY;
613 status = dcerpc_push_auth(&rep->data, call, &pkt,
614 call->conn->auth_state.auth_info);
615 if (!NT_STATUS_IS_OK(status)) {
619 dcerpc_set_frag_length(&rep->data, rep->data.length);
621 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
622 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
628 handle a dcerpc request packet
630 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
632 struct ndr_pull *pull;
633 struct ndr_push *push;
638 uint32_t total_length;
641 if (!call->conn->iface) {
642 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
645 opnum = call->pkt.u.request.opnum;
647 if (opnum >= call->conn->iface->ndr->num_calls) {
648 return dcesrv_fault(call, DCERPC_FAULT_OP_RNG_ERROR);
651 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
653 return NT_STATUS_NO_MEMORY;
656 if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_ORPC) {
657 pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
660 r = talloc(call, call->conn->iface->ndr->calls[opnum].struct_size);
662 return NT_STATUS_NO_MEMORY;
665 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
666 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
669 /* unravel the NDR for the packet */
670 status = call->conn->iface->ndr->calls[opnum].ndr_pull(pull, NDR_IN, r);
671 if (!NT_STATUS_IS_OK(status)) {
672 dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN,
673 &call->pkt.u.request.stub_and_verifier);
674 return dcesrv_fault(call, DCERPC_FAULT_NDR);
677 if (pull->offset != pull->data_size) {
678 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
679 pull->data_size - pull->offset));
680 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
683 call->fault_code = 0;
685 /* call the dispatch function */
686 status = call->conn->iface->dispatch(call, call, r);
687 if (!NT_STATUS_IS_OK(status)) {
688 dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN,
689 &call->pkt.u.request.stub_and_verifier);
690 return dcesrv_fault(call, call->fault_code);
693 /* form the reply NDR */
694 push = ndr_push_init_ctx(call);
696 return NT_STATUS_NO_MEMORY;
699 /* carry over the pointer count to the reply in case we are
700 using full pointer. See NDR specification for full
702 push->ptr_count = pull->ptr_count;
704 if (lp_rpc_big_endian()) {
705 push->flags |= LIBNDR_FLAG_BIGENDIAN;
708 status = call->conn->iface->ndr->calls[opnum].ndr_push(push, NDR_OUT, r);
709 if (!NT_STATUS_IS_OK(status)) {
710 return dcesrv_fault(call, DCERPC_FAULT_NDR);
713 stub = ndr_push_blob(push);
715 total_length = stub.length;
719 struct dcesrv_call_reply *rep;
720 struct dcerpc_packet pkt;
722 rep = talloc_p(call, struct dcesrv_call_reply);
724 return NT_STATUS_NO_MEMORY;
727 length = stub.length;
728 if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
729 /* the 32 is to cope with signing data */
730 length = call->conn->cli_max_recv_frag -
731 (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
734 /* form the dcerpc response packet */
735 dcesrv_init_hdr(&pkt);
737 pkt.call_id = call->pkt.call_id;
738 pkt.ptype = DCERPC_PKT_RESPONSE;
740 if (stub.length == total_length) {
741 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
743 if (length == stub.length) {
744 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
746 pkt.u.response.alloc_hint = stub.length;
747 pkt.u.response.context_id = call->pkt.u.request.context_id;
748 pkt.u.response.cancel_count = 0;
749 pkt.u.response.stub_and_verifier.data = stub.data;
750 pkt.u.response.stub_and_verifier.length = length;
752 if (!dcesrv_auth_response(call, &rep->data, &pkt)) {
753 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
756 dcerpc_set_frag_length(&rep->data, rep->data.length);
758 DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
761 stub.length -= length;
762 } while (stub.length != 0);
764 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
771 work out if we have a full packet yet
773 static BOOL dce_full_packet(const DATA_BLOB *data)
775 if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
778 if (dcerpc_get_frag_length(data) > data->length) {
785 we might have consumed only part of our input - advance past that part
787 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
791 if (dce_conn->partial_input.length == offset) {
792 data_blob_free(&dce_conn->partial_input);
796 blob = dce_conn->partial_input;
797 dce_conn->partial_input = data_blob(blob.data + offset,
798 blob.length - offset);
799 data_blob_free(&blob);
803 process some input to a dcerpc endpoint server.
805 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
807 struct ndr_pull *ndr;
809 struct dcesrv_call_state *call;
812 call = talloc_p(dce_conn, struct dcesrv_call_state);
814 talloc_free(dce_conn->partial_input.data);
815 return NT_STATUS_NO_MEMORY;
817 call->conn = dce_conn;
818 call->replies = NULL;
820 blob = dce_conn->partial_input;
821 blob.length = dcerpc_get_frag_length(&blob);
823 ndr = ndr_pull_init_blob(&blob, call);
825 talloc_free(dce_conn->partial_input.data);
827 return NT_STATUS_NO_MEMORY;
830 if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
831 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
834 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
835 if (!NT_STATUS_IS_OK(status)) {
836 talloc_free(dce_conn->partial_input.data);
841 /* we have to check the signing here, before combining the
843 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
844 !dcesrv_auth_request(call, &blob)) {
845 dce_partial_advance(dce_conn, blob.length);
846 return dcesrv_fault(call, DCERPC_FAULT_LOGON_FAILURE);
849 dce_partial_advance(dce_conn, blob.length);
851 /* see if this is a continued packet */
852 if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
853 struct dcesrv_call_state *call2 = call;
856 /* we only allow fragmented requests, no other packet types */
857 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
858 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
861 /* this is a continuation of an existing call - find the call then
862 tack it on the end */
863 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
865 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
868 if (call->pkt.ptype != call2->pkt.ptype) {
869 /* trying to play silly buggers are we? */
870 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
873 alloc_size = call->pkt.u.request.stub_and_verifier.length +
874 call2->pkt.u.request.stub_and_verifier.length;
875 if (call->pkt.u.request.alloc_hint > alloc_size) {
876 alloc_size = call->pkt.u.request.alloc_hint;
879 call->pkt.u.request.stub_and_verifier.data =
880 talloc_realloc(call, call->pkt.u.request.stub_and_verifier.data, alloc_size);
881 if (!call->pkt.u.request.stub_and_verifier.data) {
882 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
884 memcpy(call->pkt.u.request.stub_and_verifier.data +
885 call->pkt.u.request.stub_and_verifier.length,
886 call2->pkt.u.request.stub_and_verifier.data,
887 call2->pkt.u.request.stub_and_verifier.length);
888 call->pkt.u.request.stub_and_verifier.length +=
889 call2->pkt.u.request.stub_and_verifier.length;
891 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
896 /* this may not be the last pdu in the chain - if its isn't then
897 just put it on the call_list and wait for the rest */
898 if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
899 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
903 switch (call->pkt.ptype) {
904 case DCERPC_PKT_BIND:
905 status = dcesrv_bind(call);
907 case DCERPC_PKT_AUTH3:
908 status = dcesrv_auth3(call);
910 case DCERPC_PKT_ALTER:
911 status = dcesrv_alter(call);
913 case DCERPC_PKT_REQUEST:
914 status = dcesrv_request(call);
917 status = NT_STATUS_INVALID_PARAMETER;
921 /* if we are going to be sending a reply then add
922 it to the list of pending calls. We add it to the end to keep the call
923 list in the order we will answer */
924 if (!NT_STATUS_IS_OK(status)) {
933 provide some input to a dcerpc endpoint server. This passes data
934 from a dcerpc client into the server
936 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
940 dce_conn->partial_input.data = talloc_realloc(dce_conn,
941 dce_conn->partial_input.data,
942 dce_conn->partial_input.length + data->length);
943 if (!dce_conn->partial_input.data) {
944 return NT_STATUS_NO_MEMORY;
946 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
947 data->data, data->length);
948 dce_conn->partial_input.length += data->length;
950 while (dce_full_packet(&dce_conn->partial_input)) {
951 status = dcesrv_input_process(dce_conn);
952 if (!NT_STATUS_IS_OK(status)) {
961 retrieve some output from a dcerpc server
962 The caller supplies a function that will be called to do the
965 The first argument to write_fn() will be 'private', the second will
966 be a pointer to a buffer containing the data to be sent and the 3rd
967 will be the number of bytes to be sent.
969 write_fn() should return the number of bytes successfully written.
971 this will return STATUS_BUFFER_OVERFLOW if there is more to be read
972 from the current fragment
974 NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
976 ssize_t (*write_fn)(void *, DATA_BLOB *))
978 struct dcesrv_call_state *call;
979 struct dcesrv_call_reply *rep;
982 call = dce_conn->call_list;
983 if (!call || !call->replies) {
984 return NT_STATUS_FOOBAR;
988 nwritten = write_fn(private, &rep->data);
989 if (nwritten == -1) {
990 /* TODO: hmm, how do we cope with this? destroy the
991 connection perhaps? */
992 return NT_STATUS_UNSUCCESSFUL;
995 rep->data.length -= nwritten;
996 rep->data.data += nwritten;
998 if (rep->data.length == 0) {
999 /* we're done with this section of the call */
1000 DLIST_REMOVE(call->replies, rep);
1003 if (call->replies == NULL) {
1004 /* we're done with the whole call */
1005 DLIST_REMOVE(dce_conn->call_list, call);
1009 return NT_STATUS_OK;
1014 write_fn() for dcesrv_output_blob()
1016 static ssize_t dcesrv_output_blob_write_fn(void *private, DATA_BLOB *out)
1018 DATA_BLOB *blob = private;
1019 if (out->length < blob->length) {
1020 blob->length = out->length;
1022 memcpy(blob->data, out->data, blob->length);
1023 return blob->length;
1027 a simple wrapper for dcesrv_output() for when we want to output
1030 NTSTATUS dcesrv_output_blob(struct dcesrv_connection *dce_conn,
1033 return dcesrv_output(dce_conn, blob, dcesrv_output_blob_write_fn);
1037 initialise the dcerpc server context
1039 NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **dce_ctx)
1042 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
1044 (*dce_ctx) = talloc_p(mem_ctx, struct dcesrv_context);
1046 return NT_STATUS_NO_MEMORY;
1049 (*dce_ctx)->endpoint_list = NULL;
1051 if (!endpoint_servers) {
1052 DEBUG(3,("dcesrv_init_context: no endpoint servers configured\n"));
1053 return NT_STATUS_OK;
1056 for (i=0;endpoint_servers[i];i++) {
1058 const struct dcesrv_endpoint_server *ep_server;
1060 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1062 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1063 return NT_STATUS_UNSUCCESSFUL;
1066 ret = ep_server->init_server(*dce_ctx, ep_server);
1067 if (!NT_STATUS_IS_OK(ret)) {
1068 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1073 return NT_STATUS_OK;
1076 static void dcesrv_init(struct server_service *service, const struct model_ops *model_ops)
1078 struct dcesrv_context *dce_ctx;
1080 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
1082 DEBUG(1,("dcesrv_init\n"));
1084 if (!endpoint_servers) {
1085 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1089 dce_ctx = talloc_p(service, struct dcesrv_context);
1091 DEBUG(0,("talloc_p(mem_ctx, struct dcesrv_context) failed\n"));
1095 ZERO_STRUCTP(dce_ctx);
1096 dce_ctx->endpoint_list = NULL;
1098 for (i=0;endpoint_servers[i];i++) {
1100 const struct dcesrv_endpoint_server *ep_server;
1102 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1104 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1108 ret = ep_server->init_server(dce_ctx, ep_server);
1109 if (!NT_STATUS_IS_OK(ret)) {
1110 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1115 dcesrv_sock_init(service, model_ops, dce_ctx);
1120 static void dcesrv_accept(struct server_connection *srv_conn)
1122 dcesrv_sock_accept(srv_conn);
1125 static void dcesrv_recv(struct server_connection *srv_conn,
1126 struct timeval t, uint16_t flags)
1128 dcesrv_sock_recv(srv_conn, t, flags);
1131 static void dcesrv_send(struct server_connection *srv_conn,
1132 struct timeval t, uint16_t flags)
1134 dcesrv_sock_send(srv_conn, t, flags);
1137 static void dcesrv_close(struct server_connection *srv_conn, const char *reason)
1139 dcesrv_sock_close(srv_conn, reason);
1143 static void dcesrv_exit(struct server_service *service, const char *reason)
1145 dcesrv_sock_exit(service, reason);
1149 /* the list of currently registered DCERPC endpoint servers.
1151 static struct ep_server {
1152 struct dcesrv_endpoint_server *ep_server;
1153 } *ep_servers = NULL;
1154 static int num_ep_servers;
1157 register a DCERPC endpoint server.
1159 The 'name' can be later used by other backends to find the operations
1160 structure for this backend.
1162 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1164 NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1166 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1168 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1169 /* its already registered! */
1170 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1172 return NT_STATUS_OBJECT_NAME_COLLISION;
1175 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1177 smb_panic("out of memory in dcerpc_register");
1180 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1181 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1185 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1188 return NT_STATUS_OK;
1192 return the operations structure for a named backend of the specified type
1194 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1198 for (i=0;i<num_ep_servers;i++) {
1199 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1200 return ep_servers[i].ep_server;
1208 return the DCERPC module version, and the size of some critical types
1209 This can be used by endpoint server modules to either detect compilation errors, or provide
1210 multiple implementations for different smbd compilation options in one module
1212 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1214 static const struct dcesrv_critical_sizes critical_sizes = {
1215 DCERPC_MODULE_VERSION,
1216 sizeof(struct dcesrv_context),
1217 sizeof(struct dcesrv_endpoint),
1218 sizeof(struct dcesrv_endpoint_server),
1219 sizeof(struct dcesrv_interface),
1220 sizeof(struct dcesrv_if_list),
1221 sizeof(struct dcesrv_connection),
1222 sizeof(struct dcesrv_call_state),
1223 sizeof(struct dcesrv_auth),
1224 sizeof(struct dcesrv_handle)
1227 return &critical_sizes;
1230 static const struct server_service_ops dcesrv_ops = {
1232 .service_init = dcesrv_init,
1233 .accept_connection = dcesrv_accept,
1234 .recv_handler = dcesrv_recv,
1235 .send_handler = dcesrv_send,
1236 .idle_handler = NULL,
1237 .close_connection = dcesrv_close,
1238 .service_exit = dcesrv_exit,
1241 const struct server_service_ops *dcesrv_get_ops(void)
1246 NTSTATUS server_service_rpc_init(void)
1248 return NT_STATUS_OK;