1/* 2 Unix SMB/CIFS implementation. 3 4 server side dcerpc core code 5 6 Copyright (C) Andrew Tridgell 2003-2005 7 Copyright (C) Stefan (metze) Metzmacher 2004-2005 8 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 3 of the License, or 12 (at your option) any later version. 13 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. 18 19 You should have received a copy of the GNU General Public License 20 along with this program. If not, see <http://www.gnu.org/licenses/>. 21*/ 22 23#include "includes.h" 24#include "librpc/gen_ndr/ndr_dcerpc.h" 25#include "auth/auth.h" 26#include "auth/gensec/gensec.h" 27#include "../lib/util/dlinklist.h" 28#include "rpc_server/dcerpc_server.h" 29#include "rpc_server/dcerpc_server_proto.h" 30#include "librpc/rpc/dcerpc_proto.h" 31#include "lib/events/events.h" 32#include "smbd/service_task.h" 33#include "smbd/service_stream.h" 34#include "smbd/service.h" 35#include "system/filesys.h" 36#include "libcli/security/security.h" 37#include "param/param.h" 38 39/* this is only used when the client asks for an unknown interface */ 40#define DUMMY_ASSOC_GROUP 0x0FFFFFFF 41 42extern const struct dcesrv_interface dcesrv_mgmt_interface; 43 44 45/* 46 find an association group given a assoc_group_id 47 */ 48static struct dcesrv_assoc_group *dcesrv_assoc_group_find(struct dcesrv_context *dce_ctx, 49 uint32_t id) 50{ 51 void *id_ptr; 52 53 id_ptr = idr_find(dce_ctx->assoc_groups_idr, id); 54 if (id_ptr == NULL) { 55 return NULL; 56 } 57 return talloc_get_type_abort(id_ptr, struct dcesrv_assoc_group); 58} 59 60/* 61 take a reference to an existing association group 62 */ 63static struct dcesrv_assoc_group *dcesrv_assoc_group_reference(TALLOC_CTX *mem_ctx, 64 struct dcesrv_context *dce_ctx, 65 uint32_t id) 66{ 67 struct dcesrv_assoc_group *assoc_group; 68 69 assoc_group = dcesrv_assoc_group_find(dce_ctx, id); 70 if (assoc_group == NULL) { 71 DEBUG(0,(__location__ ": Failed to find assoc_group 0x%08x\n", id)); 72 return NULL; 73 } 74 return talloc_reference(mem_ctx, assoc_group); 75} 76 77static int dcesrv_assoc_group_destructor(struct dcesrv_assoc_group *assoc_group) 78{ 79 int ret; 80 ret = idr_remove(assoc_group->dce_ctx->assoc_groups_idr, assoc_group->id); 81 if (ret != 0) { 82 DEBUG(0,(__location__ ": Failed to remove assoc_group 0x%08x\n", 83 assoc_group->id)); 84 } 85 return 0; 86} 87 88/* 89 allocate a new association group 90 */ 91static struct dcesrv_assoc_group *dcesrv_assoc_group_new(TALLOC_CTX *mem_ctx, 92 struct dcesrv_context *dce_ctx) 93{ 94 struct dcesrv_assoc_group *assoc_group; 95 int id; 96 97 assoc_group = talloc_zero(mem_ctx, struct dcesrv_assoc_group); 98 if (assoc_group == NULL) { 99 return NULL; 100 } 101 102 id = idr_get_new_random(dce_ctx->assoc_groups_idr, assoc_group, UINT16_MAX); 103 if (id == -1) { 104 talloc_free(assoc_group); 105 DEBUG(0,(__location__ ": Out of association groups!\n")); 106 return NULL; 107 } 108 109 assoc_group->id = id; 110 assoc_group->dce_ctx = dce_ctx; 111 112 talloc_set_destructor(assoc_group, dcesrv_assoc_group_destructor); 113 114 return assoc_group; 115} 116 117 118/* 119 see if two endpoints match 120*/ 121static bool endpoints_match(const struct dcerpc_binding *ep1, 122 const struct dcerpc_binding *ep2) 123{ 124 if (ep1->transport != ep2->transport) { 125 return false; 126 } 127 128 if (!ep1->endpoint || !ep2->endpoint) { 129 return ep1->endpoint == ep2->endpoint; 130 } 131 132 if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0) 133 return false; 134 135 return true; 136} 137 138/* 139 find an endpoint in the dcesrv_context 140*/ 141static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx, 142 const struct dcerpc_binding *ep_description) 143{ 144 struct dcesrv_endpoint *ep; 145 for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) { 146 if (endpoints_match(ep->ep_description, ep_description)) { 147 return ep; 148 } 149 } 150 return NULL; 151} 152 153/* 154 find a registered context_id from a bind or alter_context 155*/ 156static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn, 157 uint32_t context_id) 158{ 159 struct dcesrv_connection_context *c; 160 for (c=conn->contexts;c;c=c->next) { 161 if (c->context_id == context_id) return c; 162 } 163 return NULL; 164} 165 166/* 167 see if a uuid and if_version match to an interface 168*/ 169static bool interface_match(const struct dcesrv_interface *if1, 170 const struct dcesrv_interface *if2) 171{ 172 return (if1->syntax_id.if_version == if2->syntax_id.if_version && 173 GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid)); 174} 175 176/* 177 find the interface operations on an endpoint 178*/ 179static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint, 180 const struct dcesrv_interface *iface) 181{ 182 struct dcesrv_if_list *ifl; 183 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) { 184 if (interface_match(&(ifl->iface), iface)) { 185 return &(ifl->iface); 186 } 187 } 188 return NULL; 189} 190 191/* 192 see if a uuid and if_version match to an interface 193*/ 194static bool interface_match_by_uuid(const struct dcesrv_interface *iface, 195 const struct GUID *uuid, uint32_t if_version) 196{ 197 return (iface->syntax_id.if_version == if_version && 198 GUID_equal(&iface->syntax_id.uuid, uuid)); 199} 200 201/* 202 find the interface operations on an endpoint by uuid 203*/ 204static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint, 205 const struct GUID *uuid, uint32_t if_version) 206{ 207 struct dcesrv_if_list *ifl; 208 for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) { 209 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) { 210 return &(ifl->iface); 211 } 212 } 213 return NULL; 214} 215 216/* 217 find the earlier parts of a fragmented call awaiting reassembily 218*/ 219static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id) 220{ 221 struct dcesrv_call_state *c; 222 for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) { 223 if (c->pkt.call_id == call_id) { 224 return c; 225 } 226 } 227 return NULL; 228} 229 230/* 231 register an interface on an endpoint 232*/ 233_PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx, 234 const char *ep_name, 235 const struct dcesrv_interface *iface, 236 const struct security_descriptor *sd) 237{ 238 struct dcesrv_endpoint *ep; 239 struct dcesrv_if_list *ifl; 240 struct dcerpc_binding *binding; 241 bool add_ep = false; 242 NTSTATUS status; 243 244 status = dcerpc_parse_binding(dce_ctx, ep_name, &binding); 245 246 if (NT_STATUS_IS_ERR(status)) { 247 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name)); 248 return status; 249 } 250 251 /* check if this endpoint exists 252 */ 253 if ((ep=find_endpoint(dce_ctx, binding))==NULL) { 254 ep = talloc(dce_ctx, struct dcesrv_endpoint); 255 if (!ep) { 256 return NT_STATUS_NO_MEMORY; 257 } 258 ZERO_STRUCTP(ep); 259 ep->ep_description = talloc_reference(ep, binding); 260 add_ep = true; 261 262 /* add mgmt interface */ 263 ifl = talloc(dce_ctx, struct dcesrv_if_list); 264 if (!ifl) { 265 return NT_STATUS_NO_MEMORY; 266 } 267 268 memcpy(&(ifl->iface), &dcesrv_mgmt_interface, 269 sizeof(struct dcesrv_interface)); 270 271 DLIST_ADD(ep->interface_list, ifl); 272 } 273 274 /* see if the interface is already registered on te endpoint */ 275 if (find_interface(ep, iface)!=NULL) { 276 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n", 277 iface->name, ep_name)); 278 return NT_STATUS_OBJECT_NAME_COLLISION; 279 } 280 281 /* talloc a new interface list element */ 282 ifl = talloc(dce_ctx, struct dcesrv_if_list); 283 if (!ifl) { 284 return NT_STATUS_NO_MEMORY; 285 } 286 287 /* copy the given interface struct to the one on the endpoints interface list */ 288 memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface)); 289 290 /* if we have a security descriptor given, 291 * we should see if we can set it up on the endpoint 292 */ 293 if (sd != NULL) { 294 /* if there's currently no security descriptor given on the endpoint 295 * we try to set it 296 */ 297 if (ep->sd == NULL) { 298 ep->sd = security_descriptor_copy(dce_ctx, sd); 299 } 300 301 /* if now there's no security descriptor given on the endpoint 302 * something goes wrong, either we failed to copy the security descriptor 303 * or there was already one on the endpoint 304 */ 305 if (ep->sd != NULL) { 306 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n" 307 " on endpoint '%s'\n", 308 iface->name, ep_name)); 309 if (add_ep) free(ep); 310 free(ifl); 311 return NT_STATUS_OBJECT_NAME_COLLISION; 312 } 313 } 314 315 /* finally add the interface on the endpoint */ 316 DLIST_ADD(ep->interface_list, ifl); 317 318 /* if it's a new endpoint add it to the dcesrv_context */ 319 if (add_ep) { 320 DLIST_ADD(dce_ctx->endpoint_list, ep); 321 } 322 323 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n", 324 iface->name, ep_name)); 325 326 return NT_STATUS_OK; 327} 328 329NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p, 330 DATA_BLOB *session_key) 331{ 332 if (p->auth_state.session_info->session_key.length) { 333 *session_key = p->auth_state.session_info->session_key; 334 return NT_STATUS_OK; 335 } 336 return NT_STATUS_NO_USER_SESSION_KEY; 337} 338 339NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p, 340 DATA_BLOB *session_key) 341{ 342 /* this took quite a few CPU cycles to find ... */ 343 session_key->data = discard_const_p(uint8_t, "SystemLibraryDTC"); 344 session_key->length = 16; 345 return NT_STATUS_OK; 346} 347 348/* 349 fetch the user session key - may be default (above) or the SMB session key 350 351 The key is always truncated to 16 bytes 352*/ 353_PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p, 354 DATA_BLOB *session_key) 355{ 356 NTSTATUS status = p->auth_state.session_key(p, session_key); 357 if (!NT_STATUS_IS_OK(status)) { 358 return status; 359 } 360 361 session_key->length = MIN(session_key->length, 16); 362 363 return NT_STATUS_OK; 364} 365 366/* 367 connect to a dcerpc endpoint 368*/ 369_PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx, 370 TALLOC_CTX *mem_ctx, 371 const struct dcesrv_endpoint *ep, 372 struct auth_session_info *session_info, 373 struct tevent_context *event_ctx, 374 struct messaging_context *msg_ctx, 375 struct server_id server_id, 376 uint32_t state_flags, 377 struct dcesrv_connection **_p) 378{ 379 struct dcesrv_connection *p; 380 381 if (!session_info) { 382 return NT_STATUS_ACCESS_DENIED; 383 } 384 385 p = talloc(mem_ctx, struct dcesrv_connection); 386 NT_STATUS_HAVE_NO_MEMORY(p); 387 388 if (!talloc_reference(p, session_info)) { 389 talloc_free(p); 390 return NT_STATUS_NO_MEMORY; 391 } 392 393 p->dce_ctx = dce_ctx; 394 p->endpoint = ep; 395 p->contexts = NULL; 396 p->call_list = NULL; 397 p->packet_log_dir = lp_lockdir(dce_ctx->lp_ctx); 398 p->incoming_fragmented_call_list = NULL; 399 p->pending_call_list = NULL; 400 p->cli_max_recv_frag = 0; 401 p->partial_input = data_blob(NULL, 0); 402 p->auth_state.auth_info = NULL; 403 p->auth_state.gensec_security = NULL; 404 p->auth_state.session_info = session_info; 405 p->auth_state.session_key = dcesrv_generic_session_key; 406 p->event_ctx = event_ctx; 407 p->msg_ctx = msg_ctx; 408 p->server_id = server_id; 409 p->processing = false; 410 p->state_flags = state_flags; 411 ZERO_STRUCT(p->transport); 412 413 *_p = p; 414 return NT_STATUS_OK; 415} 416 417static void dcesrv_init_hdr(struct ncacn_packet *pkt, bool bigendian) 418{ 419 pkt->rpc_vers = 5; 420 pkt->rpc_vers_minor = 0; 421 if (bigendian) { 422 pkt->drep[0] = 0; 423 } else { 424 pkt->drep[0] = DCERPC_DREP_LE; 425 } 426 pkt->drep[1] = 0; 427 pkt->drep[2] = 0; 428 pkt->drep[3] = 0; 429} 430 431/* 432 move a call from an existing linked list to the specified list. This 433 prevents bugs where we forget to remove the call from a previous 434 list when moving it. 435 */ 436static void dcesrv_call_set_list(struct dcesrv_call_state *call, 437 enum dcesrv_call_list list) 438{ 439 switch (call->list) { 440 case DCESRV_LIST_NONE: 441 break; 442 case DCESRV_LIST_CALL_LIST: 443 DLIST_REMOVE(call->conn->call_list, call); 444 break; 445 case DCESRV_LIST_FRAGMENTED_CALL_LIST: 446 DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call); 447 break; 448 case DCESRV_LIST_PENDING_CALL_LIST: 449 DLIST_REMOVE(call->conn->pending_call_list, call); 450 break; 451 } 452 call->list = list; 453 switch (list) { 454 case DCESRV_LIST_NONE: 455 break; 456 case DCESRV_LIST_CALL_LIST: 457 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *); 458 break; 459 case DCESRV_LIST_FRAGMENTED_CALL_LIST: 460 DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *); 461 break; 462 case DCESRV_LIST_PENDING_CALL_LIST: 463 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *); 464 break; 465 } 466} 467 468/* 469 return a dcerpc fault 470*/ 471static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code) 472{ 473 struct ncacn_packet pkt; 474 struct data_blob_list_item *rep; 475 uint8_t zeros[4]; 476 NTSTATUS status; 477 478 /* setup a bind_ack */ 479 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)); 480 pkt.auth_length = 0; 481 pkt.call_id = call->pkt.call_id; 482 pkt.ptype = DCERPC_PKT_FAULT; 483 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST; 484 pkt.u.fault.alloc_hint = 0; 485 pkt.u.fault.context_id = 0; 486 pkt.u.fault.cancel_count = 0; 487 pkt.u.fault.status = fault_code; 488 489 ZERO_STRUCT(zeros); 490 pkt.u.fault._pad = data_blob_const(zeros, sizeof(zeros)); 491 492 rep = talloc(call, struct data_blob_list_item); 493 if (!rep) { 494 return NT_STATUS_NO_MEMORY; 495 } 496 497 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL); 498 if (!NT_STATUS_IS_OK(status)) { 499 return status; 500 } 501 502 dcerpc_set_frag_length(&rep->blob, rep->blob.length); 503 504 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *); 505 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST); 506 507 if (call->conn->call_list && call->conn->call_list->replies) { 508 if (call->conn->transport.report_output_data) { 509 call->conn->transport.report_output_data(call->conn); 510 } 511 } 512 513 return NT_STATUS_OK; 514} 515 516 517/* 518 return a dcerpc bind_nak 519*/ 520static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason) 521{ 522 struct ncacn_packet pkt; 523 struct data_blob_list_item *rep; 524 NTSTATUS status; 525 526 /* setup a bind_nak */ 527 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)); 528 pkt.auth_length = 0; 529 pkt.call_id = call->pkt.call_id; 530 pkt.ptype = DCERPC_PKT_BIND_NAK; 531 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST; 532 pkt.u.bind_nak.reject_reason = reason; 533 if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) { 534 pkt.u.bind_nak.versions.v.num_versions = 0; 535 } 536 537 rep = talloc(call, struct data_blob_list_item); 538 if (!rep) { 539 return NT_STATUS_NO_MEMORY; 540 } 541 542 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL); 543 if (!NT_STATUS_IS_OK(status)) { 544 return status; 545 } 546 547 dcerpc_set_frag_length(&rep->blob, rep->blob.length); 548 549 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *); 550 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST); 551 552 if (call->conn->call_list && call->conn->call_list->replies) { 553 if (call->conn->transport.report_output_data) { 554 call->conn->transport.report_output_data(call->conn); 555 } 556 } 557 558 return NT_STATUS_OK; 559} 560 561static int dcesrv_connection_context_destructor(struct dcesrv_connection_context *c) 562{ 563 DLIST_REMOVE(c->conn->contexts, c); 564 565 if (c->iface) { 566 c->iface->unbind(c, c->iface); 567 } 568 569 return 0; 570} 571 572/* 573 handle a bind request 574*/ 575static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call) 576{ 577 uint32_t if_version, transfer_syntax_version; 578 struct GUID uuid, *transfer_syntax_uuid; 579 struct ncacn_packet pkt; 580 struct data_blob_list_item *rep; 581 NTSTATUS status; 582 uint32_t result=0, reason=0; 583 uint32_t context_id; 584 const struct dcesrv_interface *iface; 585 uint32_t extra_flags = 0; 586 587 /* 588 if provided, check the assoc_group is valid 589 */ 590 if (call->pkt.u.bind.assoc_group_id != 0 && 591 lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) && 592 dcesrv_assoc_group_find(call->conn->dce_ctx, call->pkt.u.bind.assoc_group_id) == NULL) { 593 return dcesrv_bind_nak(call, 0); 594 } 595 596 if (call->pkt.u.bind.num_contexts < 1 || 597 call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) { 598 return dcesrv_bind_nak(call, 0); 599 } 600 601 context_id = call->pkt.u.bind.ctx_list[0].context_id; 602 603 /* you can't bind twice on one context */ 604 if (dcesrv_find_context(call->conn, context_id) != NULL) { 605 return dcesrv_bind_nak(call, 0); 606 } 607 608 if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version; 609 uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid; 610 611 transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version; 612 transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid; 613 if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 || 614 ndr_transfer_syntax.if_version != transfer_syntax_version) { 615 char *uuid_str = GUID_string(call, transfer_syntax_uuid); 616 /* we only do NDR encoded dcerpc */ 617 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str)); 618 talloc_free(uuid_str); 619 return dcesrv_bind_nak(call, 0); 620 } 621 622 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version); 623 if (iface == NULL) { 624 char *uuid_str = GUID_string(call, &uuid); 625 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version)); 626 talloc_free(uuid_str); 627 628 /* we don't know about that interface */ 629 result = DCERPC_BIND_PROVIDER_REJECT; 630 reason = DCERPC_BIND_REASON_ASYNTAX; 631 } 632 633 if (iface) { 634 /* add this context to the list of available context_ids */ 635 struct dcesrv_connection_context *context = talloc(call->conn, 636 struct dcesrv_connection_context); 637 if (context == NULL) { 638 return dcesrv_bind_nak(call, 0); 639 } 640 context->conn = call->conn; 641 context->iface = iface; 642 context->context_id = context_id; 643 if (call->pkt.u.bind.assoc_group_id != 0) { 644 context->assoc_group = dcesrv_assoc_group_reference(context, 645 call->conn->dce_ctx, 646 call->pkt.u.bind.assoc_group_id); 647 } else { 648 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx); 649 } 650 if (context->assoc_group == NULL) { 651 talloc_free(context); 652 return dcesrv_bind_nak(call, 0); 653 } 654 context->private_data = NULL; 655 DLIST_ADD(call->conn->contexts, context); 656 call->context = context; 657 talloc_set_destructor(context, dcesrv_connection_context_destructor); 658 659 status = iface->bind(call, iface); 660 if (!NT_STATUS_IS_OK(status)) { 661 char *uuid_str = GUID_string(call, &uuid); 662 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n", 663 uuid_str, if_version, nt_errstr(status))); 664 talloc_free(uuid_str); 665 /* we don't want to trigger the iface->unbind() hook */ 666 context->iface = NULL; 667 talloc_free(call->context); 668 call->context = NULL; 669 return dcesrv_bind_nak(call, 0); 670 } 671 } 672 673 if (call->conn->cli_max_recv_frag == 0) { 674 call->conn->cli_max_recv_frag = MIN(0x2000, call->pkt.u.bind.max_recv_frag); 675 } 676 677 if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) && 678 lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","header signing", false)) { 679 call->conn->state_flags |= DCESRV_CALL_STATE_FLAG_HEADER_SIGNING; 680 extra_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN; 681 } 682 683 /* handle any authentication that is being requested */ 684 if (!dcesrv_auth_bind(call)) { 685 talloc_free(call->context); 686 call->context = NULL; 687 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE); 688 } 689 690 /* setup a bind_ack */ 691 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)); 692 pkt.auth_length = 0; 693 pkt.call_id = call->pkt.call_id; 694 pkt.ptype = DCERPC_PKT_BIND_ACK; 695 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags; 696 pkt.u.bind_ack.max_xmit_frag = call->conn->cli_max_recv_frag; 697 pkt.u.bind_ack.max_recv_frag = 0x2000; 698 699 /* 700 make it possible for iface->bind() to specify the assoc_group_id 701 This helps the openchange mapiproxy plugin to work correctly. 702 703 metze 704 */ 705 if (call->context) { 706 pkt.u.bind_ack.assoc_group_id = call->context->assoc_group->id; 707 } else { 708 pkt.u.bind_ack.assoc_group_id = DUMMY_ASSOC_GROUP; 709 } 710 711 if (iface) { 712 /* FIXME: Use pipe name as specified by endpoint instead of interface name */ 713 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name); 714 } else { 715 pkt.u.bind_ack.secondary_address = ""; 716 } 717 pkt.u.bind_ack.num_results = 1; 718 pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx); 719 if (!pkt.u.bind_ack.ctx_list) { 720 talloc_free(call->context); 721 call->context = NULL; 722 return NT_STATUS_NO_MEMORY; 723 } 724 pkt.u.bind_ack.ctx_list[0].result = result; 725 pkt.u.bind_ack.ctx_list[0].reason = reason; 726 pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax; 727 pkt.u.bind_ack.auth_info = data_blob(NULL, 0); 728 729 status = dcesrv_auth_bind_ack(call, &pkt); 730 if (!NT_STATUS_IS_OK(status)) { 731 talloc_free(call->context); 732 call->context = NULL; 733 return dcesrv_bind_nak(call, 0); 734 } 735 736 rep = talloc(call, struct data_blob_list_item); 737 if (!rep) { 738 talloc_free(call->context); 739 call->context = NULL; 740 return NT_STATUS_NO_MEMORY; 741 } 742 743 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info); 744 if (!NT_STATUS_IS_OK(status)) { 745 talloc_free(call->context); 746 call->context = NULL; 747 return status; 748 } 749 750 dcerpc_set_frag_length(&rep->blob, rep->blob.length); 751 752 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *); 753 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST); 754 755 if (call->conn->call_list && call->conn->call_list->replies) { 756 if (call->conn->transport.report_output_data) { 757 call->conn->transport.report_output_data(call->conn); 758 } 759 } 760 761 return NT_STATUS_OK; 762} 763 764 765/* 766 handle a auth3 request 767*/ 768static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call) 769{ 770 /* handle the auth3 in the auth code */ 771 if (!dcesrv_auth_auth3(call)) { 772 return dcesrv_fault(call, DCERPC_FAULT_OTHER); 773 } 774 775 talloc_free(call); 776 777 /* we don't send a reply to a auth3 request, except by a 778 fault */ 779 return NT_STATUS_OK; 780} 781 782 783/* 784 handle a bind request 785*/ 786static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id) 787{ 788 uint32_t if_version, transfer_syntax_version; 789 struct dcesrv_connection_context *context; 790 const struct dcesrv_interface *iface; 791 struct GUID uuid, *transfer_syntax_uuid; 792 NTSTATUS status; 793 794 if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version; 795 uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid; 796 797 transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version; 798 transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid; 799 if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) || 800 ndr_transfer_syntax.if_version != transfer_syntax_version) { 801 /* we only do NDR encoded dcerpc */ 802 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED; 803 } 804 805 iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version); 806 if (iface == NULL) { 807 char *uuid_str = GUID_string(call, &uuid); 808 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version)); 809 talloc_free(uuid_str); 810 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED; 811 } 812 813 /* add this context to the list of available context_ids */ 814 context = talloc(call->conn, struct dcesrv_connection_context); 815 if (context == NULL) { 816 return NT_STATUS_NO_MEMORY; 817 } 818 context->conn = call->conn; 819 context->iface = iface; 820 context->context_id = context_id; 821 if (call->pkt.u.alter.assoc_group_id != 0) { 822 context->assoc_group = dcesrv_assoc_group_reference(context, 823 call->conn->dce_ctx, 824 call->pkt.u.alter.assoc_group_id); 825 } else { 826 context->assoc_group = dcesrv_assoc_group_new(context, call->conn->dce_ctx); 827 } 828 if (context->assoc_group == NULL) { 829 talloc_free(context); 830 call->context = NULL; 831 return NT_STATUS_NO_MEMORY; 832 } 833 context->private_data = NULL; 834 DLIST_ADD(call->conn->contexts, context); 835 call->context = context; 836 talloc_set_destructor(context, dcesrv_connection_context_destructor); 837 838 status = iface->bind(call, iface); 839 if (!NT_STATUS_IS_OK(status)) { 840 /* we don't want to trigger the iface->unbind() hook */ 841 context->iface = NULL; 842 talloc_free(context); 843 call->context = NULL; 844 return status; 845 } 846 847 return NT_STATUS_OK; 848} 849 850 851/* 852 handle a alter context request 853*/ 854static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call) 855{ 856 struct ncacn_packet pkt; 857 struct data_blob_list_item *rep; 858 NTSTATUS status; 859 uint32_t result=0, reason=0; 860 uint32_t context_id; 861 862 /* handle any authentication that is being requested */ 863 if (!dcesrv_auth_alter(call)) { 864 /* TODO: work out the right reject code */ 865 result = DCERPC_BIND_PROVIDER_REJECT; 866 reason = DCERPC_BIND_REASON_ASYNTAX; 867 } 868 869 context_id = call->pkt.u.alter.ctx_list[0].context_id; 870 871 /* see if they are asking for a new interface */ 872 if (result == 0) { 873 call->context = dcesrv_find_context(call->conn, context_id); 874 if (!call->context) { 875 status = dcesrv_alter_new_context(call, context_id); 876 if (!NT_STATUS_IS_OK(status)) { 877 result = DCERPC_BIND_PROVIDER_REJECT; 878 reason = DCERPC_BIND_REASON_ASYNTAX; 879 } 880 } 881 } 882 883 if (result == 0 && 884 call->pkt.u.alter.assoc_group_id != 0 && 885 lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) && 886 call->pkt.u.alter.assoc_group_id != call->context->assoc_group->id) { 887 DEBUG(0,(__location__ ": Failed attempt to use new assoc_group in alter context (0x%08x 0x%08x)\n", 888 call->context->assoc_group->id, call->pkt.u.alter.assoc_group_id)); 889 /* TODO: can they ask for a new association group? */ 890 result = DCERPC_BIND_PROVIDER_REJECT; 891 reason = DCERPC_BIND_REASON_ASYNTAX; 892 } 893 894 /* setup a alter_resp */ 895 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)); 896 pkt.auth_length = 0; 897 pkt.call_id = call->pkt.call_id; 898 pkt.ptype = DCERPC_PKT_ALTER_RESP; 899 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST; 900 pkt.u.alter_resp.max_xmit_frag = 0x2000; 901 pkt.u.alter_resp.max_recv_frag = 0x2000; 902 if (result == 0) { 903 pkt.u.alter_resp.assoc_group_id = call->context->assoc_group->id; 904 } else { 905 pkt.u.alter_resp.assoc_group_id = 0; 906 } 907 pkt.u.alter_resp.num_results = 1; 908 pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1); 909 if (!pkt.u.alter_resp.ctx_list) { 910 return NT_STATUS_NO_MEMORY; 911 } 912 pkt.u.alter_resp.ctx_list[0].result = result; 913 pkt.u.alter_resp.ctx_list[0].reason = reason; 914 pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax; 915 pkt.u.alter_resp.auth_info = data_blob(NULL, 0); 916 pkt.u.alter_resp.secondary_address = ""; 917 918 status = dcesrv_auth_alter_ack(call, &pkt); 919 if (!NT_STATUS_IS_OK(status)) { 920 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) 921 || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE) 922 || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER) 923 || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) { 924 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED); 925 } 926 return dcesrv_fault(call, 0); 927 } 928 929 rep = talloc(call, struct data_blob_list_item); 930 if (!rep) { 931 return NT_STATUS_NO_MEMORY; 932 } 933 934 status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info); 935 if (!NT_STATUS_IS_OK(status)) { 936 return status; 937 } 938 939 dcerpc_set_frag_length(&rep->blob, rep->blob.length); 940 941 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *); 942 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST); 943 944 if (call->conn->call_list && call->conn->call_list->replies) { 945 if (call->conn->transport.report_output_data) { 946 call->conn->transport.report_output_data(call->conn); 947 } 948 } 949 950 return NT_STATUS_OK; 951} 952 953/* 954 handle a dcerpc request packet 955*/ 956static NTSTATUS dcesrv_request(struct dcesrv_call_state *call) 957{ 958 struct ndr_pull *pull; 959 NTSTATUS status; 960 struct dcesrv_connection_context *context; 961 962 /* if authenticated, and the mech we use can't do async replies, don't use them... */ 963 if (call->conn->auth_state.gensec_security && 964 !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) { 965 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC; 966 } 967 968 context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id); 969 if (context == NULL) { 970 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF); 971 } 972 973 pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call, 974 lp_iconv_convenience(call->conn->dce_ctx->lp_ctx)); 975 NT_STATUS_HAVE_NO_MEMORY(pull); 976 977 pull->flags |= LIBNDR_FLAG_REF_ALLOC; 978 979 call->context = context; 980 call->ndr_pull = pull; 981 982 if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) { 983 pull->flags |= LIBNDR_FLAG_BIGENDIAN; 984 } 985 986 /* unravel the NDR for the packet */ 987 status = context->iface->ndr_pull(call, call, pull, &call->r); 988 if (!NT_STATUS_IS_OK(status)) { 989 return dcesrv_fault(call, call->fault_code); 990 } 991 992 if (pull->offset != pull->data_size) { 993 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n", 994 pull->data_size - pull->offset)); 995 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset); 996 } 997 998 /* call the dispatch function */ 999 status = context->iface->dispatch(call, call, call->r); 1000 if (!NT_STATUS_IS_OK(status)) { 1001 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n", 1002 context->iface->name, 1003 call->pkt.u.request.opnum, 1004 dcerpc_errstr(pull, call->fault_code))); 1005 return dcesrv_fault(call, call->fault_code); 1006 } 1007 1008 /* add the call to the pending list */ 1009 dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST); 1010 1011 if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) { 1012 return NT_STATUS_OK; 1013 } 1014 1015 return dcesrv_reply(call); 1016} 1017 1018_PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call) 1019{ 1020 struct ndr_push *push; 1021 NTSTATUS status; 1022 DATA_BLOB stub; 1023 uint32_t total_length, chunk_size; 1024 struct dcesrv_connection_context *context = call->context; 1025 size_t sig_size = 0; 1026 1027 /* call the reply function */ 1028 status = context->iface->reply(call, call, call->r); 1029 if (!NT_STATUS_IS_OK(status)) { 1030 return dcesrv_fault(call, call->fault_code); 1031 } 1032 1033 /* form the reply NDR */ 1034 push = ndr_push_init_ctx(call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx)); 1035 NT_STATUS_HAVE_NO_MEMORY(push); 1036 1037 /* carry over the pointer count to the reply in case we are 1038 using full pointer. See NDR specification for full 1039 pointers */ 1040 push->ptr_count = call->ndr_pull->ptr_count; 1041 1042 if (lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) { 1043 push->flags |= LIBNDR_FLAG_BIGENDIAN; 1044 } 1045 1046 status = context->iface->ndr_push(call, call, push, call->r); 1047 if (!NT_STATUS_IS_OK(status)) { 1048 return dcesrv_fault(call, call->fault_code); 1049 } 1050 1051 stub = ndr_push_blob(push); 1052 1053 total_length = stub.length; 1054 1055 /* we can write a full max_recv_frag size, minus the dcerpc 1056 request header size */ 1057 chunk_size = call->conn->cli_max_recv_frag; 1058 chunk_size -= DCERPC_REQUEST_LENGTH; 1059 if (call->conn->auth_state.auth_info && 1060 call->conn->auth_state.gensec_security) { 1061 sig_size = gensec_sig_size(call->conn->auth_state.gensec_security, 1062 call->conn->cli_max_recv_frag); 1063 if (sig_size) { 1064 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH; 1065 chunk_size -= sig_size; 1066 } 1067 } 1068 chunk_size -= (chunk_size % 16); 1069 1070 do { 1071 uint32_t length; 1072 struct data_blob_list_item *rep; 1073 struct ncacn_packet pkt; 1074 1075 rep = talloc(call, struct data_blob_list_item); 1076 NT_STATUS_HAVE_NO_MEMORY(rep); 1077 1078 length = MIN(chunk_size, stub.length); 1079 1080 /* form the dcerpc response packet */ 1081 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)); 1082 pkt.auth_length = 0; 1083 pkt.call_id = call->pkt.call_id; 1084 pkt.ptype = DCERPC_PKT_RESPONSE; 1085 pkt.pfc_flags = 0; 1086 if (stub.length == total_length) { 1087 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST; 1088 } 1089 if (length == stub.length) { 1090 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST; 1091 } 1092 pkt.u.response.alloc_hint = stub.length; 1093 pkt.u.response.context_id = call->pkt.u.request.context_id; 1094 pkt.u.response.cancel_count = 0; 1095 pkt.u.response.stub_and_verifier.data = stub.data; 1096 pkt.u.response.stub_and_verifier.length = length; 1097 1098 if (!dcesrv_auth_response(call, &rep->blob, sig_size, &pkt)) { 1099 return dcesrv_fault(call, DCERPC_FAULT_OTHER); 1100 } 1101 1102 dcerpc_set_frag_length(&rep->blob, rep->blob.length); 1103 1104 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *); 1105 1106 stub.data += length; 1107 stub.length -= length; 1108 } while (stub.length != 0); 1109 1110 /* move the call from the pending to the finished calls list */ 1111 dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST); 1112 1113 if (call->conn->call_list && call->conn->call_list->replies) { 1114 if (call->conn->transport.report_output_data) { 1115 call->conn->transport.report_output_data(call->conn); 1116 } 1117 } 1118 1119 return NT_STATUS_OK; 1120} 1121 1122_PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx) 1123{ 1124 if (!conn->transport.get_my_addr) { 1125 return NULL; 1126 } 1127 1128 return conn->transport.get_my_addr(conn, mem_ctx); 1129} 1130 1131_PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx) 1132{ 1133 if (!conn->transport.get_peer_addr) { 1134 return NULL; 1135 } 1136 1137 return conn->transport.get_peer_addr(conn, mem_ctx); 1138} 1139 1140 1141/* 1142 remove the call from the right list when freed 1143 */ 1144static int dcesrv_call_dequeue(struct dcesrv_call_state *call) 1145{ 1146 dcesrv_call_set_list(call, DCESRV_LIST_NONE); 1147 return 0; 1148} 1149 1150/* 1151 process some input to a dcerpc endpoint server. 1152*/ 1153NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn, 1154 struct ncacn_packet *pkt, 1155 DATA_BLOB blob) 1156{ 1157 NTSTATUS status; 1158 struct dcesrv_call_state *call; 1159 1160 call = talloc_zero(dce_conn, struct dcesrv_call_state); 1161 if (!call) { 1162 data_blob_free(&blob); 1163 talloc_free(pkt); 1164 return NT_STATUS_NO_MEMORY; 1165 } 1166 call->conn = dce_conn; 1167 call->event_ctx = dce_conn->event_ctx; 1168 call->msg_ctx = dce_conn->msg_ctx; 1169 call->state_flags = call->conn->state_flags; 1170 call->time = timeval_current(); 1171 call->list = DCESRV_LIST_NONE; 1172 1173 talloc_steal(call, pkt); 1174 talloc_steal(call, blob.data); 1175 call->pkt = *pkt; 1176 1177 talloc_set_destructor(call, dcesrv_call_dequeue); 1178 1179 /* we have to check the signing here, before combining the 1180 pdus */ 1181 if (call->pkt.ptype == DCERPC_PKT_REQUEST && 1182 !dcesrv_auth_request(call, &blob)) { 1183 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED); 1184 } 1185 1186 /* see if this is a continued packet */ 1187 if (call->pkt.ptype == DCERPC_PKT_REQUEST && 1188 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) { 1189 struct dcesrv_call_state *call2 = call; 1190 uint32_t alloc_size; 1191 1192 /* we only allow fragmented requests, no other packet types */ 1193 if (call->pkt.ptype != DCERPC_PKT_REQUEST) { 1194 return dcesrv_fault(call2, DCERPC_FAULT_OTHER); 1195 } 1196 1197 /* this is a continuation of an existing call - find the call then 1198 tack it on the end */ 1199 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id); 1200 if (!call) { 1201 return dcesrv_fault(call2, DCERPC_FAULT_OTHER); 1202 } 1203 1204 if (call->pkt.ptype != call2->pkt.ptype) { 1205 /* trying to play silly buggers are we? */ 1206 return dcesrv_fault(call2, DCERPC_FAULT_OTHER); 1207 } 1208 1209 alloc_size = call->pkt.u.request.stub_and_verifier.length + 1210 call2->pkt.u.request.stub_and_verifier.length; 1211 if (call->pkt.u.request.alloc_hint > alloc_size) { 1212 alloc_size = call->pkt.u.request.alloc_hint; 1213 } 1214 1215 call->pkt.u.request.stub_and_verifier.data = 1216 talloc_realloc(call, 1217 call->pkt.u.request.stub_and_verifier.data, 1218 uint8_t, alloc_size); 1219 if (!call->pkt.u.request.stub_and_verifier.data) { 1220 return dcesrv_fault(call2, DCERPC_FAULT_OTHER); 1221 } 1222 memcpy(call->pkt.u.request.stub_and_verifier.data + 1223 call->pkt.u.request.stub_and_verifier.length, 1224 call2->pkt.u.request.stub_and_verifier.data, 1225 call2->pkt.u.request.stub_and_verifier.length); 1226 call->pkt.u.request.stub_and_verifier.length += 1227 call2->pkt.u.request.stub_and_verifier.length; 1228 1229 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST); 1230 1231 talloc_free(call2); 1232 } 1233 1234 /* this may not be the last pdu in the chain - if its isn't then 1235 just put it on the incoming_fragmented_call_list and wait for the rest */ 1236 if (call->pkt.ptype == DCERPC_PKT_REQUEST && 1237 !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) { 1238 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST); 1239 return NT_STATUS_OK; 1240 } 1241 1242 /* This removes any fragments we may have had stashed away */ 1243 dcesrv_call_set_list(call, DCESRV_LIST_NONE); 1244 1245 switch (call->pkt.ptype) { 1246 case DCERPC_PKT_BIND: 1247 status = dcesrv_bind(call); 1248 break; 1249 case DCERPC_PKT_AUTH3: 1250 status = dcesrv_auth3(call); 1251 break; 1252 case DCERPC_PKT_ALTER: 1253 status = dcesrv_alter(call); 1254 break; 1255 case DCERPC_PKT_REQUEST: 1256 status = dcesrv_request(call); 1257 break; 1258 default: 1259 status = NT_STATUS_INVALID_PARAMETER; 1260 break; 1261 } 1262 1263 /* if we are going to be sending a reply then add 1264 it to the list of pending calls. We add it to the end to keep the call 1265 list in the order we will answer */ 1266 if (!NT_STATUS_IS_OK(status)) { 1267 talloc_free(call); 1268 } 1269 1270 return status; 1271} 1272 1273_PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, 1274 struct loadparm_context *lp_ctx, 1275 const char **endpoint_servers, struct dcesrv_context **_dce_ctx) 1276{ 1277 NTSTATUS status; 1278 struct dcesrv_context *dce_ctx; 1279 int i; 1280 1281 if (!endpoint_servers) { 1282 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n")); 1283 return NT_STATUS_INTERNAL_ERROR; 1284 } 1285 1286 dce_ctx = talloc(mem_ctx, struct dcesrv_context); 1287 NT_STATUS_HAVE_NO_MEMORY(dce_ctx); 1288 dce_ctx->endpoint_list = NULL; 1289 dce_ctx->lp_ctx = lp_ctx; 1290 dce_ctx->assoc_groups_idr = idr_init(dce_ctx); 1291 NT_STATUS_HAVE_NO_MEMORY(dce_ctx->assoc_groups_idr); 1292 1293 for (i=0;endpoint_servers[i];i++) { 1294 const struct dcesrv_endpoint_server *ep_server; 1295 1296 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]); 1297 if (!ep_server) { 1298 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i])); 1299 return NT_STATUS_INTERNAL_ERROR; 1300 } 1301 1302 status = ep_server->init_server(dce_ctx, ep_server); 1303 if (!NT_STATUS_IS_OK(status)) { 1304 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i], 1305 nt_errstr(status))); 1306 return status; 1307 } 1308 } 1309 1310 *_dce_ctx = dce_ctx; 1311 return NT_STATUS_OK; 1312} 1313 1314/* the list of currently registered DCERPC endpoint servers. 1315 */ 1316static struct ep_server { 1317 struct dcesrv_endpoint_server *ep_server; 1318} *ep_servers = NULL; 1319static int num_ep_servers; 1320 1321/* 1322 register a DCERPC endpoint server. 1323 1324 The 'name' can be later used by other backends to find the operations 1325 structure for this backend. 1326 1327 The 'type' is used to specify whether this is for a disk, printer or IPC$ share 1328*/ 1329_PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server) 1330{ 1331 const struct dcesrv_endpoint_server *ep_server = _ep_server; 1332 1333 if (dcesrv_ep_server_byname(ep_server->name) != NULL) { 1334 /* its already registered! */ 1335 DEBUG(0,("DCERPC endpoint server '%s' already registered\n", 1336 ep_server->name)); 1337 return NT_STATUS_OBJECT_NAME_COLLISION; 1338 } 1339 1340 ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1); 1341 if (!ep_servers) { 1342 smb_panic("out of memory in dcerpc_register"); 1343 } 1344 1345 ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server)); 1346 ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name); 1347 1348 num_ep_servers++; 1349 1350 DEBUG(3,("DCERPC endpoint server '%s' registered\n", 1351 ep_server->name)); 1352 1353 return NT_STATUS_OK; 1354} 1355 1356/* 1357 return the operations structure for a named backend of the specified type 1358*/ 1359const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name) 1360{ 1361 int i; 1362 1363 for (i=0;i<num_ep_servers;i++) { 1364 if (strcmp(ep_servers[i].ep_server->name, name) == 0) { 1365 return ep_servers[i].ep_server; 1366 } 1367 } 1368 1369 return NULL; 1370} 1371 1372void dcerpc_server_init(struct loadparm_context *lp_ctx) 1373{ 1374 static bool initialized; 1375 extern NTSTATUS dcerpc_server_wkssvc_init(void); 1376 extern NTSTATUS dcerpc_server_drsuapi_init(void); 1377 extern NTSTATUS dcerpc_server_winreg_init(void); 1378 extern NTSTATUS dcerpc_server_spoolss_init(void); 1379 extern NTSTATUS dcerpc_server_epmapper_init(void); 1380 extern NTSTATUS dcerpc_server_srvsvc_init(void); 1381 extern NTSTATUS dcerpc_server_netlogon_init(void); 1382 extern NTSTATUS dcerpc_server_rpcecho_init(void); 1383 extern NTSTATUS dcerpc_server_unixinfo_init(void); 1384 extern NTSTATUS dcerpc_server_samr_init(void); 1385 extern NTSTATUS dcerpc_server_remote_init(void); 1386 extern NTSTATUS dcerpc_server_lsa_init(void); 1387 extern NTSTATUS dcerpc_server_browser_init(void); 1388 init_module_fn static_init[] = { STATIC_dcerpc_server_MODULES }; 1389 init_module_fn *shared_init; 1390 1391 if (initialized) { 1392 return; 1393 } 1394 initialized = true; 1395 1396 shared_init = load_samba_modules(NULL, lp_ctx, "dcerpc_server"); 1397 1398 run_init_functions(static_init); 1399 run_init_functions(shared_init); 1400 1401 talloc_free(shared_init); 1402} 1403 1404/* 1405 return the DCERPC module version, and the size of some critical types 1406 This can be used by endpoint server modules to either detect compilation errors, or provide 1407 multiple implementations for different smbd compilation options in one module 1408*/ 1409const struct dcesrv_critical_sizes *dcerpc_module_version(void) 1410{ 1411 static const struct dcesrv_critical_sizes critical_sizes = { 1412 DCERPC_MODULE_VERSION, 1413 sizeof(struct dcesrv_context), 1414 sizeof(struct dcesrv_endpoint), 1415 sizeof(struct dcesrv_endpoint_server), 1416 sizeof(struct dcesrv_interface), 1417 sizeof(struct dcesrv_if_list), 1418 sizeof(struct dcesrv_connection), 1419 sizeof(struct dcesrv_call_state), 1420 sizeof(struct dcesrv_auth), 1421 sizeof(struct dcesrv_handle) 1422 }; 1423 1424 return &critical_sizes; 1425} 1426 1427