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