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