1/* $OpenLDAP$ */ 2/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 3 * 4 * Copyright 1998-2011 The OpenLDAP Foundation. 5 * All rights reserved. 6 * 7 * Author: Stefan Metzmacher <metze@sernet.de> 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted only as authorized by the OpenLDAP 11 * Public License. 12 * 13 * A copy of this license is available in the file LICENSE in the 14 * top-level directory of the distribution or, alternatively, at 15 * <http://www.OpenLDAP.org/license.html>. 16 */ 17 18#include "portable.h" 19 20#include <stdio.h> 21 22#include <ac/socket.h> 23#include <ac/stdlib.h> 24#include <ac/string.h> 25#include <ac/time.h> 26#include <ac/errno.h> 27#include <ac/ctype.h> 28#include <ac/unistd.h> 29 30#ifdef HAVE_LIMITS_H 31#include <limits.h> 32#endif 33 34#include "ldap-int.h" 35 36#ifdef HAVE_GSSAPI 37 38#ifdef HAVE_GSSAPI_GSSAPI_H 39#include <gssapi/gssapi.h> 40#else 41#include <gssapi.h> 42#endif 43 44static char * 45gsserrstr( 46 char *buf, 47 ber_len_t buf_len, 48 gss_OID mech, 49 int gss_rc, 50 OM_uint32 minor_status ) 51{ 52 OM_uint32 min2; 53 gss_buffer_desc mech_msg = GSS_C_EMPTY_BUFFER; 54 gss_buffer_desc gss_msg = GSS_C_EMPTY_BUFFER; 55 gss_buffer_desc minor_msg = GSS_C_EMPTY_BUFFER; 56 OM_uint32 msg_ctx = 0; 57 58 if (buf == NULL) { 59 return NULL; 60 } 61 62 if (buf_len == 0) { 63 return NULL; 64 } 65 66#ifdef HAVE_GSS_OID_TO_STR 67 gss_oid_to_str(&min2, mech, &mech_msg); 68#endif 69 gss_display_status(&min2, gss_rc, GSS_C_GSS_CODE, 70 mech, &msg_ctx, &gss_msg); 71 gss_display_status(&min2, minor_status, GSS_C_MECH_CODE, 72 mech, &msg_ctx, &minor_msg); 73 74 snprintf(buf, buf_len, "gss_rc[%d:%*s] mech[%*s] minor[%u:%*s]", 75 gss_rc, (int)gss_msg.length, 76 (const char *)(gss_msg.value?gss_msg.value:""), 77 (int)mech_msg.length, 78 (const char *)(mech_msg.value?mech_msg.value:""), 79 minor_status, (int)minor_msg.length, 80 (const char *)(minor_msg.value?minor_msg.value:"")); 81 82 gss_release_buffer(&min2, &mech_msg); 83 gss_release_buffer(&min2, &gss_msg); 84 gss_release_buffer(&min2, &minor_msg); 85 86 buf[buf_len-1] = '\0'; 87 88 return buf; 89} 90 91static void 92sb_sasl_gssapi_init( 93 struct sb_sasl_generic_data *p, 94 ber_len_t *min_send, 95 ber_len_t *max_send, 96 ber_len_t *max_recv ) 97{ 98 gss_ctx_id_t gss_ctx = (gss_ctx_id_t)p->ops_private; 99 int gss_rc; 100 OM_uint32 minor_status; 101 gss_OID ctx_mech = GSS_C_NO_OID; 102 OM_uint32 ctx_flags = 0; 103 int conf_req_flag = 0; 104 OM_uint32 max_input_size; 105 106 gss_inquire_context(&minor_status, 107 gss_ctx, 108 NULL, 109 NULL, 110 NULL, 111 &ctx_mech, 112 &ctx_flags, 113 NULL, 114 NULL); 115 116 if (ctx_flags & (GSS_C_CONF_FLAG)) { 117 conf_req_flag = 1; 118 } 119 120#if defined(HAVE_CYRUS_SASL) 121#define SEND_PREALLOC_SIZE SASL_MIN_BUFF_SIZE 122#else 123#define SEND_PREALLOC_SIZE 4096 124#endif 125#define SEND_MAX_WIRE_SIZE 0x00A00000 126#define RECV_MAX_WIRE_SIZE 0x0FFFFFFF 127#define FALLBACK_SEND_MAX_SIZE 0x009FFFB8 /* from MIT 1.5.x */ 128 129 gss_rc = gss_wrap_size_limit(&minor_status, gss_ctx, 130 conf_req_flag, GSS_C_QOP_DEFAULT, 131 SEND_MAX_WIRE_SIZE, &max_input_size); 132 if ( gss_rc != GSS_S_COMPLETE ) { 133 char msg[256]; 134 ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug, 135 "sb_sasl_gssapi_init: failed to wrap size limit: %s\n", 136 gsserrstr( msg, sizeof(msg), ctx_mech, gss_rc, minor_status ) ); 137 ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug, 138 "sb_sasl_gssapi_init: fallback to default wrap size limit\n"); 139 /* 140 * some libgssglue/libgssapi versions 141 * have a broken gss_wrap_size_limit() 142 * implementation 143 */ 144 max_input_size = FALLBACK_SEND_MAX_SIZE; 145 } 146 147 *min_send = SEND_PREALLOC_SIZE; 148 *max_send = max_input_size; 149 *max_recv = RECV_MAX_WIRE_SIZE; 150} 151 152static ber_int_t 153sb_sasl_gssapi_encode( 154 struct sb_sasl_generic_data *p, 155 unsigned char *buf, 156 ber_len_t len, 157 Sockbuf_Buf *dst ) 158{ 159 gss_ctx_id_t gss_ctx = (gss_ctx_id_t)p->ops_private; 160 int gss_rc; 161 OM_uint32 minor_status; 162 gss_buffer_desc unwrapped, wrapped; 163 gss_OID ctx_mech = GSS_C_NO_OID; 164 OM_uint32 ctx_flags = 0; 165 int conf_req_flag = 0; 166 int conf_state; 167 unsigned char *b; 168 ber_len_t pkt_len; 169 170 unwrapped.value = buf; 171 unwrapped.length = len; 172 173 gss_inquire_context(&minor_status, 174 gss_ctx, 175 NULL, 176 NULL, 177 NULL, 178 &ctx_mech, 179 &ctx_flags, 180 NULL, 181 NULL); 182 183 if (ctx_flags & (GSS_C_CONF_FLAG)) { 184 conf_req_flag = 1; 185 } 186 187 gss_rc = gss_wrap(&minor_status, gss_ctx, 188 conf_req_flag, GSS_C_QOP_DEFAULT, 189 &unwrapped, &conf_state, 190 &wrapped); 191 if ( gss_rc != GSS_S_COMPLETE ) { 192 char msg[256]; 193 ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug, 194 "sb_sasl_gssapi_encode: failed to encode packet: %s\n", 195 gsserrstr( msg, sizeof(msg), ctx_mech, gss_rc, minor_status ) ); 196 return -1; 197 } 198 199 if ( conf_req_flag && conf_state == 0 ) { 200 ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug, 201 "sb_sasl_gssapi_encode: GSS_C_CONF_FLAG was ignored by our gss_wrap()\n" ); 202 return -1; 203 } 204 205 pkt_len = 4 + wrapped.length; 206 207 /* Grow the packet buffer if neccessary */ 208 if ( dst->buf_size < pkt_len && 209 ber_pvt_sb_grow_buffer( dst, pkt_len ) < 0 ) 210 { 211 ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug, 212 "sb_sasl_gssapi_encode: failed to grow the buffer to %lu bytes\n", 213 pkt_len ); 214 return -1; 215 } 216 217 dst->buf_end = pkt_len; 218 219 b = (unsigned char *)dst->buf_base; 220 221 b[0] = (unsigned char)(wrapped.length >> 24); 222 b[1] = (unsigned char)(wrapped.length >> 16); 223 b[2] = (unsigned char)(wrapped.length >> 8); 224 b[3] = (unsigned char)(wrapped.length >> 0); 225 226 /* copy the wrapped blob to the right location */ 227 memcpy(b + 4, wrapped.value, wrapped.length); 228 229 gss_release_buffer(&minor_status, &wrapped); 230 231 return 0; 232} 233 234static ber_int_t 235sb_sasl_gssapi_decode( 236 struct sb_sasl_generic_data *p, 237 const Sockbuf_Buf *src, 238 Sockbuf_Buf *dst ) 239{ 240 gss_ctx_id_t gss_ctx = (gss_ctx_id_t)p->ops_private; 241 int gss_rc; 242 OM_uint32 minor_status; 243 gss_buffer_desc unwrapped, wrapped; 244 gss_OID ctx_mech = GSS_C_NO_OID; 245 OM_uint32 ctx_flags = 0; 246 int conf_req_flag = 0; 247 int conf_state; 248 unsigned char *b; 249 250 wrapped.value = src->buf_base + 4; 251 wrapped.length = src->buf_end - 4; 252 253 gss_inquire_context(&minor_status, 254 gss_ctx, 255 NULL, 256 NULL, 257 NULL, 258 &ctx_mech, 259 &ctx_flags, 260 NULL, 261 NULL); 262 263 if (ctx_flags & (GSS_C_CONF_FLAG)) { 264 conf_req_flag = 1; 265 } 266 267 gss_rc = gss_unwrap(&minor_status, gss_ctx, 268 &wrapped, &unwrapped, 269 &conf_state, GSS_C_QOP_DEFAULT); 270 if ( gss_rc != GSS_S_COMPLETE ) { 271 char msg[256]; 272 ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug, 273 "sb_sasl_gssapi_decode: failed to decode packet: %s\n", 274 gsserrstr( msg, sizeof(msg), ctx_mech, gss_rc, minor_status ) ); 275 return -1; 276 } 277 278 if ( conf_req_flag && conf_state == 0 ) { 279 ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug, 280 "sb_sasl_gssapi_encode: GSS_C_CONF_FLAG was ignored by our peer\n" ); 281 return -1; 282 } 283 284 /* Grow the packet buffer if neccessary */ 285 if ( dst->buf_size < unwrapped.length && 286 ber_pvt_sb_grow_buffer( dst, unwrapped.length ) < 0 ) 287 { 288 ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug, 289 "sb_sasl_gssapi_decode: failed to grow the buffer to %lu bytes\n", 290 unwrapped.length ); 291 return -1; 292 } 293 294 dst->buf_end = unwrapped.length; 295 296 b = (unsigned char *)dst->buf_base; 297 298 /* copy the wrapped blob to the right location */ 299 memcpy(b, unwrapped.value, unwrapped.length); 300 301 gss_release_buffer(&minor_status, &unwrapped); 302 303 return 0; 304} 305 306static void 307sb_sasl_gssapi_reset_buf( 308 struct sb_sasl_generic_data *p, 309 Sockbuf_Buf *buf ) 310{ 311 ber_pvt_sb_buf_destroy( buf ); 312} 313 314static void 315sb_sasl_gssapi_fini( struct sb_sasl_generic_data *p ) 316{ 317} 318 319static const struct sb_sasl_generic_ops sb_sasl_gssapi_ops = { 320 sb_sasl_gssapi_init, 321 sb_sasl_gssapi_encode, 322 sb_sasl_gssapi_decode, 323 sb_sasl_gssapi_reset_buf, 324 sb_sasl_gssapi_fini 325}; 326 327static int 328sb_sasl_gssapi_install( 329 Sockbuf *sb, 330 gss_ctx_id_t gss_ctx ) 331{ 332 struct sb_sasl_generic_install install_arg; 333 334 install_arg.ops = &sb_sasl_gssapi_ops; 335 install_arg.ops_private = gss_ctx; 336 337 return ldap_pvt_sasl_generic_install( sb, &install_arg ); 338} 339 340static void 341sb_sasl_gssapi_remove( Sockbuf *sb ) 342{ 343 ldap_pvt_sasl_generic_remove( sb ); 344} 345 346static int 347map_gsserr2ldap( 348 LDAP *ld, 349 gss_OID mech, 350 int gss_rc, 351 OM_uint32 minor_status ) 352{ 353 char msg[256]; 354 355 Debug( LDAP_DEBUG_ANY, "%s\n", 356 gsserrstr( msg, sizeof(msg), mech, gss_rc, minor_status ), 357 NULL, NULL ); 358 359 if (gss_rc == GSS_S_COMPLETE) { 360 ld->ld_errno = LDAP_SUCCESS; 361 } else if (GSS_CALLING_ERROR(gss_rc)) { 362 ld->ld_errno = LDAP_LOCAL_ERROR; 363 } else if (GSS_ROUTINE_ERROR(gss_rc)) { 364 ld->ld_errno = LDAP_INAPPROPRIATE_AUTH; 365 } else if (gss_rc == GSS_S_CONTINUE_NEEDED) { 366 ld->ld_errno = LDAP_SASL_BIND_IN_PROGRESS; 367 } else if (GSS_SUPPLEMENTARY_INFO(gss_rc)) { 368 ld->ld_errno = LDAP_AUTH_UNKNOWN; 369 } else if (GSS_ERROR(gss_rc)) { 370 ld->ld_errno = LDAP_AUTH_UNKNOWN; 371 } else { 372 ld->ld_errno = LDAP_OTHER; 373 } 374 375 return ld->ld_errno; 376} 377 378 379static int 380ldap_gssapi_get_rootdse_infos ( 381 LDAP *ld, 382 char **pmechlist, 383 char **pldapServiceName, 384 char **pdnsHostName ) 385{ 386 /* we need to query the server for supported mechs anyway */ 387 LDAPMessage *res, *e; 388 char *attrs[] = { 389 "supportedSASLMechanisms", 390 "ldapServiceName", 391 "dnsHostName", 392 NULL 393 }; 394 char **values, *mechlist; 395 char *ldapServiceName = NULL; 396 char *dnsHostName = NULL; 397 int rc; 398 399 Debug( LDAP_DEBUG_TRACE, "ldap_gssapi_get_rootdse_infos\n", 0, 0, 0 ); 400 401 rc = ldap_search_s( ld, "", LDAP_SCOPE_BASE, 402 NULL, attrs, 0, &res ); 403 404 if ( rc != LDAP_SUCCESS ) { 405 return ld->ld_errno; 406 } 407 408 e = ldap_first_entry( ld, res ); 409 if ( e == NULL ) { 410 ldap_msgfree( res ); 411 if ( ld->ld_errno == LDAP_SUCCESS ) { 412 ld->ld_errno = LDAP_NO_SUCH_OBJECT; 413 } 414 return ld->ld_errno; 415 } 416 417 values = ldap_get_values( ld, e, "supportedSASLMechanisms" ); 418 if ( values == NULL ) { 419 ldap_msgfree( res ); 420 ld->ld_errno = LDAP_NO_SUCH_ATTRIBUTE; 421 return ld->ld_errno; 422 } 423 424 mechlist = ldap_charray2str( values, " " ); 425 if ( mechlist == NULL ) { 426 LDAP_VFREE( values ); 427 ldap_msgfree( res ); 428 ld->ld_errno = LDAP_NO_MEMORY; 429 return ld->ld_errno; 430 } 431 432 LDAP_VFREE( values ); 433 434 values = ldap_get_values( ld, e, "ldapServiceName" ); 435 if ( values == NULL ) { 436 goto get_dns_host_name; 437 } 438 439 ldapServiceName = ldap_charray2str( values, " " ); 440 if ( ldapServiceName == NULL ) { 441 LDAP_FREE( mechlist ); 442 LDAP_VFREE( values ); 443 ldap_msgfree( res ); 444 ld->ld_errno = LDAP_NO_MEMORY; 445 return ld->ld_errno; 446 } 447 LDAP_VFREE( values ); 448 449get_dns_host_name: 450 451 values = ldap_get_values( ld, e, "dnsHostName" ); 452 if ( values == NULL ) { 453 goto done; 454 } 455 456 dnsHostName = ldap_charray2str( values, " " ); 457 if ( dnsHostName == NULL ) { 458 LDAP_FREE( mechlist ); 459 LDAP_FREE( ldapServiceName ); 460 LDAP_VFREE( values ); 461 ldap_msgfree( res ); 462 ld->ld_errno = LDAP_NO_MEMORY; 463 return ld->ld_errno; 464 } 465 LDAP_VFREE( values ); 466 467done: 468 ldap_msgfree( res ); 469 470 *pmechlist = mechlist; 471 *pldapServiceName = ldapServiceName; 472 *pdnsHostName = dnsHostName; 473 474 return LDAP_SUCCESS; 475} 476 477 478static int check_for_gss_spnego_support( LDAP *ld, const char *mechs_str ) 479{ 480 int rc; 481 char **mechs_list = NULL; 482 483 mechs_list = ldap_str2charray( mechs_str, " " ); 484 if ( mechs_list == NULL ) { 485 ld->ld_errno = LDAP_NO_MEMORY; 486 return ld->ld_errno; 487 } 488 489 rc = ldap_charray_inlist( mechs_list, "GSS-SPNEGO" ); 490 ldap_charray_free( mechs_list ); 491 if ( rc != 1) { 492 ld->ld_errno = LDAP_STRONG_AUTH_NOT_SUPPORTED; 493 return ld->ld_errno; 494 } 495 496 return LDAP_SUCCESS; 497} 498 499static int 500guess_service_principal( 501 LDAP *ld, 502 const char *ldapServiceName, 503 const char *dnsHostName, 504 gss_name_t *principal ) 505{ 506 gss_buffer_desc input_name; 507 /* GSS_KRB5_NT_PRINCIPAL_NAME */ 508 gss_OID_desc nt_principal = 509 {10, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01"}; 510 const char *host = ld->ld_defconn->lconn_server->lud_host; 511 OM_uint32 minor_status; 512 int gss_rc; 513 int ret; 514 size_t svc_principal_size; 515 char *svc_principal = NULL; 516 const char *principal_fmt = NULL; 517 const char *str = NULL; 518 const char *givenstr = NULL; 519 const char *ignore = "not_defined_in_RFC4178@please_ignore"; 520 int allow_remote = 0; 521 522 if (ldapServiceName) { 523 givenstr = strchr(ldapServiceName, ':'); 524 if (givenstr && givenstr[1]) { 525 givenstr++; 526 if (strcmp(givenstr, ignore) == 0) { 527 givenstr = NULL; 528 } 529 } else { 530 givenstr = NULL; 531 } 532 } 533 534 if ( ld->ld_options.ldo_gssapi_options & LDAP_GSSAPI_OPT_ALLOW_REMOTE_PRINCIPAL ) { 535 allow_remote = 1; 536 } 537 538 if (allow_remote && givenstr) { 539 principal_fmt = "%s"; 540 svc_principal_size = strlen(givenstr) + 1; 541 str = givenstr; 542 543 } else if (allow_remote && dnsHostName) { 544 principal_fmt = "ldap/%s"; 545 svc_principal_size = STRLENOF("ldap/") + strlen(dnsHostName) + 1; 546 str = dnsHostName; 547 548 } else { 549 principal_fmt = "ldap/%s"; 550 svc_principal_size = STRLENOF("ldap/") + strlen(host) + 1; 551 str = host; 552 } 553 554 svc_principal = (char*) ldap_memalloc(svc_principal_size * sizeof(char)); 555 if ( svc_principal == NULL ) { 556 ld->ld_errno = LDAP_NO_MEMORY; 557 return ld->ld_errno; 558 } 559 560 ret = snprintf( svc_principal, svc_principal_size, principal_fmt, str ); 561 if (ret < 0 || (size_t)ret >= svc_principal_size) { 562 ld->ld_errno = LDAP_LOCAL_ERROR; 563 return ld->ld_errno; 564 } 565 566 Debug( LDAP_DEBUG_TRACE, "principal for host[%s]: '%s'\n", 567 host, svc_principal, 0 ); 568 569 input_name.value = svc_principal; 570 input_name.length = (size_t)ret; 571 572 gss_rc = gss_import_name( &minor_status, &input_name, &nt_principal, principal ); 573 ldap_memfree( svc_principal ); 574 if ( gss_rc != GSS_S_COMPLETE ) { 575 return map_gsserr2ldap( ld, GSS_C_NO_OID, gss_rc, minor_status ); 576 } 577 578 return LDAP_SUCCESS; 579} 580 581void ldap_int_gssapi_close( LDAP *ld, LDAPConn *lc ) 582{ 583 if ( lc && lc->lconn_gss_ctx ) { 584 OM_uint32 minor_status; 585 OM_uint32 ctx_flags = 0; 586 gss_ctx_id_t old_gss_ctx = GSS_C_NO_CONTEXT; 587 old_gss_ctx = (gss_ctx_id_t)lc->lconn_gss_ctx; 588 589 gss_inquire_context(&minor_status, 590 old_gss_ctx, 591 NULL, 592 NULL, 593 NULL, 594 NULL, 595 &ctx_flags, 596 NULL, 597 NULL); 598 599 if (!( ld->ld_options.ldo_gssapi_options & LDAP_GSSAPI_OPT_DO_NOT_FREE_GSS_CONTEXT )) { 600 gss_delete_sec_context( &minor_status, &old_gss_ctx, GSS_C_NO_BUFFER ); 601 } 602 lc->lconn_gss_ctx = GSS_C_NO_CONTEXT; 603 604 if (ctx_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG)) { 605 /* remove wrapping layer */ 606 sb_sasl_gssapi_remove( lc->lconn_sb ); 607 } 608 } 609} 610 611static void 612ldap_int_gssapi_setup( 613 LDAP *ld, 614 LDAPConn *lc, 615 gss_ctx_id_t gss_ctx) 616{ 617 OM_uint32 minor_status; 618 OM_uint32 ctx_flags = 0; 619 620 ldap_int_gssapi_close( ld, lc ); 621 622 gss_inquire_context(&minor_status, 623 gss_ctx, 624 NULL, 625 NULL, 626 NULL, 627 NULL, 628 &ctx_flags, 629 NULL, 630 NULL); 631 632 lc->lconn_gss_ctx = gss_ctx; 633 634 if (ctx_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG)) { 635 /* setup wrapping layer */ 636 sb_sasl_gssapi_install( lc->lconn_sb, gss_ctx ); 637 } 638} 639 640#ifdef LDAP_R_COMPILE 641ldap_pvt_thread_mutex_t ldap_int_gssapi_mutex; 642#endif 643 644static int 645ldap_int_gss_spnego_bind_s( LDAP *ld ) 646{ 647 int rc; 648 int gss_rc; 649 OM_uint32 minor_status; 650 char *mechlist = NULL; 651 char *ldapServiceName = NULL; 652 char *dnsHostName = NULL; 653 gss_OID_set supported_mechs = GSS_C_NO_OID_SET; 654 int spnego_support = 0; 655#define __SPNEGO_OID_LENGTH 6 656#define __SPNEGO_OID "\053\006\001\005\005\002" 657 gss_OID_desc spnego_oid = {__SPNEGO_OID_LENGTH, __SPNEGO_OID}; 658 gss_OID req_mech = GSS_C_NO_OID; 659 gss_OID ret_mech = GSS_C_NO_OID; 660 gss_ctx_id_t gss_ctx = GSS_C_NO_CONTEXT; 661 gss_name_t principal = GSS_C_NO_NAME; 662 OM_uint32 req_flags; 663 OM_uint32 ret_flags; 664 gss_buffer_desc input_token, output_token = GSS_C_EMPTY_BUFFER; 665 struct berval cred, *scred = NULL; 666 667 LDAP_MUTEX_LOCK( &ldap_int_gssapi_mutex ); 668 669 /* get information from RootDSE entry */ 670 rc = ldap_gssapi_get_rootdse_infos ( ld, &mechlist, 671 &ldapServiceName, &dnsHostName); 672 if ( rc != LDAP_SUCCESS ) { 673 return rc; 674 } 675 676 /* check that the server supports GSS-SPNEGO */ 677 rc = check_for_gss_spnego_support( ld, mechlist ); 678 if ( rc != LDAP_SUCCESS ) { 679 goto rc_error; 680 } 681 682 /* prepare new gss_ctx_id_t */ 683 rc = guess_service_principal( ld, ldapServiceName, dnsHostName, &principal ); 684 if ( rc != LDAP_SUCCESS ) { 685 goto rc_error; 686 } 687 688 /* see if our gssapi library supports spnego */ 689 gss_rc = gss_indicate_mechs( &minor_status, &supported_mechs ); 690 if ( gss_rc != GSS_S_COMPLETE ) { 691 goto gss_error; 692 } 693 gss_rc = gss_test_oid_set_member( &minor_status, 694 &spnego_oid, supported_mechs, &spnego_support); 695 gss_release_oid_set( &minor_status, &supported_mechs); 696 if ( gss_rc != GSS_S_COMPLETE ) { 697 goto gss_error; 698 } 699 if ( spnego_support != 0 ) { 700 req_mech = &spnego_oid; 701 } 702 703 req_flags = ld->ld_options.gssapi_flags; 704 req_flags |= GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG; 705 706 /* 707 * loop around gss_init_sec_context() and ldap_sasl_bind_s() 708 */ 709 input_token.value = NULL; 710 input_token.length = 0; 711 gss_rc = gss_init_sec_context(&minor_status, 712 GSS_C_NO_CREDENTIAL, 713 &gss_ctx, 714 principal, 715 req_mech, 716 req_flags, 717 0, 718 NULL, 719 &input_token, 720 &ret_mech, 721 &output_token, 722 &ret_flags, 723 NULL); 724 if ( gss_rc == GSS_S_COMPLETE ) { 725 rc = LDAP_INAPPROPRIATE_AUTH; 726 goto rc_error; 727 } 728 if ( gss_rc != GSS_S_CONTINUE_NEEDED ) { 729 goto gss_error; 730 } 731 while (1) { 732 cred.bv_val = (char *)output_token.value; 733 cred.bv_len = output_token.length; 734 rc = ldap_sasl_bind_s( ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred ); 735 gss_release_buffer( &minor_status, &output_token ); 736 if ( rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS ) { 737 goto rc_error; 738 } 739 740 if ( scred ) { 741 input_token.value = scred->bv_val; 742 input_token.length = scred->bv_len; 743 } else { 744 input_token.value = NULL; 745 input_token.length = 0; 746 } 747 748 gss_rc = gss_init_sec_context(&minor_status, 749 GSS_C_NO_CREDENTIAL, 750 &gss_ctx, 751 principal, 752 req_mech, 753 req_flags, 754 0, 755 NULL, 756 &input_token, 757 &ret_mech, 758 &output_token, 759 &ret_flags, 760 NULL); 761 if ( scred ) { 762 ber_bvfree( scred ); 763 } 764 if ( gss_rc == GSS_S_COMPLETE ) { 765 gss_release_buffer( &minor_status, &output_token ); 766 break; 767 } 768 769 if ( gss_rc != GSS_S_CONTINUE_NEEDED ) { 770 goto gss_error; 771 } 772 } 773 774 ldap_int_gssapi_setup( ld, ld->ld_defconn, gss_ctx); 775 gss_ctx = GSS_C_NO_CONTEXT; 776 777 rc = LDAP_SUCCESS; 778 goto rc_error; 779 780gss_error: 781 rc = map_gsserr2ldap( ld, 782 (ret_mech != GSS_C_NO_OID ? ret_mech : req_mech ), 783 gss_rc, minor_status ); 784rc_error: 785 LDAP_MUTEX_UNLOCK( &ldap_int_gssapi_mutex ); 786 LDAP_FREE( mechlist ); 787 LDAP_FREE( ldapServiceName ); 788 LDAP_FREE( dnsHostName ); 789 gss_release_buffer( &minor_status, &output_token ); 790 if ( gss_ctx != GSS_C_NO_CONTEXT ) { 791 gss_delete_sec_context( &minor_status, &gss_ctx, GSS_C_NO_BUFFER ); 792 } 793 if ( principal != GSS_C_NO_NAME ) { 794 gss_release_name( &minor_status, &principal ); 795 } 796 return rc; 797} 798 799int 800ldap_int_gssapi_config( struct ldapoptions *lo, int option, const char *arg ) 801{ 802 int ok = 0; 803 804 switch( option ) { 805 case LDAP_OPT_SIGN: 806 807 if (!arg) { 808 } else if (strcasecmp(arg, "on") == 0) { 809 ok = 1; 810 } else if (strcasecmp(arg, "yes") == 0) { 811 ok = 1; 812 } else if (strcasecmp(arg, "true") == 0) { 813 ok = 1; 814 815 } 816 if (ok) { 817 lo->ldo_gssapi_flags |= GSS_C_INTEG_FLAG; 818 } 819 820 return 0; 821 822 case LDAP_OPT_ENCRYPT: 823 824 if (!arg) { 825 } else if (strcasecmp(arg, "on") == 0) { 826 ok = 1; 827 } else if (strcasecmp(arg, "yes") == 0) { 828 ok = 1; 829 } else if (strcasecmp(arg, "true") == 0) { 830 ok = 1; 831 } 832 833 if (ok) { 834 lo->ldo_gssapi_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG; 835 } 836 837 return 0; 838 839 case LDAP_OPT_X_GSSAPI_ALLOW_REMOTE_PRINCIPAL: 840 841 if (!arg) { 842 } else if (strcasecmp(arg, "on") == 0) { 843 ok = 1; 844 } else if (strcasecmp(arg, "yes") == 0) { 845 ok = 1; 846 } else if (strcasecmp(arg, "true") == 0) { 847 ok = 1; 848 } 849 850 if (ok) { 851 lo->ldo_gssapi_options |= LDAP_GSSAPI_OPT_ALLOW_REMOTE_PRINCIPAL; 852 } 853 854 return 0; 855 } 856 857 return -1; 858} 859 860int 861ldap_int_gssapi_get_option( LDAP *ld, int option, void *arg ) 862{ 863 if ( ld == NULL ) 864 return -1; 865 866 switch ( option ) { 867 case LDAP_OPT_SSPI_FLAGS: 868 * (unsigned *) arg = (unsigned) ld->ld_options.gssapi_flags; 869 break; 870 871 case LDAP_OPT_SIGN: 872 if ( ld->ld_options.gssapi_flags & GSS_C_INTEG_FLAG ) { 873 * (int *) arg = (int)-1; 874 } else { 875 * (int *) arg = (int)0; 876 } 877 break; 878 879 case LDAP_OPT_ENCRYPT: 880 if ( ld->ld_options.gssapi_flags & GSS_C_CONF_FLAG ) { 881 * (int *) arg = (int)-1; 882 } else { 883 * (int *) arg = (int)0; 884 } 885 break; 886 887 case LDAP_OPT_SASL_METHOD: 888 * (char **) arg = LDAP_STRDUP("GSS-SPNEGO"); 889 break; 890 891 case LDAP_OPT_SECURITY_CONTEXT: 892 if ( ld->ld_defconn && ld->ld_defconn->lconn_gss_ctx ) { 893 * (gss_ctx_id_t *) arg = (gss_ctx_id_t)ld->ld_defconn->lconn_gss_ctx; 894 } else { 895 * (gss_ctx_id_t *) arg = GSS_C_NO_CONTEXT; 896 } 897 break; 898 899 case LDAP_OPT_X_GSSAPI_DO_NOT_FREE_CONTEXT: 900 if ( ld->ld_options.ldo_gssapi_options & LDAP_GSSAPI_OPT_DO_NOT_FREE_GSS_CONTEXT ) { 901 * (int *) arg = (int)-1; 902 } else { 903 * (int *) arg = (int)0; 904 } 905 break; 906 907 case LDAP_OPT_X_GSSAPI_ALLOW_REMOTE_PRINCIPAL: 908 if ( ld->ld_options.ldo_gssapi_options & LDAP_GSSAPI_OPT_ALLOW_REMOTE_PRINCIPAL ) { 909 * (int *) arg = (int)-1; 910 } else { 911 * (int *) arg = (int)0; 912 } 913 break; 914 915 default: 916 return -1; 917 } 918 919 return 0; 920} 921 922int 923ldap_int_gssapi_set_option( LDAP *ld, int option, void *arg ) 924{ 925 if ( ld == NULL ) 926 return -1; 927 928 switch ( option ) { 929 case LDAP_OPT_SSPI_FLAGS: 930 if ( arg != LDAP_OPT_OFF ) { 931 ld->ld_options.gssapi_flags = * (unsigned *)arg; 932 } 933 break; 934 935 case LDAP_OPT_SIGN: 936 if ( arg != LDAP_OPT_OFF ) { 937 ld->ld_options.gssapi_flags |= GSS_C_INTEG_FLAG; 938 } 939 break; 940 941 case LDAP_OPT_ENCRYPT: 942 if ( arg != LDAP_OPT_OFF ) { 943 ld->ld_options.gssapi_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG; 944 } 945 break; 946 947 case LDAP_OPT_SASL_METHOD: 948 if ( arg != LDAP_OPT_OFF ) { 949 const char *m = (const char *)arg; 950 if ( strcmp( "GSS-SPNEGO", m ) != 0 ) { 951 /* we currently only support GSS-SPNEGO */ 952 return -1; 953 } 954 } 955 break; 956 957 case LDAP_OPT_SECURITY_CONTEXT: 958 if ( arg != LDAP_OPT_OFF && ld->ld_defconn) { 959 ldap_int_gssapi_setup( ld, ld->ld_defconn, 960 (gss_ctx_id_t) arg); 961 } 962 break; 963 964 case LDAP_OPT_X_GSSAPI_DO_NOT_FREE_CONTEXT: 965 if ( arg != LDAP_OPT_OFF ) { 966 ld->ld_options.ldo_gssapi_options |= LDAP_GSSAPI_OPT_DO_NOT_FREE_GSS_CONTEXT; 967 } 968 break; 969 970 case LDAP_OPT_X_GSSAPI_ALLOW_REMOTE_PRINCIPAL: 971 if ( arg != LDAP_OPT_OFF ) { 972 ld->ld_options.ldo_gssapi_options |= LDAP_GSSAPI_OPT_ALLOW_REMOTE_PRINCIPAL; 973 } 974 break; 975 976 default: 977 return -1; 978 } 979 980 return 0; 981} 982 983#else /* HAVE_GSSAPI */ 984#define ldap_int_gss_spnego_bind_s(ld) LDAP_NOT_SUPPORTED 985#endif /* HAVE_GSSAPI */ 986 987int 988ldap_gssapi_bind( 989 LDAP *ld, 990 LDAP_CONST char *dn, 991 LDAP_CONST char *creds ) 992{ 993 return LDAP_NOT_SUPPORTED; 994} 995 996int 997ldap_gssapi_bind_s( 998 LDAP *ld, 999 LDAP_CONST char *dn, 1000 LDAP_CONST char *creds ) 1001{ 1002 if ( dn != NULL ) { 1003 return LDAP_NOT_SUPPORTED; 1004 } 1005 1006 if ( creds != NULL ) { 1007 return LDAP_NOT_SUPPORTED; 1008 } 1009 1010 return ldap_int_gss_spnego_bind_s(ld); 1011} 1012