1 /* 2 Unix SMB/CIFS implementation. 3 4 dcerpc utility functions 5 6 Copyright (C) Andrew Tridgell 2003 7 Copyright (C) Jelmer Vernooij 2004 8 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005 9 Copyright (C) Rafal Szczesniak 2006 10 11 This program is free software; you can redistribute it and/or modify 12 it under the terms of the GNU General Public License as published by 13 the Free Software Foundation; either version 3 of the License, or 14 (at your option) any later version. 15 16 This program is distributed in the hope that it will be useful, 17 but WITHOUT ANY WARRANTY; without even the implied warranty of 18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 GNU General Public License for more details. 20 21 You should have received a copy of the GNU General Public License 22 along with this program. If not, see <http://www.gnu.org/licenses/>. 23 */ 24 25 #include "includes.h" 26 #include "lib/events/events.h" 27 #include "libcli/composite/composite.h" 28 #include "librpc/gen_ndr/ndr_epmapper_c.h" 29 #include "librpc/gen_ndr/ndr_dcerpc.h" 30 #include "librpc/gen_ndr/ndr_misc.h" 31 #include "librpc/rpc/dcerpc_proto.h" 32 #include "auth/credentials/credentials.h" 33 #include "auth/gensec/gensec.h" 34 #include "param/param.h" 35 #include "librpc/rpc/rpc_common.h" 36 37 /* 38 find a dcerpc call on an interface by name 39 */ 40 const struct ndr_interface_call *dcerpc_iface_find_call(const struct ndr_interface_table *iface, 41 const char *name) 42 { 43 int i; 44 for (i=0;i<iface->num_calls;i++) { 45 if (strcmp(iface->calls[i].name, name) == 0) { continue_socket_connect(struct composite_context * ctx)46 return &iface->calls[i]; 47 } 48 } 49 return NULL; 50 } 51 52 struct epm_map_binding_state { 53 struct dcerpc_binding *binding; 54 const struct ndr_interface_table *table; 55 struct dcerpc_pipe *pipe; 56 struct policy_handle handle; 57 struct GUID object; 58 struct epm_twr_t twr; 59 struct epm_twr_t *twr_r; 60 uint32_t num_towers; 61 struct epm_Map r; 62 }; 63 64 65 static void continue_epm_recv_binding(struct composite_context *ctx); 66 static void continue_epm_map(struct tevent_req *subreq); 67 68 69 /* 70 Stage 2 of epm_map_binding: Receive connected rpc pipe and send endpoint 71 mapping rpc request 72 */ 73 static void continue_epm_recv_binding(struct composite_context *ctx) 74 { 75 struct composite_context *c = talloc_get_type(ctx->async.private_data, 76 struct composite_context); 77 struct epm_map_binding_state *s = talloc_get_type(c->private_data, 78 struct epm_map_binding_state); 79 struct tevent_req *subreq; 80 81 /* receive result of rpc pipe connect request */ 82 c->status = dcerpc_pipe_connect_b_recv(ctx, c, &s->pipe); 83 if (!composite_is_ok(c)) return; 84 85 c->status = dcerpc_binding_build_tower(s->pipe, s->binding, &s->twr.tower); 86 if (!composite_is_ok(c)) return; 87 88 /* with some nice pretty paper around it of course */ 89 s->r.in.object = &s->object; 90 s->r.in.map_tower = &s->twr; 91 s->r.in.entry_handle = &s->handle; 92 s->r.in.max_towers = 1; 93 s->r.out.entry_handle = &s->handle; 94 s->r.out.num_towers = &s->num_towers; 95 96 /* send request for an endpoint mapping - a rpc request on connected pipe */ 97 subreq = dcerpc_epm_Map_r_send(s, c->event_ctx, 98 s->pipe->binding_handle, 99 &s->r); 100 if (composite_nomem(subreq, c)) return; 101 102 tevent_req_set_callback(subreq, continue_epm_map, c); 103 } 104 105 106 /* 107 Stage 3 of epm_map_binding: Receive endpoint mapping and provide binding details 108 */ 109 static void continue_epm_map(struct tevent_req *subreq) 110 { 111 struct composite_context *c = tevent_req_callback_data(subreq, 112 struct composite_context); 113 struct epm_map_binding_state *s = talloc_get_type(c->private_data, 114 struct epm_map_binding_state); 115 const char *endpoint; 116 117 /* receive result of a rpc request */ 118 c->status = dcerpc_epm_Map_r_recv(subreq, s); 119 TALLOC_FREE(subreq); 120 if (!composite_is_ok(c)) return; 121 dcerpc_pipe_open_socket_send(TALLOC_CTX * mem_ctx,struct dcecli_connection * cn,struct socket_address * localaddr,struct socket_address * server,const char * target_hostname,const char * full_path,enum dcerpc_transport_t transport)122 /* check the details */ 123 if (s->r.out.result != 0 || *s->r.out.num_towers != 1) { 124 composite_error(c, NT_STATUS_PORT_UNREACHABLE); 125 return; 126 } 127 128 s->twr_r = s->r.out.towers[0].twr; 129 if (s->twr_r == NULL) { 130 composite_error(c, NT_STATUS_PORT_UNREACHABLE); 131 return; 132 } 133 134 if (s->twr_r->tower.num_floors != s->twr.tower.num_floors || 135 s->twr_r->tower.floors[3].lhs.protocol != s->twr.tower.floors[3].lhs.protocol) { 136 composite_error(c, NT_STATUS_PORT_UNREACHABLE); 137 return; 138 } 139 140 /* get received endpoint */ 141 endpoint = dcerpc_floor_get_rhs_data(s, &s->twr_r->tower.floors[3]); 142 if (composite_nomem(endpoint, c)) return; 143 144 c->status = dcerpc_binding_set_string_option(s->binding, 145 "endpoint", 146 endpoint); 147 if (!composite_is_ok(c)) { 148 return; 149 } 150 151 composite_done(c); 152 } 153 154 155 /* 156 Request for endpoint mapping of dcerpc binding - try to request for endpoint 157 unless there is default one. 158 */ 159 struct composite_context *dcerpc_epm_map_binding_send(TALLOC_CTX *mem_ctx, 160 struct dcerpc_binding *binding, 161 const struct ndr_interface_table *table, 162 struct cli_credentials *creds, 163 struct tevent_context *ev, dcerpc_pipe_open_socket_recv(struct composite_context * c,TALLOC_CTX * mem_ctx,struct socket_address ** localaddr)164 struct loadparm_context *lp_ctx) 165 { 166 struct composite_context *c; 167 struct epm_map_binding_state *s; 168 struct composite_context *pipe_connect_req; 169 NTSTATUS status; 170 struct dcerpc_binding *epmapper_binding; 171 int i; 172 173 if (ev == NULL) { 174 return NULL; 175 } 176 177 /* composite context allocation and setup */ 178 c = composite_create(mem_ctx, ev); 179 if (c == NULL) { 180 return NULL; 181 } 182 183 s = talloc_zero(c, struct epm_map_binding_state); 184 if (composite_nomem(s, c)) return c; 185 c->private_data = s; 186 187 s->binding = binding; 188 s->object = dcerpc_binding_get_object(binding); 189 s->table = table; 190 191 c->status = dcerpc_binding_set_abstract_syntax(binding, 192 &table->syntax_id); 193 if (!composite_is_ok(c)) { 194 return c; 195 } 196 197 /* 198 First, check if there is a default endpoint specified in the IDL 199 */ 200 for (i = 0; i < table->endpoints->count; i++) { 201 struct dcerpc_binding *default_binding; 202 enum dcerpc_transport_t transport; 203 enum dcerpc_transport_t dtransport; 204 const char *dendpoint = NULL; 205 206 status = dcerpc_parse_binding(s, 207 table->endpoints->names[i], 208 &default_binding); 209 if (!NT_STATUS_IS_OK(status)) { 210 continue; 211 } 212 213 transport = dcerpc_binding_get_transport(binding); 214 dtransport = dcerpc_binding_get_transport(default_binding); 215 if (transport == NCA_UNKNOWN) { 216 c->status = dcerpc_binding_set_transport(binding, 217 dtransport); 218 if (!composite_is_ok(c)) { 219 return c; 220 } 221 transport = dtransport; 222 } 223 224 if (transport != dtransport) { 225 TALLOC_FREE(default_binding); 226 continue; 227 } 228 229 dendpoint = dcerpc_binding_get_string_option(default_binding, 230 "endpoint"); 231 if (dendpoint == NULL) { 232 TALLOC_FREE(default_binding); 233 continue; 234 } 235 236 c->status = dcerpc_binding_set_string_option(binding, 237 "endpoint", 238 dendpoint); 239 if (!composite_is_ok(c)) { 240 return c; 241 } 242 243 TALLOC_FREE(default_binding); 244 composite_done(c); 245 return c; 246 } 247 248 epmapper_binding = dcerpc_binding_dup(s, binding); 249 if (composite_nomem(epmapper_binding, c)) return c; 250 251 /* basic endpoint mapping data */ 252 c->status = dcerpc_binding_set_string_option(epmapper_binding, 253 "endpoint", NULL); 254 if (!composite_is_ok(c)) { 255 return c; 256 } 257 c->status = dcerpc_binding_set_flags(epmapper_binding, 0, UINT32_MAX); 258 if (!composite_is_ok(c)) { 259 return c; 260 } 261 c->status = dcerpc_binding_set_assoc_group_id(epmapper_binding, 0); 262 if (!composite_is_ok(c)) { 263 return c; 264 } 265 c->status = dcerpc_binding_set_object(epmapper_binding, GUID_zero()); 266 if (!composite_is_ok(c)) { 267 return c; 268 } 269 270 /* initiate rpc pipe connection */ 271 pipe_connect_req = dcerpc_pipe_connect_b_send(s, epmapper_binding, 272 &ndr_table_epmapper, 273 creds, c->event_ctx, 274 lp_ctx); 275 if (composite_nomem(pipe_connect_req, c)) return c; 276 277 composite_continue(c, pipe_connect_req, continue_epm_recv_binding, c); 278 return c; 279 } 280 281 282 /* 283 Receive result of endpoint mapping request 284 */ 285 NTSTATUS dcerpc_epm_map_binding_recv(struct composite_context *c) 286 { 287 NTSTATUS status = composite_wait(c); 288 289 talloc_free(c); 290 return status; 291 } 292 293 294 /* 295 Get endpoint mapping for rpc connection 296 */ 297 _PUBLIC_ NTSTATUS dcerpc_epm_map_binding(TALLOC_CTX *mem_ctx, struct dcerpc_binding *binding, 298 const struct ndr_interface_table *table, struct tevent_context *ev, 299 struct loadparm_context *lp_ctx) 300 { 301 struct composite_context *c; 302 struct cli_credentials *epm_creds; 303 304 epm_creds = cli_credentials_init_anon(mem_ctx); 305 if (epm_creds == NULL) { 306 return NT_STATUS_NO_MEMORY; 307 } 308 c = dcerpc_epm_map_binding_send(mem_ctx, binding, table, epm_creds, ev, lp_ctx); 309 if (c == NULL) { 310 talloc_free(epm_creds); 311 return NT_STATUS_NO_MEMORY; 312 } 313 talloc_steal(c, epm_creds); 314 return dcerpc_epm_map_binding_recv(c); 315 } 316 317 318 struct pipe_auth_state { 319 struct dcerpc_pipe *pipe; 320 const struct dcerpc_binding *binding; 321 const struct ndr_interface_table *table; 322 struct loadparm_context *lp_ctx; 323 struct cli_credentials *credentials; dcerpc_pipe_open_tcp_recv(struct composite_context * c,TALLOC_CTX * mem_ctx,char ** localaddr,char ** remoteaddr)324 unsigned int logon_retries; 325 }; 326 327 328 static void continue_auth_schannel(struct composite_context *ctx); 329 static void continue_auth(struct composite_context *ctx); 330 static void continue_auth_none(struct composite_context *ctx); 331 static void continue_ntlmssp_connection(struct composite_context *ctx); 332 static void continue_spnego_after_wrong_pass(struct composite_context *ctx); 333 334 335 /* 336 Stage 2 of pipe_auth: Receive result of schannel bind request 337 */ 338 static void continue_auth_schannel(struct composite_context *ctx) 339 { 340 struct composite_context *c = talloc_get_type(ctx->async.private_data, 341 struct composite_context); 342 343 c->status = dcerpc_bind_auth_schannel_recv(ctx); 344 if (!composite_is_ok(c)) return; 345 346 composite_done(c); 347 } 348 349 350 /* 351 Stage 2 of pipe_auth: Receive result of authenticated bind request 352 */ 353 static void continue_auth(struct composite_context *ctx) 354 { 355 struct composite_context *c = talloc_get_type(ctx->async.private_data, 356 struct composite_context); 357 358 c->status = dcerpc_bind_auth_recv(ctx); 359 if (!composite_is_ok(c)) return; continue_unix_open_socket(struct composite_context * ctx)360 361 composite_done(c); 362 } 363 /* 364 Stage 2 of pipe_auth: Receive result of authenticated bind request, but handle fallbacks: 365 SPNEGO -> NTLMSSP 366 */ 367 static void continue_auth_auto(struct composite_context *ctx) 368 { 369 struct composite_context *c = talloc_get_type(ctx->async.private_data, 370 struct composite_context); 371 struct pipe_auth_state *s = talloc_get_type(c->private_data, struct pipe_auth_state); 372 struct composite_context *sec_conn_req; 373 374 c->status = dcerpc_bind_auth_recv(ctx); 375 if (NT_STATUS_EQUAL(c->status, NT_STATUS_INVALID_PARAMETER)) { 376 /* 377 * Retry with NTLMSSP auth as fallback dcerpc_pipe_open_unix_stream_send(struct dcecli_connection * conn,const char * path)378 * send a request for secondary rpc connection 379 */ 380 sec_conn_req = dcerpc_secondary_connection_send(s->pipe, 381 s->binding); 382 composite_continue(c, sec_conn_req, continue_ntlmssp_connection, c); 383 return; 384 } else if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE) || 385 NT_STATUS_EQUAL(c->status, NT_STATUS_UNSUCCESSFUL)) { 386 /* 387 try a second time on any error. We don't just do it 388 on LOGON_FAILURE as some servers will give a 389 NT_STATUS_UNSUCCESSFUL on a authentication error on RPC 390 */ 391 const char *principal; 392 const char *endpoint; 393 394 principal = gensec_get_target_principal(s->pipe->conn->security_state.generic_state); 395 if (principal == NULL) { 396 const char *hostname = gensec_get_target_hostname(s->pipe->conn->security_state.generic_state); 397 const char *service = gensec_get_target_service(s->pipe->conn->security_state.generic_state); 398 if (hostname != NULL && service != NULL) { 399 principal = talloc_asprintf(c, "%s/%s", service, hostname); 400 } 401 } 402 403 endpoint = dcerpc_binding_get_string_option(s->binding, "endpoint"); 404 405 if ((cli_credentials_failed_kerberos_login(s->credentials, principal, &s->logon_retries) || 406 cli_credentials_wrong_password(s->credentials)) && 407 endpoint != NULL) { 408 /* 409 * Retry SPNEGO with a better password 410 * send a request for secondary rpc connection 411 */ 412 sec_conn_req = dcerpc_secondary_connection_send(s->pipe, 413 s->binding); 414 composite_continue(c, sec_conn_req, continue_spnego_after_wrong_pass, c); dcerpc_pipe_open_unix_stream_recv(struct composite_context * c)415 return; 416 } 417 } 418 419 if (!composite_is_ok(c)) return; 420 421 composite_done(c); 422 } 423 424 /* 425 Stage 3 of pipe_auth (fallback to NTLMSSP case): Receive secondary 426 rpc connection (the first one can't be used any more, due to the continue_np_open_socket(struct composite_context * ctx)427 bind nak) and perform authenticated bind request 428 */ 429 static void continue_ntlmssp_connection(struct composite_context *ctx) 430 { 431 struct composite_context *c; 432 struct pipe_auth_state *s; 433 struct composite_context *auth_req; 434 struct dcerpc_pipe *p2; 435 void *pp; 436 437 c = talloc_get_type(ctx->async.private_data, struct composite_context); 438 s = talloc_get_type(c->private_data, struct pipe_auth_state); 439 440 /* receive secondary rpc connection */ 441 c->status = dcerpc_secondary_connection_recv(ctx, &p2); 442 if (!composite_is_ok(c)) return; 443 444 445 /* this is a rather strange situation. When 446 we come into the routine, s is a child of s->pipe, and 447 when we created p2 above, it also became a child of 448 s->pipe. 449 450 Now we want p2 to be a parent of s->pipe, and we want s to 451 be a parent of both of them! If we don't do this very 452 carefully we end up creating a talloc loop 453 */ 454 455 /* we need the new contexts to hang off the same context 456 that s->pipe is on, but the only way to get that is 457 via talloc_parent() */ 458 pp = talloc_parent(s->pipe); 459 460 /* promote s to be at the top */ 461 talloc_steal(pp, s); 462 463 /* and put p2 under s */ 464 talloc_steal(s, p2); 465 466 /* now put s->pipe under p2 */ 467 talloc_steal(p2, s->pipe); 468 469 s->pipe = p2; 470 471 /* initiate a authenticated bind */ 472 auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table, 473 s->credentials, 474 lpcfg_gensec_settings(c, s->lp_ctx), 475 DCERPC_AUTH_TYPE_NTLMSSP, 476 dcerpc_auth_level(s->pipe->conn), 477 s->table->authservices->names[0]); 478 composite_continue(c, auth_req, continue_auth, c); 479 } 480 481 /* 482 Stage 3 of pipe_auth (retry on wrong password): Receive secondary dcerpc_pipe_open_pipe_recv(struct composite_context * c)483 rpc connection (the first one can't be used any more, due to the 484 bind nak) and perform authenticated bind request 485 */ 486 static void continue_spnego_after_wrong_pass(struct composite_context *ctx) 487 { 488 struct composite_context *c; 489 struct pipe_auth_state *s; 490 struct composite_context *auth_req; 491 struct dcerpc_pipe *p2; 492 493 c = talloc_get_type(ctx->async.private_data, struct composite_context); 494 s = talloc_get_type(c->private_data, struct pipe_auth_state); 495 496 /* receive secondary rpc connection */ 497 c->status = dcerpc_secondary_connection_recv(ctx, &p2); 498 if (!composite_is_ok(c)) return; 499 500 talloc_steal(s, p2); 501 talloc_steal(p2, s->pipe); 502 s->pipe = p2; 503 504 /* initiate a authenticated bind */ 505 auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table, 506 s->credentials, 507 lpcfg_gensec_settings(c, s->lp_ctx), 508 DCERPC_AUTH_TYPE_SPNEGO, 509 dcerpc_auth_level(s->pipe->conn), 510 s->table->authservices->names[0]); 511 composite_continue(c, auth_req, continue_auth, c); 512 } 513 514 515 /* 516 Stage 2 of pipe_auth: Receive result of non-authenticated bind request 517 */ 518 static void continue_auth_none(struct composite_context *ctx) 519 { 520 struct composite_context *c = talloc_get_type(ctx->async.private_data, 521 struct composite_context); 522 523 c->status = dcerpc_bind_auth_none_recv(ctx); 524 if (!composite_is_ok(c)) return; 525 526 composite_done(c); 527 } 528 529 530 /* 531 Request to perform an authenticated bind if required. Authentication 532 is determined using credentials passed and binding flags. 533 */ 534 struct composite_context *dcerpc_pipe_auth_send(struct dcerpc_pipe *p, 535 const struct dcerpc_binding *binding, 536 const struct ndr_interface_table *table, 537 struct cli_credentials *credentials, 538 struct loadparm_context *lp_ctx) 539 { 540 struct composite_context *c; 541 struct pipe_auth_state *s; 542 struct composite_context *auth_schannel_req; 543 struct composite_context *auth_req; 544 struct composite_context *auth_none_req; 545 struct dcecli_connection *conn; 546 uint8_t auth_type; 547 548 /* composite context allocation and setup */ 549 c = composite_create(p, p->conn->event_ctx); 550 if (c == NULL) return NULL; 551 552 s = talloc_zero(c, struct pipe_auth_state); 553 if (composite_nomem(s, c)) return c; 554 c->private_data = s; 555 556 /* store parameters in state structure */ 557 s->binding = binding; 558 s->table = table; 559 s->credentials = credentials; 560 s->pipe = p; 561 s->lp_ctx = lp_ctx; 562 563 conn = s->pipe->conn; 564 conn->flags = dcerpc_binding_get_flags(binding); 565 566 if (DEBUGLVL(100)) { 567 conn->flags |= DCERPC_DEBUG_PRINT_BOTH; 568 } 569 570 if (conn->transport.transport == NCALRPC) { 571 const char *v = dcerpc_binding_get_string_option(binding, 572 "auth_type"); 573 574 if (v != NULL && strcmp(v, "ncalrpc_as_system") == 0) { 575 auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table, 576 s->credentials, 577 lpcfg_gensec_settings(c, s->lp_ctx), 578 DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM, 579 DCERPC_AUTH_LEVEL_CONNECT, 580 s->table->authservices->names[0]); 581 composite_continue(c, auth_req, continue_auth, c); 582 return c; 583 } 584 } 585 586 if (cli_credentials_is_anonymous(s->credentials)) { 587 auth_none_req = dcerpc_bind_auth_none_send(c, s->pipe, s->table); 588 composite_continue(c, auth_none_req, continue_auth_none, c); 589 return c; 590 } 591 592 if ((conn->flags & DCERPC_SCHANNEL) && 593 !cli_credentials_get_netlogon_creds(s->credentials)) { 594 /* If we don't already have netlogon credentials for 595 * the schannel bind, then we have to get these 596 * first */ 597 auth_schannel_req = dcerpc_bind_auth_schannel_send(c, s->pipe, s->table, 598 s->credentials, s->lp_ctx, 599 dcerpc_auth_level(conn)); 600 composite_continue(c, auth_schannel_req, continue_auth_schannel, c); 601 return c; 602 } 603 604 /* 605 * we rely on the already authenticated CIFS connection 606 * if not doing sign or seal 607 */ 608 if (conn->transport.transport == NCACN_NP && 609 !(conn->flags & (DCERPC_PACKET|DCERPC_SIGN|DCERPC_SEAL))) { 610 auth_none_req = dcerpc_bind_auth_none_send(c, s->pipe, s->table); 611 composite_continue(c, auth_none_req, continue_auth_none, c); 612 return c; 613 } 614 615 616 /* Perform an authenticated DCE-RPC bind 617 */ 618 if (!(conn->flags & (DCERPC_CONNECT|DCERPC_SEAL|DCERPC_PACKET))) { 619 /* 620 we are doing an authenticated connection, 621 which needs to use [connect], [sign] or [seal]. 622 If nothing is specified, we default to [sign] now. 623 This give roughly the same protection as 624 ncacn_np with smb signing. 625 */ 626 conn->flags |= DCERPC_SIGN; 627 } 628 629 if (conn->flags & DCERPC_AUTH_SPNEGO) { 630 auth_type = DCERPC_AUTH_TYPE_SPNEGO; 631 632 } else if (conn->flags & DCERPC_AUTH_KRB5) { 633 auth_type = DCERPC_AUTH_TYPE_KRB5; 634 635 } else if (conn->flags & DCERPC_SCHANNEL) { 636 auth_type = DCERPC_AUTH_TYPE_SCHANNEL; 637 638 } else if (conn->flags & DCERPC_AUTH_NTLM) { 639 auth_type = DCERPC_AUTH_TYPE_NTLMSSP; 640 641 } else { 642 /* try SPNEGO with fallback to NTLMSSP */ 643 auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table, 644 s->credentials, 645 lpcfg_gensec_settings(c, s->lp_ctx), 646 DCERPC_AUTH_TYPE_SPNEGO, 647 dcerpc_auth_level(conn), 648 s->table->authservices->names[0]); 649 composite_continue(c, auth_req, continue_auth_auto, c); 650 return c; 651 } 652 653 auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table, 654 s->credentials, 655 lpcfg_gensec_settings(c, s->lp_ctx), 656 auth_type, 657 dcerpc_auth_level(conn), 658 s->table->authservices->names[0]); 659 composite_continue(c, auth_req, continue_auth, c); 660 return c; 661 } 662 663 664 /* 665 Receive result of authenticated bind request on dcerpc pipe 666 667 This returns *p, which may be different to the one originally 668 supllied, as it rebinds to a new pipe due to authentication fallback 669 670 */ 671 NTSTATUS dcerpc_pipe_auth_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, 672 struct dcerpc_pipe **p) 673 { 674 NTSTATUS status; 675 676 struct pipe_auth_state *s = talloc_get_type(c->private_data, 677 struct pipe_auth_state); 678 status = composite_wait(c); 679 if (!NT_STATUS_IS_OK(status)) { 680 char *uuid_str = GUID_string(s->pipe, &s->table->syntax_id.uuid); 681 DEBUG(0, ("Failed to bind to uuid %s for %s %s\n", uuid_str, 682 dcerpc_binding_string(uuid_str, s->binding), nt_errstr(status))); 683 talloc_free(uuid_str); 684 } else { 685 talloc_steal(mem_ctx, s->pipe); 686 *p = s->pipe; 687 } 688 689 talloc_free(c); 690 return status; 691 } 692 693 694 /* 695 Perform an authenticated bind if needed - sync version 696 697 This may change *p, as it rebinds to a new pipe due to authentication fallback 698 */ 699 _PUBLIC_ NTSTATUS dcerpc_pipe_auth(TALLOC_CTX *mem_ctx, 700 struct dcerpc_pipe **p, 701 const struct dcerpc_binding *binding, 702 const struct ndr_interface_table *table, 703 struct cli_credentials *credentials, 704 struct loadparm_context *lp_ctx) 705 { 706 struct composite_context *c; 707 708 c = dcerpc_pipe_auth_send(*p, binding, table, credentials, lp_ctx); 709 return dcerpc_pipe_auth_recv(c, mem_ctx, p); 710 } 711 712 713 NTSTATUS dcecli_generic_session_key(struct dcecli_connection *c, 714 DATA_BLOB *session_key) 715 { 716 if (c != NULL) { 717 if (c->transport.transport != NCALRPC && 718 c->transport.transport != NCACN_UNIX_STREAM) 719 { 720 return NT_STATUS_LOCAL_USER_SESSION_KEY; 721 } 722 } 723 724 return dcerpc_generic_session_key(session_key); 725 } 726 727 /* 728 fetch the user session key - may be default (above) or the SMB session key 729 730 The key is always truncated to 16 bytes 731 */ 732 _PUBLIC_ NTSTATUS dcerpc_fetch_session_key(struct dcerpc_pipe *p, 733 DATA_BLOB *session_key) 734 { 735 NTSTATUS status; 736 status = p->conn->security_state.session_key(p->conn, session_key); 737 if (!NT_STATUS_IS_OK(status)) { 738 return status; 739 } 740 741 session_key->length = MIN(session_key->length, 16); 742 743 return NT_STATUS_OK; 744 } 745 746 /* 747 create a secondary context from a primary connection 748 749 this uses dcerpc_alter_context() to create a new dcerpc context_id 750 */ 751 _PUBLIC_ NTSTATUS dcerpc_secondary_context(struct dcerpc_pipe *p, 752 struct dcerpc_pipe **pp2, 753 const struct ndr_interface_table *table) 754 { 755 NTSTATUS status; 756 struct dcerpc_pipe *p2; 757 struct GUID *object = NULL; 758 759 p2 = talloc_zero(p, struct dcerpc_pipe); 760 if (p2 == NULL) { 761 return NT_STATUS_NO_MEMORY; 762 } 763 p2->conn = talloc_reference(p2, p->conn); 764 p2->request_timeout = p->request_timeout; 765 766 p2->context_id = ++p->conn->next_context_id; 767 768 p2->syntax = table->syntax_id; 769 770 p2->transfer_syntax = p->transfer_syntax; 771 772 p2->binding = dcerpc_binding_dup(p2, p->binding); 773 if (p2->binding == NULL) { 774 talloc_free(p2); 775 return NT_STATUS_NO_MEMORY; 776 } 777 778 p2->object = dcerpc_binding_get_object(p2->binding); 779 if (!GUID_all_zero(&p2->object)) { 780 object = &p2->object; 781 } 782 783 p2->binding_handle = dcerpc_pipe_binding_handle(p2, object, table); 784 if (p2->binding_handle == NULL) { 785 talloc_free(p2); 786 return NT_STATUS_NO_MEMORY; 787 } 788 789 status = dcerpc_alter_context(p2, p2, &p2->syntax, &p2->transfer_syntax); 790 if (!NT_STATUS_IS_OK(status)) { 791 talloc_free(p2); 792 return status; 793 } 794 795 *pp2 = p2; 796 797 return NT_STATUS_OK; 798 } 799