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