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