1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #ifdef LDAP_SASLIO_HOOKS 29 #include <assert.h> 30 #include "ldap-int.h" 31 #include "../ber/lber-int.h" 32 #include <sasl/sasl.h> 33 #include <thread.h> 34 #include <synch.h> 35 36 #define SEARCH_TIMEOUT_SECS 120 37 #define NSLDAPI_SM_BUF 128 38 39 extern void *sasl_create_context(void); 40 extern void sasl_free_context(void *ctx); 41 extern int _sasl_client_init(void *ctx, const sasl_callback_t *callbacks); 42 extern int _sasl_client_new(void *ctx, const char *service, 43 const char *serverFQDN, const char *iplocalport, 44 const char *ipremoteport, 45 const sasl_callback_t *prompt_supp, 46 unsigned flags, sasl_conn_t **pconn); 47 extern int _sasl_server_init(void *ctx, 48 const sasl_callback_t *callbacks, const char *appname); 49 extern int _sasl_server_new(void *ctx, const char *service, 50 const char *serverFQDN, const char *user_realm, 51 const char *iplocalport, const char *ipremoteport, 52 const sasl_callback_t *callbacks, 53 unsigned flags, sasl_conn_t **pconn); 54 55 static int nsldapi_sasl_close( LDAP *ld, Sockbuf *sb ); 56 57 /* 58 * SASL Dependent routines 59 * 60 * SASL security and integrity options are supported through the 61 * use of the extended I/O functionality. Because the extended 62 * I/O functions may already be in use prior to enabling encryption, 63 * when SASL encryption is enabled, these routine interpose themselves 64 * over the existng extended I/O routines and add an additional level 65 * of indirection. 66 * IE: Before SASL: client->libldap->lber->extio 67 * After SASL: client->libldap->lber->saslio->extio 68 * Any extio functions are still used for the raw i/O [IE prldap] 69 * but SASL will decrypt before passing to lber. 70 * SASL cannot decrypt a stream so full packets must be read 71 * before proceeding. 72 */ 73 74 static int nsldapi_sasl_fail() 75 { 76 return( SASL_FAIL ); 77 } 78 79 /* 80 * Global SASL Init data 81 */ 82 83 static sasl_callback_t client_callbacks[] = { 84 { SASL_CB_GETOPT, nsldapi_sasl_fail, NULL }, 85 { SASL_CB_GETREALM, NULL, NULL }, 86 { SASL_CB_USER, NULL, NULL }, 87 { SASL_CB_AUTHNAME, NULL, NULL }, 88 { SASL_CB_PASS, NULL, NULL }, 89 { SASL_CB_ECHOPROMPT, NULL, NULL }, 90 { SASL_CB_NOECHOPROMPT, NULL, NULL }, 91 { SASL_CB_LIST_END, NULL, NULL } 92 }; 93 static mutex_t sasl_mutex = DEFAULTMUTEX; 94 static int nsldapi_sasl_inited = 0; 95 static void *gctx; /* intentially not freed - avoid libsasl re-inits */ 96 97 int nsldapi_sasl_init( void ) 98 { 99 int saslrc; 100 101 mutex_lock(&sasl_mutex); 102 if ( nsldapi_sasl_inited ) { 103 mutex_unlock(&sasl_mutex); 104 return( 0 ); 105 } 106 if ((gctx = (void *)sasl_create_context()) != NULL) { 107 saslrc = _sasl_client_init(gctx, client_callbacks); 108 if (saslrc == SASL_OK ) { 109 nsldapi_sasl_inited = 1; 110 mutex_unlock(&sasl_mutex); 111 return( 0 ); 112 } 113 } 114 mutex_unlock(&sasl_mutex); 115 return( -1 ); 116 } 117 118 /* 119 * SASL encryption routines 120 */ 121 122 /* 123 * Get the 4 octet header [size] for a sasl encrypted buffer. 124 * See RFC222 [section 3]. 125 */ 126 127 static int 128 nsldapi_sasl_pktlen( char *buf, int maxbufsize ) 129 { 130 int size; 131 132 #if defined( _WINDOWS ) || defined( _WIN32 ) 133 size = ntohl(*(long *)buf); 134 #else 135 size = ntohl(*(uint32_t *)buf); 136 #endif 137 138 if ( size < 0 || size > maxbufsize ) { 139 return (-1 ); 140 } 141 142 return( size + 4 ); /* include the first 4 bytes */ 143 } 144 145 static int 146 nsldapi_sasl_read( int s, void *buf, int len, 147 struct lextiof_socket_private *arg) 148 { 149 Sockbuf *sb = (Sockbuf *)arg; 150 LDAP *ld; 151 const char *dbuf; 152 char *cp; 153 int ret; 154 unsigned dlen, blen; 155 156 if (sb == NULL) { 157 return( -1 ); 158 } 159 160 ld = (LDAP *)sb->sb_sasl_prld; 161 if (ld == NULL) { 162 return( -1 ); 163 } 164 165 /* Is there anything left in the existing buffer? */ 166 if ((ret = sb->sb_sasl_ilen) > 0) { 167 ret = (ret > len ? len : ret); 168 SAFEMEMCPY( buf, sb->sb_sasl_iptr, ret ); 169 if (ret == sb->sb_sasl_ilen) { 170 sb->sb_sasl_ilen = 0; 171 sb->sb_sasl_iptr = NULL; 172 } else { 173 sb->sb_sasl_ilen -= ret; 174 sb->sb_sasl_iptr += ret; 175 } 176 return( ret ); 177 } 178 179 /* buffer is empty - fill it */ 180 cp = sb->sb_sasl_ibuf; 181 dlen = 0; 182 183 /* Read the length of the packet */ 184 while ( dlen < 4 ) { 185 if (sb->sb_sasl_fns.lbextiofn_read != NULL) { 186 ret = sb->sb_sasl_fns.lbextiofn_read( 187 s, cp, 4 - dlen, 188 sb->sb_sasl_fns.lbextiofn_socket_arg); 189 } else { 190 ret = read( sb->sb_sd, cp, 4 - dlen ); 191 } 192 #ifdef EINTR 193 if ( ( ret < 0 ) && ( LDAP_GET_ERRNO(ld) == EINTR ) ) 194 continue; 195 #endif 196 if ( ret <= 0 ) 197 return( ret ); 198 199 cp += ret; 200 dlen += ret; 201 } 202 203 blen = 4; 204 205 ret = nsldapi_sasl_pktlen( sb->sb_sasl_ibuf, sb->sb_sasl_bfsz ); 206 if (ret < 0) { 207 LDAP_SET_ERRNO(ld, EIO); 208 return( -1 ); 209 } 210 dlen = ret - dlen; 211 212 /* read the rest of the encrypted packet */ 213 while ( dlen > 0 ) { 214 if (sb->sb_sasl_fns.lbextiofn_read != NULL) { 215 ret = sb->sb_sasl_fns.lbextiofn_read( 216 s, cp, dlen, 217 sb->sb_sasl_fns.lbextiofn_socket_arg); 218 } else { 219 ret = read( sb->sb_sd, cp, dlen ); 220 } 221 222 #ifdef EINTR 223 if ( ( ret < 0 ) && ( LDAP_GET_ERRNO(ld) == EINTR ) ) 224 continue; 225 #endif 226 if ( ret <= 0 ) 227 return( ret ); 228 229 cp += ret; 230 blen += ret; 231 dlen -= ret; 232 } 233 234 /* Decode the packet */ 235 ret = sasl_decode( sb->sb_sasl_ctx, 236 sb->sb_sasl_ibuf, blen, 237 &dbuf, &dlen); 238 if ( ret != SASL_OK ) { 239 /* sb_sasl_read: failed to decode packet, drop it, error */ 240 sb->sb_sasl_iptr = NULL; 241 sb->sb_sasl_ilen = 0; 242 LDAP_SET_ERRNO(ld, EIO); 243 return( -1 ); 244 } 245 246 /* copy decrypted packet to the input buffer */ 247 SAFEMEMCPY( sb->sb_sasl_ibuf, dbuf, dlen ); 248 sb->sb_sasl_iptr = sb->sb_sasl_ibuf; 249 sb->sb_sasl_ilen = dlen; 250 251 ret = (dlen > (unsigned) len ? len : dlen); 252 SAFEMEMCPY( buf, sb->sb_sasl_iptr, ret ); 253 if (ret == sb->sb_sasl_ilen) { 254 sb->sb_sasl_ilen = 0; 255 sb->sb_sasl_iptr = NULL; 256 } else { 257 sb->sb_sasl_ilen -= ret; 258 sb->sb_sasl_iptr += ret; 259 } 260 return( ret ); 261 } 262 263 static int 264 nsldapi_sasl_write( int s, const void *buf, int len, 265 struct lextiof_socket_private *arg) 266 { 267 Sockbuf *sb = (Sockbuf *)arg; 268 int ret; 269 const char *obuf, *optr; 270 unsigned olen; 271 272 if (sb == NULL) { 273 return( -1 ); 274 } 275 276 /* encode the next packet. */ 277 ret = sasl_encode( sb->sb_sasl_ctx, buf, (unsigned)len, &obuf, &olen); 278 if ( ret != SASL_OK ) { 279 /* XXX Log error? "sb_sasl_write: failed to encode packet..." */ 280 return( -1 ); 281 } 282 283 /* Write everything now, buffer is only good until next sasl_encode */ 284 optr = obuf; 285 while (olen > 0) { 286 if (sb->sb_sasl_fns.lbextiofn_write != NULL) { 287 ret = sb->sb_sasl_fns.lbextiofn_write( 288 s, optr, olen, 289 sb->sb_sasl_fns.lbextiofn_socket_arg); 290 } else { 291 ret = write( sb->sb_sd, optr, olen); 292 } 293 if ( ret < 0 ) 294 return( ret ); 295 optr += ret; 296 olen -= ret; 297 } 298 return( len ); 299 } 300 301 static int 302 nsldapi_sasl_poll( 303 LDAP_X_PollFD fds[], int nfds, int timeout, 304 struct lextiof_session_private *arg ) 305 { 306 Sockbuf *sb = (Sockbuf *)arg; 307 LDAP *ld; 308 int i; 309 310 if (sb == NULL) { 311 return( -1 ); 312 } 313 ld = (LDAP *)sb->sb_sasl_prld; 314 if (ld == NULL) { 315 return( -1 ); 316 } 317 318 if (fds && nfds > 0) { 319 for(i = 0; i < nfds; i++) { 320 if (fds[i].lpoll_socketarg == 321 (struct lextiof_socket_private *)sb) { 322 fds[i].lpoll_socketarg = 323 (struct lextiof_socket_private *) 324 sb->sb_sasl_fns.lbextiofn_socket_arg; 325 } 326 327 } 328 } 329 return ( ld->ld_sasl_io_fns.lextiof_poll( fds, nfds, timeout, 330 (void *)ld->ld_sasl_io_fns.lextiof_session_arg) ); 331 } 332 333 /* no encryption indirect routines */ 334 335 static int 336 nsldapi_sasl_ne_read( int s, void *buf, int len, 337 struct lextiof_socket_private *arg) 338 { 339 Sockbuf *sb = (Sockbuf *)arg; 340 341 if (sb == NULL) { 342 return( -1 ); 343 } 344 345 return( sb->sb_sasl_fns.lbextiofn_read( s, buf, len, 346 sb->sb_sasl_fns.lbextiofn_socket_arg) ); 347 } 348 349 static int 350 nsldapi_sasl_ne_write( int s, const void *buf, int len, 351 struct lextiof_socket_private *arg) 352 { 353 Sockbuf *sb = (Sockbuf *)arg; 354 355 if (sb == NULL) { 356 return( -1 ); 357 } 358 359 return( sb->sb_sasl_fns.lbextiofn_write( s, buf, len, 360 sb->sb_sasl_fns.lbextiofn_socket_arg) ); 361 } 362 363 static int 364 nsldapi_sasl_close_socket(int s, struct lextiof_socket_private *arg ) 365 { 366 Sockbuf *sb = (Sockbuf *)arg; 367 LDAP *ld; 368 369 if (sb == NULL) { 370 return( -1 ); 371 } 372 ld = (LDAP *)sb->sb_sasl_prld; 373 if (ld == NULL) { 374 return( -1 ); 375 } 376 /* undo function pointer interposing */ 377 ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, &ld->ld_sasl_io_fns ); 378 ber_sockbuf_set_option( sb, 379 LBER_SOCKBUF_OPT_EXT_IO_FNS, 380 (void *)&sb->sb_sasl_fns); 381 382 /* undo SASL */ 383 nsldapi_sasl_close( ld, sb ); 384 385 return ( ld->ld_sasl_io_fns.lextiof_close( s, 386 (struct lextiof_socket_private *) 387 sb->sb_sasl_fns.lbextiofn_socket_arg ) ); 388 } 389 390 /* 391 * install encryption routines if security has been negotiated 392 */ 393 static int 394 nsldapi_sasl_install( LDAP *ld, Sockbuf *sb, void *ctx_arg, sasl_ssf_t *ssf) 395 { 396 struct lber_x_ext_io_fns fns; 397 struct ldap_x_ext_io_fns iofns; 398 sasl_security_properties_t *secprops; 399 int rc, value; 400 int bufsiz; 401 int encrypt = 0; 402 403 if (ssf && *ssf) { 404 encrypt = 1; 405 } 406 rc = ber_sockbuf_get_option( sb, 407 LBER_SOCKBUF_OPT_TO_FILE_ONLY, 408 (void *) &value); 409 if (rc != 0 || value != 0) 410 return( LDAP_LOCAL_ERROR ); 411 412 if (encrypt) { 413 /* initialize input buffer - use MAX SIZE to avoid reallocs */ 414 sb->sb_sasl_ctx = (sasl_conn_t *)ctx_arg; 415 rc = sasl_getprop( sb->sb_sasl_ctx, SASL_SEC_PROPS, 416 (const void **)&secprops ); 417 if (rc != SASL_OK) 418 return( LDAP_LOCAL_ERROR ); 419 bufsiz = secprops->maxbufsize; 420 if (bufsiz <= 0) { 421 return( LDAP_LOCAL_ERROR ); 422 } 423 if ((sb->sb_sasl_ibuf = NSLDAPI_MALLOC(bufsiz)) == NULL) { 424 return( LDAP_LOCAL_ERROR ); 425 } 426 sb->sb_sasl_iptr = NULL; 427 sb->sb_sasl_bfsz = bufsiz; 428 sb->sb_sasl_ilen = 0; 429 } 430 431 /* Reset Session then Socket Args */ 432 /* Get old values */ 433 (void) memset( &sb->sb_sasl_fns, 0, LBER_X_EXTIO_FNS_SIZE); 434 sb->sb_sasl_fns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE; 435 rc = ber_sockbuf_get_option( sb, 436 LBER_SOCKBUF_OPT_EXT_IO_FNS, 437 (void *)&sb->sb_sasl_fns); 438 memset( &ld->ld_sasl_io_fns, 0, sizeof(iofns)); 439 ld->ld_sasl_io_fns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE; 440 rc = ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, 441 &ld->ld_sasl_io_fns ); 442 if (rc != 0 ) 443 return( LDAP_LOCAL_ERROR ); 444 445 /* Set new values */ 446 if ( ld->ld_sasl_io_fns.lextiof_read != NULL || 447 ld->ld_sasl_io_fns.lextiof_write != NULL || 448 ld->ld_sasl_io_fns.lextiof_poll != NULL || 449 ld->ld_sasl_io_fns.lextiof_connect != NULL || 450 ld->ld_sasl_io_fns.lextiof_close != NULL ) { 451 memset( &iofns, 0, sizeof(iofns)); 452 iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE; 453 if (encrypt) { 454 iofns.lextiof_read = nsldapi_sasl_read; 455 iofns.lextiof_write = nsldapi_sasl_write; 456 iofns.lextiof_poll = nsldapi_sasl_poll; 457 } else { 458 iofns.lextiof_read = nsldapi_sasl_ne_read; 459 iofns.lextiof_write = nsldapi_sasl_ne_write; 460 iofns.lextiof_poll = nsldapi_sasl_poll; 461 } 462 iofns.lextiof_connect = ld->ld_sasl_io_fns.lextiof_connect; 463 iofns.lextiof_close = nsldapi_sasl_close_socket; 464 iofns.lextiof_newhandle = ld->ld_sasl_io_fns.lextiof_newhandle; 465 iofns.lextiof_disposehandle = 466 ld->ld_sasl_io_fns.lextiof_disposehandle; 467 iofns.lextiof_session_arg = 468 (void *) sb; 469 /* ld->ld_sasl_io_fns.lextiof_session_arg; */ 470 rc = ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, 471 &iofns ); 472 if (rc != 0 ) 473 return( LDAP_LOCAL_ERROR ); 474 sb->sb_sasl_prld = (void *)ld; 475 } 476 477 if (encrypt) { 478 (void) memset( &fns, 0, LBER_X_EXTIO_FNS_SIZE); 479 fns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE; 480 fns.lbextiofn_read = nsldapi_sasl_read; 481 fns.lbextiofn_write = nsldapi_sasl_write; 482 fns.lbextiofn_socket_arg = 483 (void *) sb; 484 /* (void *)sb->sb_sasl_fns.lbextiofn_socket_arg; */ 485 rc = ber_sockbuf_set_option( sb, 486 LBER_SOCKBUF_OPT_EXT_IO_FNS, 487 (void *)&fns); 488 if (rc != 0) 489 return( LDAP_LOCAL_ERROR ); 490 } 491 492 return( LDAP_SUCCESS ); 493 } 494 495 static int 496 nsldapi_sasl_cvterrno( LDAP *ld, int err ) 497 { 498 int rc = LDAP_LOCAL_ERROR; 499 500 switch (err) { 501 case SASL_OK: 502 rc = LDAP_SUCCESS; 503 break; 504 case SASL_NOMECH: 505 rc = LDAP_AUTH_UNKNOWN; 506 break; 507 case SASL_BADSERV: 508 rc = LDAP_CONNECT_ERROR; 509 break; 510 case SASL_DISABLED: 511 case SASL_ENCRYPT: 512 case SASL_EXPIRED: 513 case SASL_NOUSERPASS: 514 case SASL_NOVERIFY: 515 case SASL_PWLOCK: 516 case SASL_TOOWEAK: 517 case SASL_UNAVAIL: 518 case SASL_WEAKPASS: 519 rc = LDAP_INAPPROPRIATE_AUTH; 520 break; 521 case SASL_BADAUTH: 522 case SASL_NOAUTHZ: 523 rc = LDAP_INVALID_CREDENTIALS; 524 break; 525 case SASL_NOMEM: 526 rc = LDAP_NO_MEMORY; 527 break; 528 case SASL_NOUSER: 529 rc = LDAP_NO_SUCH_OBJECT; 530 break; 531 case SASL_CONTINUE: 532 case SASL_FAIL: 533 case SASL_INTERACT: 534 default: 535 rc = LDAP_LOCAL_ERROR; 536 break; 537 } 538 539 LDAP_SET_LDERRNO( ld, rc, NULL, NULL ); 540 return( rc ); 541 } 542 543 int 544 nsldapi_sasl_open(LDAP *ld) 545 { 546 Sockbuf *sb; 547 char * host; 548 int saslrc; 549 sasl_conn_t *ctx; 550 551 if (ld == NULL) { 552 return( LDAP_LOCAL_ERROR ); 553 } 554 555 if (ld->ld_defconn == NULL) { 556 LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, NULL ); 557 return( LDAP_LOCAL_ERROR ); 558 } 559 sb = ld->ld_defconn->lconn_sb; 560 host = ld->ld_defhost; 561 562 if ( sb == NULL || host == NULL ) { 563 LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, NULL ); 564 return( LDAP_LOCAL_ERROR ); 565 } 566 567 /* SASL is not properly initialized */ 568 mutex_lock(&sasl_mutex); 569 if (gctx == NULL) { 570 LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, NULL ); 571 mutex_unlock(&sasl_mutex); 572 return( LDAP_LOCAL_ERROR ); 573 } 574 575 saslrc = _sasl_client_new(gctx, "ldap", host, 576 NULL, NULL, /* iplocal ipremote strings currently unused */ 577 NULL, 0, &ctx ); 578 579 if ( saslrc != SASL_OK ) { 580 mutex_unlock(&sasl_mutex); 581 return( nsldapi_sasl_cvterrno( ld, saslrc ) ); 582 } 583 584 sb->sb_sasl_ctx = (void *)ctx; 585 mutex_unlock(&sasl_mutex); 586 587 return( LDAP_SUCCESS ); 588 } 589 590 static int 591 nsldapi_sasl_close( LDAP *ld, Sockbuf *sb ) 592 { 593 sasl_conn_t *ctx = (sasl_conn_t *)sb->sb_sasl_ctx; 594 595 if( ctx != NULL ) { 596 sasl_dispose( &ctx ); 597 sb->sb_sasl_ctx = NULL; 598 } 599 return( LDAP_SUCCESS ); 600 } 601 602 static int 603 nsldapi_sasl_do_bind( LDAP *ld, const char *dn, 604 const char *mechs, unsigned flags, 605 LDAP_SASL_INTERACT_PROC *callback, void *defaults, 606 LDAPControl **sctrl, LDAPControl **cctrl ) 607 { 608 sasl_interact_t *prompts = NULL; 609 sasl_conn_t *ctx; 610 sasl_ssf_t *ssf = NULL; 611 const char *mech = NULL; 612 int saslrc, rc; 613 struct berval ccred; 614 unsigned credlen; 615 616 if (NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3) { 617 LDAP_SET_LDERRNO( ld, LDAP_NOT_SUPPORTED, NULL, NULL ); 618 return( LDAP_NOT_SUPPORTED ); 619 } 620 621 /* shouldn't happen */ 622 if (callback == NULL) { 623 return( LDAP_LOCAL_ERROR ); 624 } 625 626 if ( ld->ld_defconn == NULL || 627 ld->ld_defconn->lconn_status != LDAP_CONNST_CONNECTED) { 628 rc = nsldapi_open_ldap_defconn( ld ); 629 if( rc < 0 ) { 630 return( LDAP_GET_LDERRNO( ld, NULL, NULL ) ); 631 } 632 } 633 634 /* should have a valid ld connection - now create sasl connection */ 635 if ((rc = nsldapi_sasl_open(ld)) != LDAP_SUCCESS) { 636 LDAP_SET_LDERRNO( ld, rc, NULL, NULL ); 637 return( rc ); 638 } 639 640 /* expect context to be initialized when connection is open */ 641 ctx = (sasl_conn_t *)ld->ld_defconn->lconn_sb->sb_sasl_ctx; 642 643 if( ctx == NULL ) { 644 LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, NULL ); 645 return( LDAP_LOCAL_ERROR ); 646 } 647 648 /* (re)set security properties */ 649 sasl_setprop( ctx, SASL_SEC_PROPS, &ld->ld_sasl_secprops ); 650 651 ccred.bv_val = NULL; 652 ccred.bv_len = 0; 653 654 do { 655 saslrc = sasl_client_start( ctx, 656 mechs, 657 &prompts, 658 (const char **)&ccred.bv_val, 659 &credlen, 660 &mech ); 661 662 LDAPDebug(LDAP_DEBUG_TRACE, "Starting SASL/%s authentication\n", 663 (mech ? mech : ""), 0, 0 ); 664 665 if( saslrc == SASL_INTERACT && 666 (callback)(ld, flags, defaults, prompts) != LDAP_SUCCESS ) { 667 break; 668 } 669 } while ( saslrc == SASL_INTERACT ); 670 671 ccred.bv_len = credlen; 672 673 if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) { 674 return( nsldapi_sasl_cvterrno( ld, saslrc ) ); 675 } 676 677 do { 678 struct berval *scred; 679 680 scred = NULL; 681 682 /* notify server of a sasl bind step */ 683 rc = ldap_sasl_bind_s(ld, dn, mech, &ccred, 684 sctrl, cctrl, &scred); 685 686 if ( ccred.bv_val != NULL ) { 687 ccred.bv_val = NULL; 688 } 689 690 if ( rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS ) { 691 if( scred && scred->bv_len ) { 692 /* and server provided us with data? */ 693 ber_bvfree( scred ); 694 } 695 return( rc ); 696 } 697 698 if( rc == LDAP_SUCCESS && saslrc == SASL_OK ) { 699 /* we're done, no need to step */ 700 if( scred && scred->bv_len ) { 701 /* but server provided us with data! */ 702 ber_bvfree( scred ); 703 LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, 704 NULL, NULL ); 705 return( LDAP_LOCAL_ERROR ); 706 } 707 break; 708 } 709 710 /* perform the next step of the sasl bind */ 711 do { 712 saslrc = sasl_client_step( ctx, 713 (scred == NULL) ? NULL : scred->bv_val, 714 (scred == NULL) ? 0 : scred->bv_len, 715 &prompts, 716 (const char **)&ccred.bv_val, 717 &credlen ); 718 719 if( saslrc == SASL_INTERACT && 720 (callback)(ld, flags, defaults, prompts) 721 != LDAP_SUCCESS ) { 722 break; 723 } 724 } while ( saslrc == SASL_INTERACT ); 725 726 ccred.bv_len = credlen; 727 ber_bvfree( scred ); 728 729 if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) { 730 return( nsldapi_sasl_cvterrno( ld, saslrc ) ); 731 } 732 } while ( rc == LDAP_SASL_BIND_IN_PROGRESS ); 733 734 if ( rc != LDAP_SUCCESS ) { 735 return( rc ); 736 } 737 738 if ( saslrc != SASL_OK ) { 739 return( nsldapi_sasl_cvterrno( ld, saslrc ) ); 740 } 741 742 saslrc = sasl_getprop( ctx, SASL_SSF, (const void **) &ssf ); 743 if( saslrc == SASL_OK ) { 744 rc = nsldapi_sasl_install(ld, ld->ld_conns->lconn_sb, ctx, ssf); 745 } 746 747 return( rc ); 748 } 749 750 #ifdef LDAP_SASLIO_GET_MECHS_FROM_SERVER 751 /* 752 * Get available SASL Mechanisms supported by the server 753 */ 754 755 static int 756 nsldapi_get_sasl_mechs ( LDAP *ld, char **pmech ) 757 { 758 char *attr[] = { "supportedSASLMechanisms", NULL }; 759 char **values, **v, *mech, *m; 760 LDAPMessage *res, *e; 761 struct timeval timeout; 762 int slen, rc; 763 764 if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) { 765 return( LDAP_PARAM_ERROR ); 766 } 767 768 timeout.tv_sec = SEARCH_TIMEOUT_SECS; 769 timeout.tv_usec = 0; 770 771 rc = ldap_search_st( ld, "", LDAP_SCOPE_BASE, 772 "objectclass=*", attr, 0, &timeout, &res ); 773 774 if ( rc != LDAP_SUCCESS ) { 775 return( LDAP_GET_LDERRNO( ld, NULL, NULL ) ); 776 } 777 778 e = ldap_first_entry( ld, res ); 779 if ( e == NULL ) { 780 ldap_msgfree( res ); 781 if ( ld->ld_errno == LDAP_SUCCESS ) { 782 LDAP_SET_LDERRNO( ld, LDAP_NO_SUCH_OBJECT, NULL, NULL ); 783 } 784 return( LDAP_GET_LDERRNO( ld, NULL, NULL ) ); 785 } 786 787 values = ldap_get_values( ld, e, "supportedSASLMechanisms" ); 788 if ( values == NULL ) { 789 ldap_msgfree( res ); 790 LDAP_SET_LDERRNO( ld, LDAP_NO_SUCH_ATTRIBUTE, NULL, NULL ); 791 return( LDAP_NO_SUCH_ATTRIBUTE ); 792 } 793 794 slen = 0; 795 for(v = values; *v != NULL; v++ ) { 796 slen += strlen(*v) + 1; 797 } 798 if ( (mech = NSLDAPI_CALLOC(1, slen)) == NULL) { 799 ldap_value_free( values ); 800 ldap_msgfree( res ); 801 LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL ); 802 return( LDAP_NO_MEMORY ); 803 } 804 m = mech; 805 for(v = values; *v; v++) { 806 if (v != values) { 807 *m++ = ' '; 808 } 809 slen = strlen(*v); 810 strncpy(m, *v, slen); 811 m += slen; 812 } 813 *m = '\0'; 814 815 ldap_value_free( values ); 816 ldap_msgfree( res ); 817 818 *pmech = mech; 819 820 return( LDAP_SUCCESS ); 821 } 822 #endif 823 824 int nsldapi_sasl_secprops( 825 const char *in, 826 sasl_security_properties_t *secprops ) 827 { 828 int i; 829 char **props = NULL; 830 char *inp; 831 unsigned sflags = 0; 832 sasl_ssf_t max_ssf = 0; 833 sasl_ssf_t min_ssf = 0; 834 unsigned maxbufsize = 0; 835 int got_sflags = 0; 836 int got_max_ssf = 0; 837 int got_min_ssf = 0; 838 int got_maxbufsize = 0; 839 840 if (in == NULL) { 841 return LDAP_PARAM_ERROR; 842 } 843 inp = nsldapi_strdup(in); 844 if (inp == NULL) { 845 return LDAP_PARAM_ERROR; 846 } 847 props = ldap_str2charray( inp, "," ); 848 NSLDAPI_FREE( inp ); 849 850 if( props == NULL || secprops == NULL ) { 851 return LDAP_PARAM_ERROR; 852 } 853 854 for( i=0; props[i]; i++ ) { 855 if( strcasecmp(props[i], "none") == 0 ) { 856 got_sflags++; 857 858 } else if( strcasecmp(props[i], "noactive") == 0 ) { 859 got_sflags++; 860 sflags |= SASL_SEC_NOACTIVE; 861 862 } else if( strcasecmp(props[i], "noanonymous") == 0 ) { 863 got_sflags++; 864 sflags |= SASL_SEC_NOANONYMOUS; 865 866 } else if( strcasecmp(props[i], "nodict") == 0 ) { 867 got_sflags++; 868 sflags |= SASL_SEC_NODICTIONARY; 869 870 } else if( strcasecmp(props[i], "noplain") == 0 ) { 871 got_sflags++; 872 sflags |= SASL_SEC_NOPLAINTEXT; 873 874 } else if( strcasecmp(props[i], "forwardsec") == 0 ) { 875 got_sflags++; 876 sflags |= SASL_SEC_FORWARD_SECRECY; 877 878 } else if( strcasecmp(props[i], "passcred") == 0 ) { 879 got_sflags++; 880 sflags |= SASL_SEC_PASS_CREDENTIALS; 881 882 } else if( strncasecmp(props[i], 883 "minssf=", sizeof("minssf")) == 0 ) { 884 if( isdigit( props[i][sizeof("minssf")] ) ) { 885 got_min_ssf++; 886 min_ssf = atoi( &props[i][sizeof("minssf")] ); 887 } else { 888 return LDAP_NOT_SUPPORTED; 889 } 890 891 } else if( strncasecmp(props[i], 892 "maxssf=", sizeof("maxssf")) == 0 ) { 893 if( isdigit( props[i][sizeof("maxssf")] ) ) { 894 got_max_ssf++; 895 max_ssf = atoi( &props[i][sizeof("maxssf")] ); 896 } else { 897 return LDAP_NOT_SUPPORTED; 898 } 899 900 } else if( strncasecmp(props[i], 901 "maxbufsize=", sizeof("maxbufsize")) == 0 ) { 902 if( isdigit( props[i][sizeof("maxbufsize")] ) ) { 903 got_maxbufsize++; 904 maxbufsize = atoi( &props[i][sizeof("maxbufsize")] ); 905 if( maxbufsize && 906 (( maxbufsize < SASL_MIN_BUFF_SIZE ) 907 || (maxbufsize > SASL_MAX_BUFF_SIZE ))) { 908 return( LDAP_PARAM_ERROR ); 909 } 910 } else { 911 return( LDAP_NOT_SUPPORTED ); 912 } 913 } else { 914 return( LDAP_NOT_SUPPORTED ); 915 } 916 } 917 918 if(got_sflags) { 919 secprops->security_flags = sflags; 920 } 921 if(got_min_ssf) { 922 secprops->min_ssf = min_ssf; 923 } 924 if(got_max_ssf) { 925 secprops->max_ssf = max_ssf; 926 } 927 if(got_maxbufsize) { 928 secprops->maxbufsize = maxbufsize; 929 } 930 931 ldap_charray_free( props ); 932 return( LDAP_SUCCESS ); 933 } 934 935 /* 936 * SASL Authentication Interface: ldap_sasl_interactive_bind_s 937 * 938 * This routine takes a DN, SASL mech list, and a SASL callback 939 * and performs the necessary sequencing to complete a SASL bind 940 * to the LDAP connection ld. The user provided callback can 941 * use an optionally provided set of default values to complete 942 * any necessary interactions. 943 * 944 * Currently inpose the following restrictions: 945 * A mech list must be provided, only LDAP_SASL_INTERACTIVE 946 * mode is supported 947 */ 948 int 949 LDAP_CALL 950 ldap_sasl_interactive_bind_s( LDAP *ld, const char *dn, 951 const char *saslMechanism, 952 LDAPControl **sctrl, LDAPControl **cctrl, unsigned flags, 953 LDAP_SASL_INTERACT_PROC *callback, void *defaults ) 954 { 955 #ifdef LDAP_SASLIO_GET_MECHS_FROM_SERVER 956 char *smechs; 957 #endif 958 int rc; 959 960 LDAPDebug(LDAP_DEBUG_TRACE, "ldap_sasl_interactive_bind_s\n", 0, 0, 0); 961 962 if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) { 963 return( LDAP_PARAM_ERROR ); 964 } 965 966 if (flags != LDAP_SASL_INTERACTIVE || callback == NULL) { 967 return( LDAP_PARAM_ERROR ); 968 } 969 970 LDAP_MUTEX_LOCK(ld, LDAP_SASL_LOCK ); 971 972 if( saslMechanism == NULL || *saslMechanism == '\0' ) { 973 #ifdef LDAP_SASLIO_GET_MECHS_FROM_SERVER 974 rc = nsldapi_get_sasl_mechs( ld, &smechs ); 975 if( rc != LDAP_SUCCESS ) { 976 LDAP_MUTEX_UNLOCK(ld, LDAP_SASL_LOCK ); 977 return( rc ); 978 } 979 saslMechanism = smechs; 980 #else 981 LDAP_MUTEX_UNLOCK(ld, LDAP_SASL_LOCK ); 982 return( LDAP_PARAM_ERROR ); 983 #endif 984 } 985 986 /* initialize SASL library */ 987 if ( nsldapi_sasl_init() < 0 ) { 988 return( LDAP_PARAM_ERROR ); 989 } 990 991 rc = nsldapi_sasl_do_bind( ld, dn, saslMechanism, 992 flags, callback, defaults, sctrl, cctrl); 993 994 LDAP_MUTEX_UNLOCK(ld, LDAP_SASL_LOCK ); 995 return( rc ); 996 } 997 998 #endif 999