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.ptype == DCERPC_PKT_REQUEST &&
853 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
854 struct dcesrv_call_state *call2 = call;
857 /* we only allow fragmented requests, no other packet types */
858 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
859 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
862 /* this is a continuation of an existing call - find the call then
863 tack it on the end */
864 call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
866 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
869 if (call->pkt.ptype != call2->pkt.ptype) {
870 /* trying to play silly buggers are we? */
871 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
874 alloc_size = call->pkt.u.request.stub_and_verifier.length +
875 call2->pkt.u.request.stub_and_verifier.length;
876 if (call->pkt.u.request.alloc_hint > alloc_size) {
877 alloc_size = call->pkt.u.request.alloc_hint;
880 call->pkt.u.request.stub_and_verifier.data =
881 talloc_realloc(call, call->pkt.u.request.stub_and_verifier.data, alloc_size);
882 if (!call->pkt.u.request.stub_and_verifier.data) {
883 return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
885 memcpy(call->pkt.u.request.stub_and_verifier.data +
886 call->pkt.u.request.stub_and_verifier.length,
887 call2->pkt.u.request.stub_and_verifier.data,
888 call2->pkt.u.request.stub_and_verifier.length);
889 call->pkt.u.request.stub_and_verifier.length +=
890 call2->pkt.u.request.stub_and_verifier.length;
892 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
897 /* this may not be the last pdu in the chain - if its isn't then
898 just put it on the call_list and wait for the rest */
899 if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
900 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
901 DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
905 switch (call->pkt.ptype) {
906 case DCERPC_PKT_BIND:
907 status = dcesrv_bind(call);
909 case DCERPC_PKT_AUTH3:
910 status = dcesrv_auth3(call);
912 case DCERPC_PKT_ALTER:
913 status = dcesrv_alter(call);
915 case DCERPC_PKT_REQUEST:
916 status = dcesrv_request(call);
919 status = NT_STATUS_INVALID_PARAMETER;
923 /* if we are going to be sending a reply then add
924 it to the list of pending calls. We add it to the end to keep the call
925 list in the order we will answer */
926 if (!NT_STATUS_IS_OK(status)) {
935 provide some input to a dcerpc endpoint server. This passes data
936 from a dcerpc client into the server
938 NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
942 dce_conn->partial_input.data = talloc_realloc(dce_conn,
943 dce_conn->partial_input.data,
944 dce_conn->partial_input.length + data->length);
945 if (!dce_conn->partial_input.data) {
946 return NT_STATUS_NO_MEMORY;
948 memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
949 data->data, data->length);
950 dce_conn->partial_input.length += data->length;
952 while (dce_full_packet(&dce_conn->partial_input)) {
953 status = dcesrv_input_process(dce_conn);
954 if (!NT_STATUS_IS_OK(status)) {
963 retrieve some output from a dcerpc server
964 The caller supplies a function that will be called to do the
967 The first argument to write_fn() will be 'private', the second will
968 be a pointer to a buffer containing the data to be sent and the 3rd
969 will be the number of bytes to be sent.
971 write_fn() should return the number of bytes successfully written.
973 this will return STATUS_BUFFER_OVERFLOW if there is more to be read
974 from the current fragment
976 NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
978 ssize_t (*write_fn)(void *, DATA_BLOB *))
980 struct dcesrv_call_state *call;
981 struct dcesrv_call_reply *rep;
984 call = dce_conn->call_list;
985 if (!call || !call->replies) {
986 return NT_STATUS_FOOBAR;
990 nwritten = write_fn(private, &rep->data);
991 if (nwritten == -1) {
992 /* TODO: hmm, how do we cope with this? destroy the
993 connection perhaps? */
994 return NT_STATUS_UNSUCCESSFUL;
997 rep->data.length -= nwritten;
998 rep->data.data += nwritten;
1000 if (rep->data.length == 0) {
1001 /* we're done with this section of the call */
1002 DLIST_REMOVE(call->replies, rep);
1004 return STATUS_BUFFER_OVERFLOW;
1007 if (call->replies == NULL) {
1008 /* we're done with the whole call */
1009 DLIST_REMOVE(dce_conn->call_list, call);
1013 return NT_STATUS_OK;
1018 write_fn() for dcesrv_output_blob()
1020 static ssize_t dcesrv_output_blob_write_fn(void *private, DATA_BLOB *out)
1022 DATA_BLOB *blob = private;
1023 if (out->length < blob->length) {
1024 blob->length = out->length;
1026 memcpy(blob->data, out->data, blob->length);
1027 return blob->length;
1031 a simple wrapper for dcesrv_output() for when we want to output
1034 NTSTATUS dcesrv_output_blob(struct dcesrv_connection *dce_conn,
1037 return dcesrv_output(dce_conn, blob, dcesrv_output_blob_write_fn);
1041 initialise the dcerpc server context
1043 NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **dce_ctx)
1046 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
1048 (*dce_ctx) = talloc_p(mem_ctx, struct dcesrv_context);
1050 return NT_STATUS_NO_MEMORY;
1053 (*dce_ctx)->endpoint_list = NULL;
1055 if (!endpoint_servers) {
1056 DEBUG(3,("dcesrv_init_context: no endpoint servers configured\n"));
1057 return NT_STATUS_OK;
1060 for (i=0;endpoint_servers[i];i++) {
1062 const struct dcesrv_endpoint_server *ep_server;
1064 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1066 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1067 return NT_STATUS_UNSUCCESSFUL;
1070 ret = ep_server->init_server(*dce_ctx, ep_server);
1071 if (!NT_STATUS_IS_OK(ret)) {
1072 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1077 return NT_STATUS_OK;
1080 static void dcesrv_init(struct server_service *service, const struct model_ops *model_ops)
1082 struct dcesrv_context *dce_ctx;
1084 const char **endpoint_servers = lp_dcerpc_endpoint_servers();
1086 DEBUG(1,("dcesrv_init\n"));
1088 if (!endpoint_servers) {
1089 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1093 dce_ctx = talloc_p(service, struct dcesrv_context);
1095 DEBUG(0,("talloc_p(mem_ctx, struct dcesrv_context) failed\n"));
1099 ZERO_STRUCTP(dce_ctx);
1100 dce_ctx->endpoint_list = NULL;
1102 for (i=0;endpoint_servers[i];i++) {
1104 const struct dcesrv_endpoint_server *ep_server;
1106 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1108 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1112 ret = ep_server->init_server(dce_ctx, ep_server);
1113 if (!NT_STATUS_IS_OK(ret)) {
1114 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
1119 dcesrv_sock_init(service, model_ops, dce_ctx);
1124 static void dcesrv_accept(struct server_connection *srv_conn)
1126 dcesrv_sock_accept(srv_conn);
1129 static void dcesrv_recv(struct server_connection *srv_conn,
1130 struct timeval t, uint16_t flags)
1132 dcesrv_sock_recv(srv_conn, t, flags);
1135 static void dcesrv_send(struct server_connection *srv_conn,
1136 struct timeval t, uint16_t flags)
1138 dcesrv_sock_send(srv_conn, t, flags);
1141 static void dcesrv_close(struct server_connection *srv_conn, const char *reason)
1143 dcesrv_sock_close(srv_conn, reason);
1147 static void dcesrv_exit(struct server_service *service, const char *reason)
1149 dcesrv_sock_exit(service, reason);
1153 /* the list of currently registered DCERPC endpoint servers.
1155 static struct ep_server {
1156 struct dcesrv_endpoint_server *ep_server;
1157 } *ep_servers = NULL;
1158 static int num_ep_servers;
1161 register a DCERPC endpoint server.
1163 The 'name' can be later used by other backends to find the operations
1164 structure for this backend.
1166 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1168 NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
1170 const struct dcesrv_endpoint_server *ep_server = _ep_server;
1172 if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1173 /* its already registered! */
1174 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1176 return NT_STATUS_OBJECT_NAME_COLLISION;
1179 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1181 smb_panic("out of memory in dcerpc_register");
1184 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1185 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1189 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1192 return NT_STATUS_OK;
1196 return the operations structure for a named backend of the specified type
1198 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
1202 for (i=0;i<num_ep_servers;i++) {
1203 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1204 return ep_servers[i].ep_server;
1212 return the DCERPC module version, and the size of some critical types
1213 This can be used by endpoint server modules to either detect compilation errors, or provide
1214 multiple implementations for different smbd compilation options in one module
1216 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
1218 static const struct dcesrv_critical_sizes critical_sizes = {
1219 DCERPC_MODULE_VERSION,
1220 sizeof(struct dcesrv_context),
1221 sizeof(struct dcesrv_endpoint),
1222 sizeof(struct dcesrv_endpoint_server),
1223 sizeof(struct dcesrv_interface),
1224 sizeof(struct dcesrv_if_list),
1225 sizeof(struct dcesrv_connection),
1226 sizeof(struct dcesrv_call_state),
1227 sizeof(struct dcesrv_auth),
1228 sizeof(struct dcesrv_handle)
1231 return &critical_sizes;
1234 static const struct server_service_ops dcesrv_ops = {
1236 .service_init = dcesrv_init,
1237 .accept_connection = dcesrv_accept,
1238 .recv_handler = dcesrv_recv,
1239 .send_handler = dcesrv_send,
1240 .idle_handler = NULL,
1241 .close_connection = dcesrv_close,
1242 .service_exit = dcesrv_exit,
1245 const struct server_service_ops *dcesrv_get_ops(void)
1250 NTSTATUS server_service_rpc_init(void)
1252 return NT_STATUS_OK;