Changeset 77 for trunk/samba/source/libads/sasl.c
- Timestamp:
- Sep 30, 2007, 1:42:50 AM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/samba/source/libads/sasl.c
r26 r77 6 6 This program is free software; you can redistribute it and/or modify 7 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2of the License, or8 the Free Software Foundation; either version 3 of the License, or 9 9 (at your option) any later version. 10 10 … … 15 15 16 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 19 18 */ 20 19 … … 22 21 23 22 #ifdef HAVE_LDAP 23 24 static ADS_STATUS ads_sasl_ntlmssp_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len) 25 { 26 struct ntlmssp_state *ntlmssp_state = 27 (struct ntlmssp_state *)ads->ldap.wrap_private_data; 28 ADS_STATUS status; 29 NTSTATUS nt_status; 30 DATA_BLOB sig; 31 uint8 *dptr = ads->ldap.out.buf + (4 + NTLMSSP_SIG_SIZE); 32 33 /* copy the data to the right location */ 34 memcpy(dptr, buf, len); 35 36 /* create the signature and may encrypt the data */ 37 if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) { 38 nt_status = ntlmssp_seal_packet(ntlmssp_state, 39 dptr, len, 40 dptr, len, 41 &sig); 42 } else { 43 nt_status = ntlmssp_sign_packet(ntlmssp_state, 44 dptr, len, 45 dptr, len, 46 &sig); 47 } 48 status = ADS_ERROR_NT(nt_status); 49 if (!ADS_ERR_OK(status)) return status; 50 51 /* copy the signature to the right location */ 52 memcpy(ads->ldap.out.buf + 4, 53 sig.data, NTLMSSP_SIG_SIZE); 54 55 data_blob_free(&sig); 56 57 /* set how many bytes must be written to the underlying socket */ 58 ads->ldap.out.left = 4 + NTLMSSP_SIG_SIZE + len; 59 60 return ADS_SUCCESS; 61 } 62 63 static ADS_STATUS ads_sasl_ntlmssp_unwrap(ADS_STRUCT *ads) 64 { 65 struct ntlmssp_state *ntlmssp_state = 66 (struct ntlmssp_state *)ads->ldap.wrap_private_data; 67 ADS_STATUS status; 68 NTSTATUS nt_status; 69 DATA_BLOB sig; 70 uint8 *dptr = ads->ldap.in.buf + (4 + NTLMSSP_SIG_SIZE); 71 uint32 dlen = ads->ldap.in.ofs - (4 + NTLMSSP_SIG_SIZE); 72 73 /* wrap the signature into a DATA_BLOB */ 74 sig = data_blob_const(ads->ldap.in.buf + 4, NTLMSSP_SIG_SIZE); 75 76 /* verify the signature and maybe decrypt the data */ 77 if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) { 78 nt_status = ntlmssp_unseal_packet(ntlmssp_state, 79 dptr, dlen, 80 dptr, dlen, 81 &sig); 82 } else { 83 nt_status = ntlmssp_check_packet(ntlmssp_state, 84 dptr, dlen, 85 dptr, dlen, 86 &sig); 87 } 88 status = ADS_ERROR_NT(nt_status); 89 if (!ADS_ERR_OK(status)) return status; 90 91 /* set the amount of bytes for the upper layer and set the ofs to the data */ 92 ads->ldap.in.left = dlen; 93 ads->ldap.in.ofs = 4 + NTLMSSP_SIG_SIZE; 94 95 return ADS_SUCCESS; 96 } 97 98 static void ads_sasl_ntlmssp_disconnect(ADS_STRUCT *ads) 99 { 100 struct ntlmssp_state *ntlmssp_state = 101 (struct ntlmssp_state *)ads->ldap.wrap_private_data; 102 103 ntlmssp_end(&ntlmssp_state); 104 105 ads->ldap.wrap_ops = NULL; 106 ads->ldap.wrap_private_data = NULL; 107 } 108 109 static const struct ads_saslwrap_ops ads_sasl_ntlmssp_ops = { 110 .name = "ntlmssp", 111 .wrap = ads_sasl_ntlmssp_wrap, 112 .unwrap = ads_sasl_ntlmssp_unwrap, 113 .disconnect = ads_sasl_ntlmssp_disconnect 114 }; 24 115 25 116 /* … … 29 120 static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads) 30 121 { 31 DATA_BLOB msg1 = data_blob (NULL, 0);32 DATA_BLOB blob = data_blob (NULL, 0);33 DATA_BLOB blob_in = data_blob (NULL, 0);34 DATA_BLOB blob_out = data_blob (NULL, 0);122 DATA_BLOB msg1 = data_blob_null; 123 DATA_BLOB blob = data_blob_null; 124 DATA_BLOB blob_in = data_blob_null; 125 DATA_BLOB blob_out = data_blob_null; 35 126 struct berval cred, *scred = NULL; 36 127 int rc; 37 128 NTSTATUS nt_status; 129 ADS_STATUS status; 38 130 int turn = 1; 131 uint32 features = 0; 39 132 40 133 struct ntlmssp_state *ntlmssp_state; … … 55 148 } 56 149 57 blob_in = data_blob(NULL, 0); 150 switch (ads->ldap.wrap_type) { 151 case ADS_SASLWRAP_TYPE_SEAL: 152 features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL; 153 break; 154 case ADS_SASLWRAP_TYPE_SIGN: 155 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) { 156 features = NTLMSSP_FEATURE_SIGN; 157 } else { 158 /* 159 * windows servers are broken with sign only, 160 * so we need to use seal here too 161 */ 162 features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL; 163 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL; 164 } 165 break; 166 case ADS_SASLWRAP_TYPE_PLAIN: 167 break; 168 } 169 170 ntlmssp_want_feature(ntlmssp_state, features); 171 172 blob_in = data_blob_null; 58 173 59 174 do { … … 77 192 cred.bv_len = msg1.length; 78 193 scred = NULL; 79 rc = ldap_sasl_bind_s(ads->ld , NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);194 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred); 80 195 data_blob_free(&msg1); 81 196 if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) { … … 91 206 ber_bvfree(scred); 92 207 } else { 93 blob = data_blob (NULL, 0);208 blob = data_blob_null; 94 209 } 95 210 … … 103 218 if ((turn == 1) && 104 219 (rc == LDAP_SASL_BIND_IN_PROGRESS)) { 105 DATA_BLOB tmp_blob = data_blob (NULL, 0);220 DATA_BLOB tmp_blob = data_blob_null; 106 221 /* the server might give us back two challenges */ 107 222 if (!spnego_parse_challenge(blob, &blob_in, … … 115 230 data_blob_free(&tmp_blob); 116 231 } else if (rc == LDAP_SASL_BIND_IN_PROGRESS) { 117 if (!spnego_parse_auth_response(blob, nt_status, 232 if (!spnego_parse_auth_response(blob, nt_status, OID_NTLMSSP, 118 233 &blob_in)) { 119 234 … … 132 247 then the state will be kept by the signing engine */ 133 248 134 ntlmssp_end(&ntlmssp_state); 249 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) { 250 ads->ldap.out.max_unwrapped = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED - NTLMSSP_SIG_SIZE; 251 ads->ldap.out.sig_size = NTLMSSP_SIG_SIZE; 252 ads->ldap.in.min_wrapped = ads->ldap.out.sig_size; 253 ads->ldap.in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED; 254 status = ads_setup_sasl_wrapping(ads, &ads_sasl_ntlmssp_ops, ntlmssp_state); 255 if (!ADS_ERR_OK(status)) { 256 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n", 257 ads_errstr(status))); 258 ntlmssp_end(&ntlmssp_state); 259 return status; 260 } 261 } else { 262 ntlmssp_end(&ntlmssp_state); 263 } 135 264 136 265 return ADS_ERROR(rc); 137 266 } 138 267 268 #ifdef HAVE_GSSAPI 269 static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len) 270 { 271 gss_ctx_id_t context_handle = ads->ldap.wrap_private_data; 272 ADS_STATUS status; 273 int gss_rc; 274 uint32 minor_status; 275 gss_buffer_desc unwrapped, wrapped; 276 int conf_req_flag, conf_state; 277 278 unwrapped.value = buf; 279 unwrapped.length = len; 280 281 /* for now request sign and seal */ 282 conf_req_flag = (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL); 283 284 gss_rc = gss_wrap(&minor_status, context_handle, 285 conf_req_flag, GSS_C_QOP_DEFAULT, 286 &unwrapped, &conf_state, 287 &wrapped); 288 status = ADS_ERROR_GSS(gss_rc, minor_status); 289 if (!ADS_ERR_OK(status)) return status; 290 291 if (conf_req_flag && conf_state == 0) { 292 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED); 293 } 294 295 if ((ads->ldap.out.size - 4) < wrapped.length) { 296 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR); 297 } 298 299 /* copy the wrapped blob to the right location */ 300 memcpy(ads->ldap.out.buf + 4, wrapped.value, wrapped.length); 301 302 /* set how many bytes must be written to the underlying socket */ 303 ads->ldap.out.left = 4 + wrapped.length; 304 305 gss_release_buffer(&minor_status, &wrapped); 306 307 return ADS_SUCCESS; 308 } 309 310 static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads) 311 { 312 gss_ctx_id_t context_handle = ads->ldap.wrap_private_data; 313 ADS_STATUS status; 314 int gss_rc; 315 uint32 minor_status; 316 gss_buffer_desc unwrapped, wrapped; 317 int conf_state; 318 319 wrapped.value = ads->ldap.in.buf + 4; 320 wrapped.length = ads->ldap.in.ofs - 4; 321 322 gss_rc = gss_unwrap(&minor_status, context_handle, 323 &wrapped, &unwrapped, 324 &conf_state, GSS_C_QOP_DEFAULT); 325 status = ADS_ERROR_GSS(gss_rc, minor_status); 326 if (!ADS_ERR_OK(status)) return status; 327 328 if (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) { 329 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED); 330 } 331 332 if (wrapped.length < wrapped.length) { 333 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR); 334 } 335 336 /* copy the wrapped blob to the right location */ 337 memcpy(ads->ldap.in.buf + 4, unwrapped.value, unwrapped.length); 338 339 /* set how many bytes must be written to the underlying socket */ 340 ads->ldap.in.left = unwrapped.length; 341 ads->ldap.in.ofs = 4; 342 343 gss_release_buffer(&minor_status, &unwrapped); 344 345 return ADS_SUCCESS; 346 } 347 348 static void ads_sasl_gssapi_disconnect(ADS_STRUCT *ads) 349 { 350 gss_ctx_id_t context_handle = ads->ldap.wrap_private_data; 351 uint32 minor_status; 352 353 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER); 354 355 ads->ldap.wrap_ops = NULL; 356 ads->ldap.wrap_private_data = NULL; 357 } 358 359 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = { 360 .name = "gssapi", 361 .wrap = ads_sasl_gssapi_wrap, 362 .unwrap = ads_sasl_gssapi_unwrap, 363 .disconnect = ads_sasl_gssapi_disconnect 364 }; 365 366 /* 367 perform a LDAP/SASL/SPNEGO/GSSKRB5 bind 368 */ 369 static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const gss_name_t serv_name) 370 { 371 ADS_STATUS status; 372 BOOL ok; 373 uint32 minor_status; 374 int gss_rc, rc; 375 gss_OID_desc krb5_mech_type = 376 {9, CONST_DISCARD(char *, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") }; 377 gss_OID mech_type = &krb5_mech_type; 378 gss_OID actual_mech_type = GSS_C_NULL_OID; 379 const char *spnego_mechs[] = {OID_KERBEROS5_OLD, OID_KERBEROS5, OID_NTLMSSP, NULL}; 380 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT; 381 gss_buffer_desc input_token, output_token; 382 uint32 req_flags, ret_flags; 383 uint32 req_tmp, ret_tmp; 384 DATA_BLOB unwrapped; 385 DATA_BLOB wrapped; 386 struct berval cred, *scred = NULL; 387 388 input_token.value = NULL; 389 input_token.length = 0; 390 391 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG; 392 switch (ads->ldap.wrap_type) { 393 case ADS_SASLWRAP_TYPE_SEAL: 394 req_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG; 395 break; 396 case ADS_SASLWRAP_TYPE_SIGN: 397 req_flags |= GSS_C_INTEG_FLAG; 398 break; 399 case ADS_SASLWRAP_TYPE_PLAIN: 400 break; 401 } 402 403 /* Note: here we explicit ask for the krb5 mech_type */ 404 gss_rc = gss_init_sec_context(&minor_status, 405 GSS_C_NO_CREDENTIAL, 406 &context_handle, 407 serv_name, 408 mech_type, 409 req_flags, 410 0, 411 NULL, 412 &input_token, 413 &actual_mech_type, 414 &output_token, 415 &ret_flags, 416 NULL); 417 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) { 418 status = ADS_ERROR_GSS(gss_rc, minor_status); 419 goto failed; 420 } 421 422 /* 423 * As some gssapi krb5 mech implementations 424 * automaticly add GSS_C_INTEG_FLAG and GSS_C_CONF_FLAG 425 * to req_flags internaly, it's not possible to 426 * use plain or signing only connection via 427 * the gssapi interface. 428 * 429 * Because of this we need to check it the ret_flags 430 * has more flags as req_flags and correct the value 431 * of ads->ldap.wrap_type. 432 * 433 * I ads->auth.flags has ADS_AUTH_SASL_FORCE 434 * we need to give an error. 435 */ 436 req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG); 437 ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG); 438 439 if (req_tmp == ret_tmp) { 440 /* everythings fine... */ 441 442 } else if (req_flags & GSS_C_CONF_FLAG) { 443 /* 444 * here we wanted sealing but didn't got it 445 * from the gssapi library 446 */ 447 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED); 448 goto failed; 449 450 } else if ((req_flags & GSS_C_INTEG_FLAG) && 451 !(ret_flags & GSS_C_INTEG_FLAG)) { 452 /* 453 * here we wanted siging but didn't got it 454 * from the gssapi library 455 */ 456 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED); 457 goto failed; 458 459 } else if (ret_flags & GSS_C_CONF_FLAG) { 460 /* 461 * here we didn't want sealing 462 * but the gssapi library forces it 463 * so correct the needed wrap_type if 464 * the caller didn't forced siging only 465 */ 466 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) { 467 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED); 468 goto failed; 469 } 470 471 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL; 472 req_flags = ret_flags; 473 474 } else if (ret_flags & GSS_C_INTEG_FLAG) { 475 /* 476 * here we didn't want signing 477 * but the gssapi library forces it 478 * so correct the needed wrap_type if 479 * the caller didn't forced plain 480 */ 481 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) { 482 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED); 483 goto failed; 484 } 485 486 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN; 487 req_flags = ret_flags; 488 } else { 489 /* 490 * This could (should?) not happen 491 */ 492 status = ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR); 493 goto failed; 494 495 } 496 497 /* and wrap that in a shiny SPNEGO wrapper */ 498 unwrapped = data_blob_const(output_token.value, output_token.length); 499 wrapped = gen_negTokenTarg(spnego_mechs, unwrapped); 500 gss_release_buffer(&minor_status, &output_token); 501 if (unwrapped.length > wrapped.length) { 502 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY); 503 goto failed; 504 } 505 506 cred.bv_val = (char *)wrapped.data; 507 cred.bv_len = wrapped.length; 508 509 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, 510 &scred); 511 data_blob_free(&wrapped); 512 if (rc != LDAP_SUCCESS) { 513 status = ADS_ERROR(rc); 514 goto failed; 515 } 516 517 if (scred) { 518 wrapped = data_blob_const(scred->bv_val, scred->bv_len); 519 } else { 520 wrapped = data_blob_null; 521 } 522 523 ok = spnego_parse_auth_response(wrapped, NT_STATUS_OK, 524 OID_KERBEROS5_OLD, 525 &unwrapped); 526 if (scred) ber_bvfree(scred); 527 if (!ok) { 528 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE); 529 goto failed; 530 } 531 532 input_token.value = unwrapped.data; 533 input_token.length = unwrapped.length; 534 535 /* 536 * As we asked for mutal authentication 537 * we need to pass the servers response 538 * to gssapi 539 */ 540 gss_rc = gss_init_sec_context(&minor_status, 541 GSS_C_NO_CREDENTIAL, 542 &context_handle, 543 serv_name, 544 mech_type, 545 req_flags, 546 0, 547 NULL, 548 &input_token, 549 &actual_mech_type, 550 &output_token, 551 &ret_flags, 552 NULL); 553 data_blob_free(&unwrapped); 554 if (gss_rc) { 555 status = ADS_ERROR_GSS(gss_rc, minor_status); 556 goto failed; 557 } 558 559 gss_release_buffer(&minor_status, &output_token); 560 561 /* 562 * If we the sign and seal options 563 * doesn't match after getting the response 564 * from the server, we don't want to use the connection 565 */ 566 req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG); 567 ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG); 568 569 if (req_tmp != ret_tmp) { 570 /* everythings fine... */ 571 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE); 572 goto failed; 573 } 574 575 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) { 576 uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED; 577 578 gss_rc = gss_wrap_size_limit(&minor_status, context_handle, 579 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL), 580 GSS_C_QOP_DEFAULT, 581 max_msg_size, &ads->ldap.out.max_unwrapped); 582 if (gss_rc) { 583 status = ADS_ERROR_GSS(gss_rc, minor_status); 584 goto failed; 585 } 586 587 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped; 588 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */ 589 ads->ldap.in.max_wrapped = max_msg_size; 590 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle); 591 if (!ADS_ERR_OK(status)) { 592 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n", 593 ads_errstr(status))); 594 goto failed; 595 } 596 /* make sure we don't free context_handle */ 597 context_handle = GSS_C_NO_CONTEXT; 598 } 599 600 failed: 601 if (context_handle != GSS_C_NO_CONTEXT) 602 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER); 603 return status; 604 } 605 606 #endif /* HAVE_GSSAPI */ 607 139 608 #ifdef HAVE_KRB5 609 struct ads_service_principal { 610 char *string; 611 #ifdef HAVE_GSSAPI 612 gss_name_t name; 613 #endif 614 }; 615 616 static void ads_free_service_principal(struct ads_service_principal *p) 617 { 618 SAFE_FREE(p->string); 619 620 #ifdef HAVE_GSSAPI 621 if (p->name) { 622 uint32 minor_status; 623 gss_release_name(&minor_status, &p->name); 624 } 625 #endif 626 ZERO_STRUCTP(p); 627 } 628 629 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads, 630 const char *given_principal, 631 struct ads_service_principal *p) 632 { 633 ADS_STATUS status; 634 #ifdef HAVE_GSSAPI 635 gss_buffer_desc input_name; 636 /* GSS_KRB5_NT_PRINCIPAL_NAME */ 637 gss_OID_desc nt_principal = 638 {10, CONST_DISCARD(char *, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")}; 639 uint32 minor_status; 640 int gss_rc; 641 #endif 642 643 ZERO_STRUCTP(p); 644 645 /* I've seen a child Windows 2000 domain not send 646 the principal name back in the first round of 647 the SASL bind reply. So we guess based on server 648 name and realm. --jerry */ 649 /* Also try best guess when we get the w2k8 ignore 650 principal back - gd */ 651 652 if (!given_principal || 653 strequal(given_principal, ADS_IGNORE_PRINCIPAL)) { 654 655 status = ads_guess_service_principal(ads, &p->string); 656 if (!ADS_ERR_OK(status)) { 657 return status; 658 } 659 } else { 660 p->string = SMB_STRDUP(given_principal); 661 if (!p->string) { 662 return ADS_ERROR(LDAP_NO_MEMORY); 663 } 664 } 665 666 #ifdef HAVE_GSSAPI 667 input_name.value = p->string; 668 input_name.length = strlen(p->string); 669 670 gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name); 671 if (gss_rc) { 672 ads_free_service_principal(p); 673 return ADS_ERROR_GSS(gss_rc, minor_status); 674 } 675 #endif 676 677 return ADS_SUCCESS; 678 } 679 140 680 /* 141 681 perform a LDAP/SASL/SPNEGO/KRB5 bind 142 682 */ 143 static ADS_STATUS ads_sasl_spnego_ krb5_bind(ADS_STRUCT *ads, const char *principal)144 { 145 DATA_BLOB blob = data_blob (NULL, 0);683 static ADS_STATUS ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT *ads, const char *principal) 684 { 685 DATA_BLOB blob = data_blob_null; 146 686 struct berval cred, *scred = NULL; 147 DATA_BLOB session_key = data_blob (NULL, 0);687 DATA_BLOB session_key = data_blob_null; 148 688 int rc; 689 690 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) { 691 return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED); 692 } 149 693 150 694 rc = spnego_gen_negTokenTarg(principal, ads->auth.time_offset, &blob, &session_key, 0, … … 159 703 cred.bv_len = blob.length; 160 704 161 rc = ldap_sasl_bind_s(ads->ld , NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);705 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred); 162 706 163 707 data_blob_free(&blob); … … 168 712 return ADS_ERROR(rc); 169 713 } 714 715 static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads, 716 struct ads_service_principal *p) 717 { 718 #ifdef HAVE_GSSAPI 719 /* 720 * we only use the gsskrb5 based implementation 721 * when sasl sign or seal is requested. 722 * 723 * This has the following reasons: 724 * - it's likely that the gssapi krb5 mech implementation 725 * doesn't support to negotiate plain connections 726 * - the ads_sasl_spnego_rawkrb5_bind is more robust 727 * against clock skew errors 728 */ 729 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) { 730 return ads_sasl_spnego_gsskrb5_bind(ads, p->name); 731 } 170 732 #endif 733 return ads_sasl_spnego_rawkrb5_bind(ads, p->string); 734 } 735 #endif /* HAVE_KRB5 */ 171 736 172 737 /* … … 179 744 ADS_STATUS status; 180 745 DATA_BLOB blob; 181 char * principal = NULL;746 char *given_principal = NULL; 182 747 char *OIDs[ASN1_MAX_OIDS]; 183 748 #ifdef HAVE_KRB5 … … 185 750 #endif 186 751 187 rc = ldap_sasl_bind_s(ads->ld , NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);752 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred); 188 753 189 754 if (rc != LDAP_SASL_BIND_IN_PROGRESS) { … … 202 767 /* the server sent us the first part of the SPNEGO exchange in the negprot 203 768 reply */ 204 if (!spnego_parse_negTokenInit(blob, OIDs, & principal)) {769 if (!spnego_parse_negTokenInit(blob, OIDs, &given_principal)) { 205 770 data_blob_free(&blob); 206 771 status = ADS_ERROR(LDAP_OPERATIONS_ERROR); … … 220 785 free(OIDs[i]); 221 786 } 222 DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", principal));787 DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal)); 223 788 224 789 #ifdef HAVE_KRB5 … … 226 791 got_kerberos_mechanism) 227 792 { 228 /* I've seen a child Windows 2000 domain not send 229 the principal name back in the first round of 230 the SASL bind reply. So we guess based on server 231 name and realm. --jerry */ 232 if ( !principal ) { 233 if ( ads->server.realm && ads->server.ldap_server ) { 234 char *server, *server_realm; 235 236 server = SMB_STRDUP( ads->server.ldap_server ); 237 server_realm = SMB_STRDUP( ads->server.realm ); 238 239 if ( !server || !server_realm ) 240 return ADS_ERROR(LDAP_NO_MEMORY); 241 242 strlower_m( server ); 243 strupper_m( server_realm ); 244 asprintf( &principal, "ldap/%s@%s", server, server_realm ); 245 246 SAFE_FREE( server ); 247 SAFE_FREE( server_realm ); 248 249 if ( !principal ) 250 return ADS_ERROR(LDAP_NO_MEMORY); 251 } 252 253 } 254 255 status = ads_sasl_spnego_krb5_bind(ads, principal); 793 struct ads_service_principal p; 794 795 status = ads_generate_service_principal(ads, given_principal, &p); 796 SAFE_FREE(given_principal); 797 if (!ADS_ERR_OK(status)) { 798 return status; 799 } 800 801 status = ads_sasl_spnego_krb5_bind(ads, &p); 256 802 if (ADS_ERR_OK(status)) { 257 SAFE_FREE(principal);803 ads_free_service_principal(&p); 258 804 return status; 259 805 } … … 265 811 266 812 if (ADS_ERR_OK(status)) { 267 status = ads_sasl_spnego_krb5_bind(ads, principal); 268 } 813 status = ads_sasl_spnego_krb5_bind(ads, &p); 814 if (!ADS_ERR_OK(status)) { 815 DEBUG(0,("kinit succeeded but " 816 "ads_sasl_spnego_krb5_bind failed: %s\n", 817 ads_errstr(status))); 818 } 819 } 820 821 ads_free_service_principal(&p); 269 822 270 823 /* only fallback to NTLMSSP if allowed */ 271 824 if (ADS_ERR_OK(status) || 272 825 !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) { 273 SAFE_FREE(principal);274 826 return status; 275 827 } 276 } 828 } else 277 829 #endif 278 279 SAFE_FREE(principal); 830 { 831 SAFE_FREE(given_principal); 832 } 280 833 281 834 /* lets do NTLMSSP ... this has the big advantage that we don't need … … 297 850 see RFC2078 and RFC2222 for details 298 851 */ 299 static ADS_STATUS ads_sasl_gssapi_ bind(ADS_STRUCT *ads)852 static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name) 300 853 { 301 854 uint32 minor_status; 302 gss_name_t serv_name;303 gss_buffer_desc input_name;304 855 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT; 305 856 gss_OID mech_type = GSS_C_NULL_OID; 306 857 gss_buffer_desc output_token, input_token; 307 uint32 ret_flags, conf_state; 858 uint32 req_flags, ret_flags; 859 int conf_state; 308 860 struct berval cred; 309 861 struct berval *scred = NULL; … … 311 863 int gss_rc, rc; 312 864 uint8 *p; 313 uint32 max_msg_size = 0;314 char *sname = NULL;865 uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED; 866 uint8 wrap_type = ADS_SASLWRAP_TYPE_PLAIN; 315 867 ADS_STATUS status; 316 krb5_principal principal = NULL;317 krb5_context ctx = NULL;318 krb5_enctype enc_types[] = {319 #ifdef ENCTYPE_ARCFOUR_HMAC320 ENCTYPE_ARCFOUR_HMAC,321 #endif322 ENCTYPE_DES_CBC_MD5,323 ENCTYPE_NULL};324 gss_OID_desc nt_principal =325 {10, CONST_DISCARD(char *, "\052\206\110\206\367\022\001\002\002\002")};326 327 /* we need to fetch a service ticket as the ldap user in the328 servers realm, regardless of our realm */329 asprintf(&sname, "ldap/%s@%s", ads->config.ldap_server_name, ads->config.realm);330 331 initialize_krb5_error_table();332 status = ADS_ERROR_KRB5(krb5_init_context(&ctx));333 if (!ADS_ERR_OK(status)) {334 SAFE_FREE(sname);335 return status;336 }337 status = ADS_ERROR_KRB5(krb5_set_default_tgs_ktypes(ctx, enc_types));338 if (!ADS_ERR_OK(status)) {339 SAFE_FREE(sname);340 krb5_free_context(ctx);341 return status;342 }343 status = ADS_ERROR_KRB5(smb_krb5_parse_name(ctx, sname, &principal));344 if (!ADS_ERR_OK(status)) {345 SAFE_FREE(sname);346 krb5_free_context(ctx);347 return status;348 }349 350 input_name.value = &principal;351 input_name.length = sizeof(principal);352 353 gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &serv_name);354 355 /*356 * The MIT libraries have a *HORRIBLE* bug - input_value.value needs357 * to point to the *address* of the krb5_principal, and the gss libraries358 * to a shallow copy of the krb5_principal pointer - so we need to keep359 * the krb5_principal around until we do the gss_release_name. MIT *SUCKS* !360 * Just one more way in which MIT engineers screwed me over.... JRA.361 */362 363 SAFE_FREE(sname);364 365 if (gss_rc) {366 krb5_free_principal(ctx, principal);367 krb5_free_context(ctx);368 return ADS_ERROR_GSS(gss_rc, minor_status);369 }370 868 371 869 input_token.value = NULL; 372 870 input_token.length = 0; 871 872 /* 873 * Note: here we always ask the gssapi for sign and seal 874 * as this is negotiated later after the mutal 875 * authentication 876 */ 877 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG; 373 878 374 879 for (i=0; i < MAX_GSS_PASSES; i++) { … … 378 883 serv_name, 379 884 mech_type, 380 GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,885 req_flags, 381 886 0, 382 887 NULL, … … 386 891 &ret_flags, 387 892 NULL); 388 389 if (input_token.value) { 390 gss_release_buffer(&minor_status, &input_token); 391 } 392 893 if (scred) { 894 ber_bvfree(scred); 895 scred = NULL; 896 } 393 897 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) { 394 898 status = ADS_ERROR_GSS(gss_rc, minor_status); … … 399 903 cred.bv_len = output_token.length; 400 904 401 rc = ldap_sasl_bind_s(ads->ld , NULL, "GSSAPI", &cred, NULL, NULL,905 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL, 402 906 &scred); 403 907 if (rc != LDAP_SASL_BIND_IN_PROGRESS) { … … 422 926 423 927 gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token, 424 (int *)&conf_state,NULL); 928 &conf_state,NULL); 929 if (scred) { 930 ber_bvfree(scred); 931 scred = NULL; 932 } 425 933 if (gss_rc) { 426 934 status = ADS_ERROR_GSS(gss_rc, minor_status); 427 935 goto failed; 428 936 } 429 430 gss_release_buffer(&minor_status, &input_token);431 937 432 938 p = (uint8 *)output_token.value; … … 437 943 438 944 if (p) { 439 max_msg_size = (p[1]<<16) | (p[2]<<8) | p[3]; 945 wrap_type = CVAL(p,0); 946 SCVAL(p,0,0); 947 max_msg_size = RIVAL(p,0); 440 948 } 441 949 442 950 gss_release_buffer(&minor_status, &output_token); 443 951 444 output_token.value = SMB_MALLOC(strlen(ads->config.bind_path) + 8); 952 if (!(wrap_type & ads->ldap.wrap_type)) { 953 /* 954 * the server doesn't supports the wrap 955 * type we want :-( 956 */ 957 DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n", 958 ads->ldap.wrap_type, wrap_type)); 959 DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n")); 960 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED); 961 goto failed; 962 } 963 964 /* 0x58 is the minimum windows accepts */ 965 if (max_msg_size < 0x58) { 966 max_msg_size = 0x58; 967 } 968 969 output_token.length = 4; 970 output_token.value = SMB_MALLOC(output_token.length); 445 971 p = (uint8 *)output_token.value; 446 972 447 *p++ = 1; /* no sign & seal selection */ 448 /* choose the same size as the server gave us */ 449 *p++ = max_msg_size>>16; 450 *p++ = max_msg_size>>8; 451 *p++ = max_msg_size; 452 snprintf((char *)p, strlen(ads->config.bind_path)+4, "dn:%s", ads->config.bind_path); 453 p += strlen((const char *)p); 454 455 output_token.length = PTR_DIFF(p, output_token.value); 973 RSIVAL(p,0,max_msg_size); 974 SCVAL(p,0,ads->ldap.wrap_type); 975 976 /* 977 * we used to add sprintf("dn:%s", ads->config.bind_path) here. 978 * but using ads->config.bind_path is the wrong! It should be 979 * the DN of the user object! 980 * 981 * w2k3 gives an error when we send an incorrect DN, but sending nothing 982 * is ok and matches the information flow used in GSS-SPNEGO. 983 */ 456 984 457 985 gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT, 458 &output_token, (int *)&conf_state,986 &output_token, &conf_state, 459 987 &input_token); 460 988 if (gss_rc) { … … 468 996 cred.bv_len = input_token.length; 469 997 470 rc = ldap_sasl_bind_s(ads->ld , NULL, "GSSAPI", &cred, NULL, NULL,998 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL, 471 999 &scred); 1000 gss_release_buffer(&minor_status, &input_token); 472 1001 status = ADS_ERROR(rc); 473 474 gss_release_buffer(&minor_status, &input_token); 1002 if (!ADS_ERR_OK(status)) { 1003 goto failed; 1004 } 1005 1006 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) { 1007 gss_rc = gss_wrap_size_limit(&minor_status, context_handle, 1008 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL), 1009 GSS_C_QOP_DEFAULT, 1010 max_msg_size, &ads->ldap.out.max_unwrapped); 1011 if (gss_rc) { 1012 status = ADS_ERROR_GSS(gss_rc, minor_status); 1013 goto failed; 1014 } 1015 1016 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped; 1017 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */ 1018 ads->ldap.in.max_wrapped = max_msg_size; 1019 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle); 1020 if (!ADS_ERR_OK(status)) { 1021 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n", 1022 ads_errstr(status))); 1023 goto failed; 1024 } 1025 /* make sure we don't free context_handle */ 1026 context_handle = GSS_C_NO_CONTEXT; 1027 } 475 1028 476 1029 failed: 477 1030 478 gss_release_name(&minor_status, &serv_name);479 1031 if (context_handle != GSS_C_NO_CONTEXT) 480 1032 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER); 481 krb5_free_principal(ctx, principal);482 krb5_free_context(ctx);483 1033 484 1034 if(scred) … … 486 1036 return status; 487 1037 } 488 #endif /* HAVE_GGSAPI */ 1038 1039 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads) 1040 { 1041 ADS_STATUS status; 1042 struct ads_service_principal p; 1043 1044 status = ads_generate_service_principal(ads, NULL, &p); 1045 if (!ADS_ERR_OK(status)) { 1046 return status; 1047 } 1048 1049 status = ads_sasl_gssapi_do_bind(ads, p.name); 1050 if (ADS_ERR_OK(status)) { 1051 ads_free_service_principal(&p); 1052 return status; 1053 } 1054 1055 DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, " 1056 "calling kinit\n", ads_errstr(status))); 1057 1058 status = ADS_ERROR_KRB5(ads_kinit_password(ads)); 1059 1060 if (ADS_ERR_OK(status)) { 1061 status = ads_sasl_gssapi_do_bind(ads, p.name); 1062 } 1063 1064 ads_free_service_principal(&p); 1065 1066 return status; 1067 } 1068 1069 #endif /* HAVE_GSSAPI */ 489 1070 490 1071 /* mapping between SASL mechanisms and functions */ … … 512 1093 if (!ADS_ERR_OK(status)) return status; 513 1094 514 values = ldap_get_values(ads->ld, res, "supportedSASLMechanisms"); 1095 values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms"); 1096 1097 if (ads->auth.flags & ADS_AUTH_SASL_SEAL) { 1098 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL; 1099 } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) { 1100 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN; 1101 } else { 1102 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_PLAIN; 1103 } 515 1104 516 1105 /* try our supported mechanisms in order */
Note: See TracChangeset
for help on using the changeset viewer.