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