cyrus.c revision 1.1.1.3
1/* $NetBSD: cyrus.c,v 1.1.1.3 2010/12/12 15:21:30 adam Exp $ */ 2 3/* OpenLDAP: pkg/ldap/libraries/libldap/cyrus.c,v 1.133.2.18 2010/06/12 22:06:11 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 * 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_CYRUS_SASL 37 38#ifdef HAVE_LIMITS_H 39#include <limits.h> 40#endif 41 42#ifndef INT_MAX 43#define INT_MAX 2147483647 /* 32 bit signed max */ 44#endif 45 46#ifdef LDAP_R_COMPILE 47ldap_pvt_thread_mutex_t ldap_int_sasl_mutex; 48#endif 49 50#ifdef HAVE_SASL_SASL_H 51#include <sasl/sasl.h> 52#else 53#include <sasl.h> 54#endif 55 56#if SASL_VERSION_MAJOR >= 2 57#define SASL_CONST const 58#else 59#define SASL_CONST 60#endif 61 62/* 63* Various Cyrus SASL related stuff. 64*/ 65 66static const sasl_callback_t client_callbacks[] = { 67#ifdef SASL_CB_GETREALM 68 { SASL_CB_GETREALM, NULL, NULL }, 69#endif 70 { SASL_CB_USER, NULL, NULL }, 71 { SASL_CB_AUTHNAME, NULL, NULL }, 72 { SASL_CB_PASS, NULL, NULL }, 73 { SASL_CB_ECHOPROMPT, NULL, NULL }, 74 { SASL_CB_NOECHOPROMPT, NULL, NULL }, 75 { SASL_CB_LIST_END, NULL, NULL } 76}; 77 78int ldap_int_sasl_init( void ) 79{ 80 /* XXX not threadsafe */ 81 static int sasl_initialized = 0; 82 83#ifdef HAVE_SASL_VERSION 84 /* stringify the version number, sasl.h doesn't do it for us */ 85#define VSTR0(maj, min, pat) #maj "." #min "." #pat 86#define VSTR(maj, min, pat) VSTR0(maj, min, pat) 87#define SASL_VERSION_STRING VSTR(SASL_VERSION_MAJOR, SASL_VERSION_MINOR, \ 88 SASL_VERSION_STEP) 89 { int rc; 90 sasl_version( NULL, &rc ); 91 if ( ((rc >> 16) != ((SASL_VERSION_MAJOR << 8)|SASL_VERSION_MINOR)) || 92 (rc & 0xffff) < SASL_VERSION_STEP) { 93 char version[sizeof("xxx.xxx.xxxxx")]; 94 sprintf( version, "%u.%d.%d", (unsigned)rc >> 24, (rc >> 16) & 0xff, 95 rc & 0xffff ); 96 97 Debug( LDAP_DEBUG_ANY, 98 "ldap_int_sasl_init: SASL library version mismatch:" 99 " expected " SASL_VERSION_STRING "," 100 " got %s\n", version, 0, 0 ); 101 return -1; 102 } 103 } 104#endif 105 if ( sasl_initialized ) { 106 return 0; 107 } 108 109/* SASL 2 takes care of its own memory completely internally */ 110#if SASL_VERSION_MAJOR < 2 && !defined(CSRIMALLOC) 111 sasl_set_alloc( 112 ber_memalloc, 113 ber_memcalloc, 114 ber_memrealloc, 115 ber_memfree ); 116#endif /* CSRIMALLOC */ 117 118#ifdef LDAP_R_COMPILE 119 sasl_set_mutex( 120 ldap_pvt_sasl_mutex_new, 121 ldap_pvt_sasl_mutex_lock, 122 ldap_pvt_sasl_mutex_unlock, 123 ldap_pvt_sasl_mutex_dispose ); 124#endif 125 126 if ( sasl_client_init( NULL ) == SASL_OK ) { 127 sasl_initialized = 1; 128 return 0; 129 } 130 131#if SASL_VERSION_MAJOR < 2 132 /* A no-op to make sure we link with Cyrus 1.5 */ 133 sasl_client_auth( NULL, NULL, NULL, 0, NULL, NULL ); 134#endif 135 return -1; 136} 137 138static void 139sb_sasl_cyrus_init( 140 struct sb_sasl_generic_data *p, 141 ber_len_t *min_send, 142 ber_len_t *max_send, 143 ber_len_t *max_recv) 144{ 145 sasl_conn_t *sasl_context = (sasl_conn_t *)p->ops_private; 146 ber_len_t maxbuf; 147 148 sasl_getprop( sasl_context, SASL_MAXOUTBUF, 149 (SASL_CONST void **)(char *) &maxbuf ); 150 151 *min_send = SASL_MIN_BUFF_SIZE; 152 *max_send = maxbuf; 153 *max_recv = SASL_MAX_BUFF_SIZE; 154} 155 156static ber_int_t 157sb_sasl_cyrus_encode( 158 struct sb_sasl_generic_data *p, 159 unsigned char *buf, 160 ber_len_t len, 161 Sockbuf_Buf *dst) 162{ 163 sasl_conn_t *sasl_context = (sasl_conn_t *)p->ops_private; 164 ber_int_t ret; 165 unsigned tmpsize = dst->buf_size; 166 167 ret = sasl_encode( sasl_context, (char *)buf, len, 168 (SASL_CONST char **)&dst->buf_base, 169 &tmpsize ); 170 171 dst->buf_size = tmpsize; 172 dst->buf_end = dst->buf_size; 173 174 if ( ret != SASL_OK ) { 175 ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug, 176 "sb_sasl_cyrus_encode: failed to encode packet: %s\n", 177 sasl_errstring( ret, NULL, NULL ) ); 178 return -1; 179 } 180 181 return 0; 182} 183 184static ber_int_t 185sb_sasl_cyrus_decode( 186 struct sb_sasl_generic_data *p, 187 const Sockbuf_Buf *src, 188 Sockbuf_Buf *dst) 189{ 190 sasl_conn_t *sasl_context = (sasl_conn_t *)p->ops_private; 191 ber_int_t ret; 192 unsigned tmpsize = dst->buf_size; 193 194 ret = sasl_decode( sasl_context, 195 src->buf_base, src->buf_end, 196 (SASL_CONST char **)&dst->buf_base, 197 (unsigned *)&tmpsize ); 198 199 200 dst->buf_size = tmpsize; 201 dst->buf_end = dst->buf_size; 202 203 if ( ret != SASL_OK ) { 204 ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug, 205 "sb_sasl_cyrus_decode: failed to decode packet: %s\n", 206 sasl_errstring( ret, NULL, NULL ) ); 207 return -1; 208 } 209 210 return 0; 211} 212 213static void 214sb_sasl_cyrus_reset_buf( 215 struct sb_sasl_generic_data *p, 216 Sockbuf_Buf *buf) 217{ 218#if SASL_VERSION_MAJOR >= 2 219 ber_pvt_sb_buf_init( buf ); 220#else 221 ber_pvt_sb_buf_destroy( buf ); 222#endif 223} 224 225static void 226sb_sasl_cyrus_fini( 227 struct sb_sasl_generic_data *p) 228{ 229#if SASL_VERSION_MAJOR >= 2 230 /* 231 * SASLv2 encode/decode buffers are managed by 232 * libsasl2. Ensure they are not freed by liblber. 233 */ 234 p->buf_in.buf_base = NULL; 235 p->buf_out.buf_base = NULL; 236#endif 237} 238 239static const struct sb_sasl_generic_ops sb_sasl_cyrus_ops = { 240 sb_sasl_cyrus_init, 241 sb_sasl_cyrus_encode, 242 sb_sasl_cyrus_decode, 243 sb_sasl_cyrus_reset_buf, 244 sb_sasl_cyrus_fini 245 }; 246 247int ldap_pvt_sasl_install( Sockbuf *sb, void *ctx_arg ) 248{ 249 struct sb_sasl_generic_install install_arg; 250 251 install_arg.ops = &sb_sasl_cyrus_ops; 252 install_arg.ops_private = ctx_arg; 253 254 return ldap_pvt_sasl_generic_install( sb, &install_arg ); 255} 256 257void ldap_pvt_sasl_remove( Sockbuf *sb ) 258{ 259 ldap_pvt_sasl_generic_remove( sb ); 260} 261 262static int 263sasl_err2ldap( int saslerr ) 264{ 265 int rc; 266 267 /* map SASL errors to LDAP API errors returned by: 268 * sasl_client_new() 269 * SASL_OK, SASL_NOMECH, SASL_NOMEM 270 * sasl_client_start() 271 * SASL_OK, SASL_NOMECH, SASL_NOMEM, SASL_INTERACT 272 * sasl_client_step() 273 * SASL_OK, SASL_INTERACT, SASL_BADPROT, SASL_BADSERV 274 */ 275 276 switch (saslerr) { 277 case SASL_CONTINUE: 278 rc = LDAP_MORE_RESULTS_TO_RETURN; 279 break; 280 case SASL_INTERACT: 281 rc = LDAP_LOCAL_ERROR; 282 break; 283 case SASL_OK: 284 rc = LDAP_SUCCESS; 285 break; 286 case SASL_NOMEM: 287 rc = LDAP_NO_MEMORY; 288 break; 289 case SASL_NOMECH: 290 rc = LDAP_AUTH_UNKNOWN; 291 break; 292 case SASL_BADPROT: 293 rc = LDAP_DECODING_ERROR; 294 break; 295 case SASL_BADSERV: 296 rc = LDAP_AUTH_UNKNOWN; 297 break; 298 299 /* other codes */ 300 case SASL_BADAUTH: 301 rc = LDAP_AUTH_UNKNOWN; 302 break; 303 case SASL_NOAUTHZ: 304 rc = LDAP_PARAM_ERROR; 305 break; 306 case SASL_FAIL: 307 rc = LDAP_LOCAL_ERROR; 308 break; 309 case SASL_TOOWEAK: 310 case SASL_ENCRYPT: 311 rc = LDAP_AUTH_UNKNOWN; 312 break; 313 default: 314 rc = LDAP_LOCAL_ERROR; 315 break; 316 } 317 318 assert( rc == LDAP_SUCCESS || LDAP_API_ERROR( rc ) ); 319 return rc; 320} 321 322int 323ldap_int_sasl_open( 324 LDAP *ld, 325 LDAPConn *lc, 326 const char * host ) 327{ 328 int rc; 329 sasl_conn_t *ctx; 330 331 assert( lc->lconn_sasl_authctx == NULL ); 332 333 if ( host == NULL ) { 334 ld->ld_errno = LDAP_LOCAL_ERROR; 335 return ld->ld_errno; 336 } 337 338 if ( ldap_int_sasl_init() ) { 339 ld->ld_errno = LDAP_LOCAL_ERROR; 340 return ld->ld_errno; 341 } 342 343#if SASL_VERSION_MAJOR >= 2 344 rc = sasl_client_new( "ldap", host, NULL, NULL, 345 client_callbacks, 0, &ctx ); 346#else 347 rc = sasl_client_new( "ldap", host, client_callbacks, 348 SASL_SECURITY_LAYER, &ctx ); 349#endif 350 351 if ( rc != SASL_OK ) { 352 ld->ld_errno = sasl_err2ldap( rc ); 353 return ld->ld_errno; 354 } 355 356 Debug( LDAP_DEBUG_TRACE, "ldap_int_sasl_open: host=%s\n", 357 host, 0, 0 ); 358 359 lc->lconn_sasl_authctx = ctx; 360 361 return LDAP_SUCCESS; 362} 363 364int ldap_int_sasl_close( LDAP *ld, LDAPConn *lc ) 365{ 366 sasl_conn_t *ctx = lc->lconn_sasl_authctx; 367 368 if( ctx != NULL ) { 369 sasl_dispose( &ctx ); 370 if ( lc->lconn_sasl_sockctx && 371 lc->lconn_sasl_authctx != lc->lconn_sasl_sockctx ) { 372 ctx = lc->lconn_sasl_sockctx; 373 sasl_dispose( &ctx ); 374 } 375 lc->lconn_sasl_sockctx = NULL; 376 lc->lconn_sasl_authctx = NULL; 377 } 378 379 return LDAP_SUCCESS; 380} 381 382int 383ldap_int_sasl_bind( 384 LDAP *ld, 385 const char *dn, 386 const char *mechs, 387 LDAPControl **sctrls, 388 LDAPControl **cctrls, 389 unsigned flags, 390 LDAP_SASL_INTERACT_PROC *interact, 391 void * defaults ) 392{ 393 char *data; 394 const char *mech = NULL; 395 const char *pmech = NULL; 396 int saslrc, rc; 397 sasl_ssf_t *ssf = NULL; 398 sasl_conn_t *ctx, *oldctx = NULL; 399 sasl_interact_t *prompts = NULL; 400 unsigned credlen; 401 struct berval ccred; 402 ber_socket_t sd; 403 void *ssl; 404 405 Debug( LDAP_DEBUG_TRACE, "ldap_int_sasl_bind: %s\n", 406 mechs ? mechs : "<null>", 0, 0 ); 407 408 /* do a quick !LDAPv3 check... ldap_sasl_bind will do the rest. */ 409 if (ld->ld_version < LDAP_VERSION3) { 410 ld->ld_errno = LDAP_NOT_SUPPORTED; 411 return ld->ld_errno; 412 } 413 414 rc = 0; 415#ifdef LDAP_R_COMPILE 416 ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex ); 417#endif 418 ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd ); 419 420 if ( sd == AC_SOCKET_INVALID ) { 421 /* not connected yet */ 422 423 rc = ldap_open_defconn( ld ); 424 425 if ( rc == 0 ) { 426 ber_sockbuf_ctrl( ld->ld_defconn->lconn_sb, 427 LBER_SB_OPT_GET_FD, &sd ); 428 429 if( sd == AC_SOCKET_INVALID ) { 430 ld->ld_errno = LDAP_LOCAL_ERROR; 431 rc = ld->ld_errno; 432 } 433 } 434 } 435#ifdef LDAP_R_COMPILE 436 ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex ); 437#endif 438 if( rc != 0 ) return ld->ld_errno; 439 440 oldctx = ld->ld_defconn->lconn_sasl_authctx; 441 442 /* If we already have an authentication context, clear it out */ 443 if( oldctx ) { 444 if ( oldctx != ld->ld_defconn->lconn_sasl_sockctx ) { 445 sasl_dispose( &oldctx ); 446 } 447 ld->ld_defconn->lconn_sasl_authctx = NULL; 448 } 449 450 { 451 char *saslhost; 452 int nocanon = (int)LDAP_BOOL_GET( &ld->ld_options, 453 LDAP_BOOL_SASL_NOCANON ); 454 455 /* If we don't need to canonicalize just use the host 456 * from the LDAP URI. 457 */ 458 if ( nocanon ) 459 saslhost = ld->ld_defconn->lconn_server->lud_host; 460 else 461 saslhost = ldap_host_connected_to( ld->ld_defconn->lconn_sb, 462 "localhost" ); 463 rc = ldap_int_sasl_open( ld, ld->ld_defconn, saslhost ); 464 if ( !nocanon ) 465 LDAP_FREE( saslhost ); 466 } 467 468 if ( rc != LDAP_SUCCESS ) return rc; 469 470 ctx = ld->ld_defconn->lconn_sasl_authctx; 471 472#ifdef HAVE_TLS 473 /* Check for TLS */ 474 ssl = ldap_pvt_tls_sb_ctx( ld->ld_defconn->lconn_sb ); 475 if ( ssl ) { 476 struct berval authid = BER_BVNULL; 477 ber_len_t fac; 478 479 fac = ldap_pvt_tls_get_strength( ssl ); 480 /* failure is OK, we just can't use SASL EXTERNAL */ 481 (void) ldap_pvt_tls_get_my_dn( ssl, &authid, NULL, 0 ); 482 483 (void) ldap_int_sasl_external( ld, ld->ld_defconn, authid.bv_val, fac ); 484 LDAP_FREE( authid.bv_val ); 485 } 486#endif 487 488#if !defined(_WIN32) 489 /* Check for local */ 490 if ( ldap_pvt_url_scheme2proto( 491 ld->ld_defconn->lconn_server->lud_scheme ) == LDAP_PROTO_IPC ) 492 { 493 char authid[sizeof("gidNumber=4294967295+uidNumber=4294967295," 494 "cn=peercred,cn=external,cn=auth")]; 495 sprintf( authid, "gidNumber=%u+uidNumber=%u," 496 "cn=peercred,cn=external,cn=auth", 497 getegid(), geteuid() ); 498 (void) ldap_int_sasl_external( ld, ld->ld_defconn, authid, 499 LDAP_PVT_SASL_LOCAL_SSF ); 500 } 501#endif 502 503 /* (re)set security properties */ 504 sasl_setprop( ctx, SASL_SEC_PROPS, 505 &ld->ld_options.ldo_sasl_secprops ); 506 507 ccred.bv_val = NULL; 508 ccred.bv_len = 0; 509 510 do { 511 saslrc = sasl_client_start( ctx, 512 mechs, 513#if SASL_VERSION_MAJOR < 2 514 NULL, 515#endif 516 &prompts, 517 (SASL_CONST char **)&ccred.bv_val, 518 &credlen, 519 &mech ); 520 521 if( pmech == NULL && mech != NULL ) { 522 pmech = mech; 523 524 if( flags != LDAP_SASL_QUIET ) { 525 fprintf(stderr, 526 "SASL/%s authentication started\n", 527 pmech ); 528 } 529 } 530 531 if( saslrc == SASL_INTERACT ) { 532 int res; 533 if( !interact ) break; 534 res = (interact)( ld, flags, defaults, prompts ); 535 536 if( res != LDAP_SUCCESS ) break; 537 } 538 } while ( saslrc == SASL_INTERACT ); 539 540 ccred.bv_len = credlen; 541 542 if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) { 543 rc = ld->ld_errno = sasl_err2ldap( saslrc ); 544#if SASL_VERSION_MAJOR >= 2 545 if ( ld->ld_error ) { 546 LDAP_FREE( ld->ld_error ); 547 } 548 ld->ld_error = LDAP_STRDUP( sasl_errdetail( ctx ) ); 549#endif 550 goto done; 551 } 552 553 do { 554 struct berval *scred; 555 unsigned credlen; 556 557 scred = NULL; 558 559 rc = ldap_sasl_bind_s( ld, dn, mech, &ccred, sctrls, cctrls, 560 &scred ); 561 562 if ( ccred.bv_val != NULL ) { 563#if SASL_VERSION_MAJOR < 2 564 LDAP_FREE( ccred.bv_val ); 565#endif 566 ccred.bv_val = NULL; 567 } 568 569 if ( rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS ) { 570 if( scred ) { 571 /* and server provided us with data? */ 572 Debug( LDAP_DEBUG_TRACE, 573 "ldap_int_sasl_bind: rc=%d sasl=%d len=%ld\n", 574 rc, saslrc, scred ? (long) scred->bv_len : -1L ); 575 ber_bvfree( scred ); 576 scred = NULL; 577 } 578 rc = ld->ld_errno; 579 goto done; 580 } 581 582 if( rc == LDAP_SUCCESS && saslrc == SASL_OK ) { 583 /* we're done, no need to step */ 584 if( scred ) { 585 /* but we got additional data? */ 586#define KLUDGE_FOR_MSAD 587#ifdef KLUDGE_FOR_MSAD 588 /* 589 * MSAD provides empty additional data in violation of LDAP 590 * technical specifications. As no existing SASL mechanism 591 * allows empty data with an outcome message, just ignore it 592 * for now. Hopefully MS will fix their bug before someone 593 * defines a mechanism with possibly empty additional data. 594 */ 595 if( scred->bv_len == 0 ) { 596 Debug( LDAP_DEBUG_ANY, 597 "ldap_int_sasl_bind: ignoring " 598 " bogus empty data provided with SASL outcome message.\n", 599 rc, saslrc, scred->bv_len ); 600 ber_bvfree( scred ); 601 } else 602#endif 603 { 604 Debug( LDAP_DEBUG_TRACE, 605 "ldap_int_sasl_bind: rc=%d sasl=%d len=%ld\n", 606 rc, saslrc, scred->bv_len ); 607 rc = ld->ld_errno = LDAP_LOCAL_ERROR; 608 ber_bvfree( scred ); 609 goto done; 610 } 611 } 612 break; 613 } 614 615 do { 616 if( ! scred ) { 617 /* no data! */ 618 Debug( LDAP_DEBUG_TRACE, 619 "ldap_int_sasl_bind: no data in step!\n", 620 0, 0, 0 ); 621 } 622 623 saslrc = sasl_client_step( ctx, 624 (scred == NULL) ? NULL : scred->bv_val, 625 (scred == NULL) ? 0 : scred->bv_len, 626 &prompts, 627 (SASL_CONST char **)&ccred.bv_val, 628 &credlen ); 629 630 Debug( LDAP_DEBUG_TRACE, "sasl_client_step: %d\n", 631 saslrc, 0, 0 ); 632 633 if( saslrc == SASL_INTERACT ) { 634 int res; 635 if( !interact ) break; 636 res = (interact)( ld, flags, defaults, prompts ); 637 if( res != LDAP_SUCCESS ) break; 638 } 639 } while ( saslrc == SASL_INTERACT ); 640 641 ccred.bv_len = credlen; 642 ber_bvfree( scred ); 643 644 if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) { 645 ld->ld_errno = sasl_err2ldap( saslrc ); 646#if SASL_VERSION_MAJOR >= 2 647 if ( ld->ld_error ) { 648 LDAP_FREE( ld->ld_error ); 649 } 650 ld->ld_error = LDAP_STRDUP( sasl_errdetail( ctx ) ); 651#endif 652 rc = ld->ld_errno; 653 goto done; 654 } 655 } while ( rc == LDAP_SASL_BIND_IN_PROGRESS ); 656 657 if ( rc != LDAP_SUCCESS ) goto done; 658 659 if ( saslrc != SASL_OK ) { 660#if SASL_VERSION_MAJOR >= 2 661 if ( ld->ld_error ) { 662 LDAP_FREE( ld->ld_error ); 663 } 664 ld->ld_error = LDAP_STRDUP( sasl_errdetail( ctx ) ); 665#endif 666 rc = ld->ld_errno = sasl_err2ldap( saslrc ); 667 goto done; 668 } 669 670 if( flags != LDAP_SASL_QUIET ) { 671 saslrc = sasl_getprop( ctx, SASL_USERNAME, 672 (SASL_CONST void **)(char *) &data ); 673 if( saslrc == SASL_OK && data && *data ) { 674 fprintf( stderr, "SASL username: %s\n", data ); 675 } 676 677#if SASL_VERSION_MAJOR < 2 678 saslrc = sasl_getprop( ctx, SASL_REALM, 679 (SASL_CONST void **) &data ); 680 if( saslrc == SASL_OK && data && *data ) { 681 fprintf( stderr, "SASL realm: %s\n", data ); 682 } 683#endif 684 } 685 686 saslrc = sasl_getprop( ctx, SASL_SSF, (SASL_CONST void **)(char *) &ssf ); 687 if( saslrc == SASL_OK ) { 688 if( flags != LDAP_SASL_QUIET ) { 689 fprintf( stderr, "SASL SSF: %lu\n", 690 (unsigned long) *ssf ); 691 } 692 693 if( ssf && *ssf ) { 694 if ( ld->ld_defconn->lconn_sasl_sockctx ) { 695 oldctx = ld->ld_defconn->lconn_sasl_sockctx; 696 sasl_dispose( &oldctx ); 697 ldap_pvt_sasl_remove( ld->ld_defconn->lconn_sb ); 698 } 699 ldap_pvt_sasl_install( ld->ld_defconn->lconn_sb, ctx ); 700 ld->ld_defconn->lconn_sasl_sockctx = ctx; 701 702 if( flags != LDAP_SASL_QUIET ) { 703 fprintf( stderr, "SASL data security layer installed.\n" ); 704 } 705 } 706 } 707 ld->ld_defconn->lconn_sasl_authctx = ctx; 708 709done: 710 return rc; 711} 712 713int 714ldap_int_sasl_external( 715 LDAP *ld, 716 LDAPConn *conn, 717 const char * authid, 718 ber_len_t ssf ) 719{ 720 int sc; 721 sasl_conn_t *ctx; 722#if SASL_VERSION_MAJOR < 2 723 sasl_external_properties_t extprops; 724#else 725 sasl_ssf_t sasl_ssf = ssf; 726#endif 727 728 ctx = conn->lconn_sasl_authctx; 729 730 if ( ctx == NULL ) { 731 return LDAP_LOCAL_ERROR; 732 } 733 734#if SASL_VERSION_MAJOR >= 2 735 sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL, &sasl_ssf ); 736 if ( sc == SASL_OK ) 737 sc = sasl_setprop( ctx, SASL_AUTH_EXTERNAL, authid ); 738#else 739 memset( &extprops, '\0', sizeof(extprops) ); 740 extprops.ssf = ssf; 741 extprops.auth_id = (char *) authid; 742 743 sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL, 744 (void *) &extprops ); 745#endif 746 747 if ( sc != SASL_OK ) { 748 return LDAP_LOCAL_ERROR; 749 } 750 751 return LDAP_SUCCESS; 752} 753 754 755#define GOT_MINSSF 1 756#define GOT_MAXSSF 2 757#define GOT_MAXBUF 4 758 759static struct { 760 struct berval key; 761 int sflag; 762 int ival; 763 int idef; 764} sprops[] = { 765 { BER_BVC("none"), 0, 0, 0 }, 766 { BER_BVC("nodict"), SASL_SEC_NODICTIONARY, 0, 0 }, 767 { BER_BVC("noplain"), SASL_SEC_NOPLAINTEXT, 0, 0 }, 768 { BER_BVC("noactive"), SASL_SEC_NOACTIVE, 0, 0 }, 769 { BER_BVC("passcred"), SASL_SEC_PASS_CREDENTIALS, 0, 0 }, 770 { BER_BVC("forwardsec"), SASL_SEC_FORWARD_SECRECY, 0, 0 }, 771 { BER_BVC("noanonymous"), SASL_SEC_NOANONYMOUS, 0, 0 }, 772 { BER_BVC("minssf="), 0, GOT_MINSSF, 0 }, 773 { BER_BVC("maxssf="), 0, GOT_MAXSSF, INT_MAX }, 774 { BER_BVC("maxbufsize="), 0, GOT_MAXBUF, 65536 }, 775 { BER_BVNULL, 0, 0, 0 } 776}; 777 778void ldap_pvt_sasl_secprops_unparse( 779 sasl_security_properties_t *secprops, 780 struct berval *out ) 781{ 782 int i, l = 0; 783 int comma; 784 char *ptr; 785 786 if ( secprops == NULL || out == NULL ) { 787 return; 788 } 789 790 comma = 0; 791 for ( i=0; !BER_BVISNULL( &sprops[i].key ); i++ ) { 792 if ( sprops[i].ival ) { 793 int v = 0; 794 795 switch( sprops[i].ival ) { 796 case GOT_MINSSF: v = secprops->min_ssf; break; 797 case GOT_MAXSSF: v = secprops->max_ssf; break; 798 case GOT_MAXBUF: v = secprops->maxbufsize; break; 799 } 800 /* It is the default, ignore it */ 801 if ( v == sprops[i].idef ) continue; 802 803 l += sprops[i].key.bv_len + 24; 804 } else if ( sprops[i].sflag ) { 805 if ( sprops[i].sflag & secprops->security_flags ) { 806 l += sprops[i].key.bv_len; 807 } 808 } else if ( secprops->security_flags == 0 ) { 809 l += sprops[i].key.bv_len; 810 } 811 if ( comma ) l++; 812 comma = 1; 813 } 814 l++; 815 816 out->bv_val = LDAP_MALLOC( l ); 817 if ( out->bv_val == NULL ) { 818 out->bv_len = 0; 819 return; 820 } 821 822 ptr = out->bv_val; 823 comma = 0; 824 for ( i=0; !BER_BVISNULL( &sprops[i].key ); i++ ) { 825 if ( sprops[i].ival ) { 826 int v = 0; 827 828 switch( sprops[i].ival ) { 829 case GOT_MINSSF: v = secprops->min_ssf; break; 830 case GOT_MAXSSF: v = secprops->max_ssf; break; 831 case GOT_MAXBUF: v = secprops->maxbufsize; break; 832 } 833 /* It is the default, ignore it */ 834 if ( v == sprops[i].idef ) continue; 835 836 if ( comma ) *ptr++ = ','; 837 ptr += sprintf(ptr, "%s%d", sprops[i].key.bv_val, v ); 838 comma = 1; 839 } else if ( sprops[i].sflag ) { 840 if ( sprops[i].sflag & secprops->security_flags ) { 841 if ( comma ) *ptr++ = ','; 842 ptr += sprintf(ptr, "%s", sprops[i].key.bv_val ); 843 comma = 1; 844 } 845 } else if ( secprops->security_flags == 0 ) { 846 if ( comma ) *ptr++ = ','; 847 ptr += sprintf(ptr, "%s", sprops[i].key.bv_val ); 848 comma = 1; 849 } 850 } 851 out->bv_len = ptr - out->bv_val; 852} 853 854int ldap_pvt_sasl_secprops( 855 const char *in, 856 sasl_security_properties_t *secprops ) 857{ 858 unsigned i, j, l; 859 char **props; 860 unsigned sflags = 0; 861 int got_sflags = 0; 862 sasl_ssf_t max_ssf = 0; 863 int got_max_ssf = 0; 864 sasl_ssf_t min_ssf = 0; 865 int got_min_ssf = 0; 866 unsigned maxbufsize = 0; 867 int got_maxbufsize = 0; 868 869 if( secprops == NULL ) { 870 return LDAP_PARAM_ERROR; 871 } 872 props = ldap_str2charray( in, "," ); 873 if( props == NULL ) { 874 return LDAP_PARAM_ERROR; 875 } 876 877 for( i=0; props[i]; i++ ) { 878 l = strlen( props[i] ); 879 for ( j=0; !BER_BVISNULL( &sprops[j].key ); j++ ) { 880 if ( l < sprops[j].key.bv_len ) continue; 881 if ( strncasecmp( props[i], sprops[j].key.bv_val, 882 sprops[j].key.bv_len )) continue; 883 if ( sprops[j].ival ) { 884 unsigned v; 885 char *next = NULL; 886 if ( !isdigit( (unsigned char)props[i][sprops[j].key.bv_len] )) 887 continue; 888 v = strtoul( &props[i][sprops[j].key.bv_len], &next, 10 ); 889 if ( next == &props[i][sprops[j].key.bv_len] || next[0] != '\0' ) continue; 890 switch( sprops[j].ival ) { 891 case GOT_MINSSF: 892 min_ssf = v; got_min_ssf++; break; 893 case GOT_MAXSSF: 894 max_ssf = v; got_max_ssf++; break; 895 case GOT_MAXBUF: 896 maxbufsize = v; got_maxbufsize++; break; 897 } 898 } else { 899 if ( props[i][sprops[j].key.bv_len] ) continue; 900 if ( sprops[j].sflag ) 901 sflags |= sprops[j].sflag; 902 else 903 sflags = 0; 904 got_sflags++; 905 } 906 break; 907 } 908 if ( BER_BVISNULL( &sprops[j].key )) { 909 ldap_charray_free( props ); 910 return LDAP_NOT_SUPPORTED; 911 } 912 } 913 914 if(got_sflags) { 915 secprops->security_flags = sflags; 916 } 917 if(got_min_ssf) { 918 secprops->min_ssf = min_ssf; 919 } 920 if(got_max_ssf) { 921 secprops->max_ssf = max_ssf; 922 } 923 if(got_maxbufsize) { 924 secprops->maxbufsize = maxbufsize; 925 } 926 927 ldap_charray_free( props ); 928 return LDAP_SUCCESS; 929} 930 931int 932ldap_int_sasl_config( struct ldapoptions *lo, int option, const char *arg ) 933{ 934 int rc; 935 936 switch( option ) { 937 case LDAP_OPT_X_SASL_SECPROPS: 938 rc = ldap_pvt_sasl_secprops( arg, &lo->ldo_sasl_secprops ); 939 if( rc == LDAP_SUCCESS ) return 0; 940 } 941 942 return -1; 943} 944 945int 946ldap_int_sasl_get_option( LDAP *ld, int option, void *arg ) 947{ 948 if ( option == LDAP_OPT_X_SASL_MECHLIST ) { 949 if ( ldap_int_sasl_init() ) 950 return -1; 951 *(char ***)arg = (char **)sasl_global_listmech(); 952 return 0; 953 } 954 955 if ( ld == NULL ) 956 return -1; 957 958 switch ( option ) { 959 case LDAP_OPT_X_SASL_MECH: { 960 *(char **)arg = ld->ld_options.ldo_def_sasl_mech 961 ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_mech ) : NULL; 962 } break; 963 case LDAP_OPT_X_SASL_REALM: { 964 *(char **)arg = ld->ld_options.ldo_def_sasl_realm 965 ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_realm ) : NULL; 966 } break; 967 case LDAP_OPT_X_SASL_AUTHCID: { 968 *(char **)arg = ld->ld_options.ldo_def_sasl_authcid 969 ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_authcid ) : NULL; 970 } break; 971 case LDAP_OPT_X_SASL_AUTHZID: { 972 *(char **)arg = ld->ld_options.ldo_def_sasl_authzid 973 ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_authzid ) : NULL; 974 } break; 975 976 case LDAP_OPT_X_SASL_SSF: { 977 int sc; 978 sasl_ssf_t *ssf; 979 sasl_conn_t *ctx; 980 981 if( ld->ld_defconn == NULL ) { 982 return -1; 983 } 984 985 ctx = ld->ld_defconn->lconn_sasl_sockctx; 986 987 if ( ctx == NULL ) { 988 return -1; 989 } 990 991 sc = sasl_getprop( ctx, SASL_SSF, 992 (SASL_CONST void **)(char *) &ssf ); 993 994 if ( sc != SASL_OK ) { 995 return -1; 996 } 997 998 *(ber_len_t *)arg = *ssf; 999 } break; 1000 1001 case LDAP_OPT_X_SASL_SSF_EXTERNAL: 1002 /* this option is write only */ 1003 return -1; 1004 1005 case LDAP_OPT_X_SASL_SSF_MIN: 1006 *(ber_len_t *)arg = ld->ld_options.ldo_sasl_secprops.min_ssf; 1007 break; 1008 case LDAP_OPT_X_SASL_SSF_MAX: 1009 *(ber_len_t *)arg = ld->ld_options.ldo_sasl_secprops.max_ssf; 1010 break; 1011 case LDAP_OPT_X_SASL_MAXBUFSIZE: 1012 *(ber_len_t *)arg = ld->ld_options.ldo_sasl_secprops.maxbufsize; 1013 break; 1014 case LDAP_OPT_X_SASL_NOCANON: 1015 *(int *)arg = (int) LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_SASL_NOCANON ); 1016 break; 1017 1018 case LDAP_OPT_X_SASL_USERNAME: { 1019 int sc; 1020 char *username; 1021 sasl_conn_t *ctx; 1022 1023 if( ld->ld_defconn == NULL ) { 1024 return -1; 1025 } 1026 1027 ctx = ld->ld_defconn->lconn_sasl_authctx; 1028 1029 if ( ctx == NULL ) { 1030 return -1; 1031 } 1032 1033 sc = sasl_getprop( ctx, SASL_USERNAME, 1034 (SASL_CONST void **)(char **) &username ); 1035 1036 if ( sc != SASL_OK ) { 1037 return -1; 1038 } 1039 1040 *(char **)arg = username ? LDAP_STRDUP( username ) : NULL; 1041 } break; 1042 1043 case LDAP_OPT_X_SASL_SECPROPS: 1044 /* this option is write only */ 1045 return -1; 1046 1047#ifdef SASL_GSS_CREDS 1048 case LDAP_OPT_X_SASL_GSS_CREDS: { 1049 sasl_conn_t *ctx; 1050 int sc; 1051 1052 if ( ld->ld_defconn == NULL ) 1053 return -1; 1054 1055 ctx = ld->ld_defconn->lconn_sasl_authctx; 1056 if ( ctx == NULL ) 1057 return -1; 1058 1059 sc = sasl_getprop( ctx, SASL_GSS_CREDS, arg ); 1060 if ( sc != SASL_OK ) 1061 return -1; 1062 } 1063 break; 1064#endif 1065 1066 default: 1067 return -1; 1068 } 1069 return 0; 1070} 1071 1072int 1073ldap_int_sasl_set_option( LDAP *ld, int option, void *arg ) 1074{ 1075 if ( ld == NULL ) 1076 return -1; 1077 1078 if ( arg == NULL && option != LDAP_OPT_X_SASL_NOCANON ) 1079 return -1; 1080 1081 switch ( option ) { 1082 case LDAP_OPT_X_SASL_SSF: 1083 case LDAP_OPT_X_SASL_USERNAME: 1084 /* This option is read-only */ 1085 return -1; 1086 1087 case LDAP_OPT_X_SASL_SSF_EXTERNAL: { 1088 int sc; 1089#if SASL_VERSION_MAJOR < 2 1090 sasl_external_properties_t extprops; 1091#else 1092 sasl_ssf_t sasl_ssf; 1093#endif 1094 sasl_conn_t *ctx; 1095 1096 if( ld->ld_defconn == NULL ) { 1097 return -1; 1098 } 1099 1100 ctx = ld->ld_defconn->lconn_sasl_authctx; 1101 1102 if ( ctx == NULL ) { 1103 return -1; 1104 } 1105 1106#if SASL_VERSION_MAJOR >= 2 1107 sasl_ssf = * (ber_len_t *)arg; 1108 sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL, &sasl_ssf); 1109#else 1110 memset(&extprops, 0L, sizeof(extprops)); 1111 1112 extprops.ssf = * (ber_len_t *) arg; 1113 1114 sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL, 1115 (void *) &extprops ); 1116#endif 1117 1118 if ( sc != SASL_OK ) { 1119 return -1; 1120 } 1121 } break; 1122 1123 case LDAP_OPT_X_SASL_SSF_MIN: 1124 ld->ld_options.ldo_sasl_secprops.min_ssf = *(ber_len_t *)arg; 1125 break; 1126 case LDAP_OPT_X_SASL_SSF_MAX: 1127 ld->ld_options.ldo_sasl_secprops.max_ssf = *(ber_len_t *)arg; 1128 break; 1129 case LDAP_OPT_X_SASL_MAXBUFSIZE: 1130 ld->ld_options.ldo_sasl_secprops.maxbufsize = *(ber_len_t *)arg; 1131 break; 1132 case LDAP_OPT_X_SASL_NOCANON: 1133 if ( arg == LDAP_OPT_OFF ) { 1134 LDAP_BOOL_CLR(&ld->ld_options, LDAP_BOOL_SASL_NOCANON ); 1135 } else { 1136 LDAP_BOOL_SET(&ld->ld_options, LDAP_BOOL_SASL_NOCANON ); 1137 } 1138 break; 1139 1140 case LDAP_OPT_X_SASL_SECPROPS: { 1141 int sc; 1142 sc = ldap_pvt_sasl_secprops( (char *) arg, 1143 &ld->ld_options.ldo_sasl_secprops ); 1144 1145 return sc == LDAP_SUCCESS ? 0 : -1; 1146 } 1147 1148#ifdef SASL_GSS_CREDS 1149 case LDAP_OPT_X_SASL_GSS_CREDS: { 1150 sasl_conn_t *ctx; 1151 int sc; 1152 1153 if ( ld->ld_defconn == NULL ) 1154 return -1; 1155 1156 ctx = ld->ld_defconn->lconn_sasl_authctx; 1157 if ( ctx == NULL ) 1158 return -1; 1159 1160 sc = sasl_setprop( ctx, SASL_GSS_CREDS, arg ); 1161 if ( sc != SASL_OK ) 1162 return -1; 1163 } 1164 break; 1165#endif 1166 1167 default: 1168 return -1; 1169 } 1170 return 0; 1171} 1172 1173#ifdef LDAP_R_COMPILE 1174#define LDAP_DEBUG_R_SASL 1175void *ldap_pvt_sasl_mutex_new(void) 1176{ 1177 ldap_pvt_thread_mutex_t *mutex; 1178 1179 mutex = (ldap_pvt_thread_mutex_t *) LDAP_CALLOC( 1, 1180 sizeof(ldap_pvt_thread_mutex_t) ); 1181 1182 if ( ldap_pvt_thread_mutex_init( mutex ) == 0 ) { 1183 return mutex; 1184 } 1185#ifndef LDAP_DEBUG_R_SASL 1186 assert( 0 ); 1187#endif /* !LDAP_DEBUG_R_SASL */ 1188 return NULL; 1189} 1190 1191int ldap_pvt_sasl_mutex_lock(void *mutex) 1192{ 1193#ifdef LDAP_DEBUG_R_SASL 1194 if ( mutex == NULL ) { 1195 return SASL_OK; 1196 } 1197#else /* !LDAP_DEBUG_R_SASL */ 1198 assert( mutex != NULL ); 1199#endif /* !LDAP_DEBUG_R_SASL */ 1200 return ldap_pvt_thread_mutex_lock( (ldap_pvt_thread_mutex_t *)mutex ) 1201 ? SASL_FAIL : SASL_OK; 1202} 1203 1204int ldap_pvt_sasl_mutex_unlock(void *mutex) 1205{ 1206#ifdef LDAP_DEBUG_R_SASL 1207 if ( mutex == NULL ) { 1208 return SASL_OK; 1209 } 1210#else /* !LDAP_DEBUG_R_SASL */ 1211 assert( mutex != NULL ); 1212#endif /* !LDAP_DEBUG_R_SASL */ 1213 return ldap_pvt_thread_mutex_unlock( (ldap_pvt_thread_mutex_t *)mutex ) 1214 ? SASL_FAIL : SASL_OK; 1215} 1216 1217void ldap_pvt_sasl_mutex_dispose(void *mutex) 1218{ 1219#ifdef LDAP_DEBUG_R_SASL 1220 if ( mutex == NULL ) { 1221 return; 1222 } 1223#else /* !LDAP_DEBUG_R_SASL */ 1224 assert( mutex != NULL ); 1225#endif /* !LDAP_DEBUG_R_SASL */ 1226 (void) ldap_pvt_thread_mutex_destroy( (ldap_pvt_thread_mutex_t *)mutex ); 1227 LDAP_FREE( mutex ); 1228} 1229#endif 1230 1231#else 1232int ldap_int_sasl_init( void ) 1233{ return LDAP_SUCCESS; } 1234 1235int ldap_int_sasl_close( LDAP *ld, LDAPConn *lc ) 1236{ return LDAP_SUCCESS; } 1237 1238int 1239ldap_int_sasl_bind( 1240 LDAP *ld, 1241 const char *dn, 1242 const char *mechs, 1243 LDAPControl **sctrls, 1244 LDAPControl **cctrls, 1245 unsigned flags, 1246 LDAP_SASL_INTERACT_PROC *interact, 1247 void * defaults ) 1248{ return LDAP_NOT_SUPPORTED; } 1249 1250int 1251ldap_int_sasl_external( 1252 LDAP *ld, 1253 LDAPConn *conn, 1254 const char * authid, 1255 ber_len_t ssf ) 1256{ return LDAP_SUCCESS; } 1257 1258#endif /* HAVE_CYRUS_SASL */ 1259