1 /* $NetBSD: cyrus.c,v 1.1.1.2 2010/03/08 02:14:20 lukem Exp $ */ 2 3 /* OpenLDAP: pkg/ldap/libraries/libldap/cyrus.c,v 1.133.2.15 2009/08/25 23:04:13 quanah Exp */ 4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1998-2009 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 47 ldap_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 66 static 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 78 int 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 138 static void 139 sb_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 156 static ber_int_t 157 sb_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 184 static ber_int_t 185 sb_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 213 static void 214 sb_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 225 static void 226 sb_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 239 static 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 247 int 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 257 void ldap_pvt_sasl_remove( Sockbuf *sb ) 258 { 259 ldap_pvt_sasl_generic_remove( sb ); 260 } 261 262 static int 263 sasl_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 322 int 323 ldap_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 364 int 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 382 int 383 ldap_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 709 done: 710 return rc; 711 } 712 713 int 714 ldap_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 759 static 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 778 void 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 854 int 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 931 int 932 ldap_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 945 int 946 ldap_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 default: 1048 return -1; 1049 } 1050 return 0; 1051 } 1052 1053 int 1054 ldap_int_sasl_set_option( LDAP *ld, int option, void *arg ) 1055 { 1056 if ( ld == NULL ) 1057 return -1; 1058 1059 if ( arg == NULL && option != LDAP_OPT_X_SASL_NOCANON ) 1060 return -1; 1061 1062 switch ( option ) { 1063 case LDAP_OPT_X_SASL_SSF: 1064 case LDAP_OPT_X_SASL_USERNAME: 1065 /* This option is read-only */ 1066 return -1; 1067 1068 case LDAP_OPT_X_SASL_SSF_EXTERNAL: { 1069 int sc; 1070 #if SASL_VERSION_MAJOR < 2 1071 sasl_external_properties_t extprops; 1072 #else 1073 sasl_ssf_t sasl_ssf; 1074 #endif 1075 sasl_conn_t *ctx; 1076 1077 if( ld->ld_defconn == NULL ) { 1078 return -1; 1079 } 1080 1081 ctx = ld->ld_defconn->lconn_sasl_authctx; 1082 1083 if ( ctx == NULL ) { 1084 return -1; 1085 } 1086 1087 #if SASL_VERSION_MAJOR >= 2 1088 sasl_ssf = * (ber_len_t *)arg; 1089 sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL, &sasl_ssf); 1090 #else 1091 memset(&extprops, 0L, sizeof(extprops)); 1092 1093 extprops.ssf = * (ber_len_t *) arg; 1094 1095 sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL, 1096 (void *) &extprops ); 1097 #endif 1098 1099 if ( sc != SASL_OK ) { 1100 return -1; 1101 } 1102 } break; 1103 1104 case LDAP_OPT_X_SASL_SSF_MIN: 1105 ld->ld_options.ldo_sasl_secprops.min_ssf = *(ber_len_t *)arg; 1106 break; 1107 case LDAP_OPT_X_SASL_SSF_MAX: 1108 ld->ld_options.ldo_sasl_secprops.max_ssf = *(ber_len_t *)arg; 1109 break; 1110 case LDAP_OPT_X_SASL_MAXBUFSIZE: 1111 ld->ld_options.ldo_sasl_secprops.maxbufsize = *(ber_len_t *)arg; 1112 break; 1113 case LDAP_OPT_X_SASL_NOCANON: 1114 if ( arg == LDAP_OPT_OFF ) { 1115 LDAP_BOOL_CLR(&ld->ld_options, LDAP_BOOL_SASL_NOCANON ); 1116 } else { 1117 LDAP_BOOL_SET(&ld->ld_options, LDAP_BOOL_SASL_NOCANON ); 1118 } 1119 break; 1120 1121 case LDAP_OPT_X_SASL_SECPROPS: { 1122 int sc; 1123 sc = ldap_pvt_sasl_secprops( (char *) arg, 1124 &ld->ld_options.ldo_sasl_secprops ); 1125 1126 return sc == LDAP_SUCCESS ? 0 : -1; 1127 } 1128 1129 default: 1130 return -1; 1131 } 1132 return 0; 1133 } 1134 1135 #ifdef LDAP_R_COMPILE 1136 #define LDAP_DEBUG_R_SASL 1137 void *ldap_pvt_sasl_mutex_new(void) 1138 { 1139 ldap_pvt_thread_mutex_t *mutex; 1140 1141 mutex = (ldap_pvt_thread_mutex_t *) LDAP_CALLOC( 1, 1142 sizeof(ldap_pvt_thread_mutex_t) ); 1143 1144 if ( ldap_pvt_thread_mutex_init( mutex ) == 0 ) { 1145 return mutex; 1146 } 1147 #ifndef LDAP_DEBUG_R_SASL 1148 assert( 0 ); 1149 #endif /* !LDAP_DEBUG_R_SASL */ 1150 return NULL; 1151 } 1152 1153 int ldap_pvt_sasl_mutex_lock(void *mutex) 1154 { 1155 #ifdef LDAP_DEBUG_R_SASL 1156 if ( mutex == NULL ) { 1157 return SASL_OK; 1158 } 1159 #else /* !LDAP_DEBUG_R_SASL */ 1160 assert( mutex != NULL ); 1161 #endif /* !LDAP_DEBUG_R_SASL */ 1162 return ldap_pvt_thread_mutex_lock( (ldap_pvt_thread_mutex_t *)mutex ) 1163 ? SASL_FAIL : SASL_OK; 1164 } 1165 1166 int ldap_pvt_sasl_mutex_unlock(void *mutex) 1167 { 1168 #ifdef LDAP_DEBUG_R_SASL 1169 if ( mutex == NULL ) { 1170 return SASL_OK; 1171 } 1172 #else /* !LDAP_DEBUG_R_SASL */ 1173 assert( mutex != NULL ); 1174 #endif /* !LDAP_DEBUG_R_SASL */ 1175 return ldap_pvt_thread_mutex_unlock( (ldap_pvt_thread_mutex_t *)mutex ) 1176 ? SASL_FAIL : SASL_OK; 1177 } 1178 1179 void ldap_pvt_sasl_mutex_dispose(void *mutex) 1180 { 1181 #ifdef LDAP_DEBUG_R_SASL 1182 if ( mutex == NULL ) { 1183 return; 1184 } 1185 #else /* !LDAP_DEBUG_R_SASL */ 1186 assert( mutex != NULL ); 1187 #endif /* !LDAP_DEBUG_R_SASL */ 1188 (void) ldap_pvt_thread_mutex_destroy( (ldap_pvt_thread_mutex_t *)mutex ); 1189 LDAP_FREE( mutex ); 1190 } 1191 #endif 1192 1193 #else 1194 int ldap_int_sasl_init( void ) 1195 { return LDAP_SUCCESS; } 1196 1197 int ldap_int_sasl_close( LDAP *ld, LDAPConn *lc ) 1198 { return LDAP_SUCCESS; } 1199 1200 int 1201 ldap_int_sasl_bind( 1202 LDAP *ld, 1203 const char *dn, 1204 const char *mechs, 1205 LDAPControl **sctrls, 1206 LDAPControl **cctrls, 1207 unsigned flags, 1208 LDAP_SASL_INTERACT_PROC *interact, 1209 void * defaults ) 1210 { return LDAP_NOT_SUPPORTED; } 1211 1212 int 1213 ldap_int_sasl_external( 1214 LDAP *ld, 1215 LDAPConn *conn, 1216 const char * authid, 1217 ber_len_t ssf ) 1218 { return LDAP_SUCCESS; } 1219 1220 #endif /* HAVE_CYRUS_SASL */ 1221