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