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