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