1 /* $NetBSD: sasl.c,v 1.1.1.2 2010/03/08 02:14:20 lukem Exp $ */ 2 3 /* OpenLDAP: pkg/ldap/libraries/libldap/sasl.c,v 1.64.2.7 2009/10/31 00:11:22 quanah Exp */ 4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1998-2009 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 /* 19 * BindRequest ::= SEQUENCE { 20 * version INTEGER, 21 * name DistinguishedName, -- who 22 * authentication CHOICE { 23 * simple [0] OCTET STRING -- passwd 24 * krbv42ldap [1] OCTET STRING -- OBSOLETE 25 * krbv42dsa [2] OCTET STRING -- OBSOLETE 26 * sasl [3] SaslCredentials -- LDAPv3 27 * } 28 * } 29 * 30 * BindResponse ::= SEQUENCE { 31 * COMPONENTS OF LDAPResult, 32 * serverSaslCreds OCTET STRING OPTIONAL -- LDAPv3 33 * } 34 * 35 */ 36 37 #include "portable.h" 38 39 #include <stdio.h> 40 41 #include <ac/socket.h> 42 #include <ac/stdlib.h> 43 #include <ac/string.h> 44 #include <ac/time.h> 45 #include <ac/errno.h> 46 47 #include "ldap-int.h" 48 49 /* 50 * ldap_sasl_bind - bind to the ldap server (and X.500). 51 * The dn (usually NULL), mechanism, and credentials are provided. 52 * The message id of the request initiated is provided upon successful 53 * (LDAP_SUCCESS) return. 54 * 55 * Example: 56 * ldap_sasl_bind( ld, NULL, "mechanism", 57 * cred, NULL, NULL, &msgid ) 58 */ 59 60 int 61 ldap_sasl_bind( 62 LDAP *ld, 63 LDAP_CONST char *dn, 64 LDAP_CONST char *mechanism, 65 struct berval *cred, 66 LDAPControl **sctrls, 67 LDAPControl **cctrls, 68 int *msgidp ) 69 { 70 BerElement *ber; 71 int rc; 72 ber_int_t id; 73 74 Debug( LDAP_DEBUG_TRACE, "ldap_sasl_bind\n", 0, 0, 0 ); 75 76 assert( ld != NULL ); 77 assert( LDAP_VALID( ld ) ); 78 assert( msgidp != NULL ); 79 80 /* check client controls */ 81 rc = ldap_int_client_controls( ld, cctrls ); 82 if( rc != LDAP_SUCCESS ) return rc; 83 84 if( mechanism == LDAP_SASL_SIMPLE ) { 85 if( dn == NULL && cred != NULL && cred->bv_len ) { 86 /* use default binddn */ 87 dn = ld->ld_defbinddn; 88 } 89 90 } else if( ld->ld_version < LDAP_VERSION3 ) { 91 ld->ld_errno = LDAP_NOT_SUPPORTED; 92 return ld->ld_errno; 93 } 94 95 if ( dn == NULL ) { 96 dn = ""; 97 } 98 99 /* create a message to send */ 100 if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { 101 ld->ld_errno = LDAP_NO_MEMORY; 102 return ld->ld_errno; 103 } 104 105 assert( LBER_VALID( ber ) ); 106 107 LDAP_NEXT_MSGID( ld, id ); 108 if( mechanism == LDAP_SASL_SIMPLE ) { 109 /* simple bind */ 110 rc = ber_printf( ber, "{it{istON}" /*}*/, 111 id, LDAP_REQ_BIND, 112 ld->ld_version, dn, LDAP_AUTH_SIMPLE, 113 cred ); 114 115 } else if ( cred == NULL || cred->bv_val == NULL ) { 116 /* SASL bind w/o credentials */ 117 rc = ber_printf( ber, "{it{ist{sN}N}" /*}*/, 118 id, LDAP_REQ_BIND, 119 ld->ld_version, dn, LDAP_AUTH_SASL, 120 mechanism ); 121 122 } else { 123 /* SASL bind w/ credentials */ 124 rc = ber_printf( ber, "{it{ist{sON}N}" /*}*/, 125 id, LDAP_REQ_BIND, 126 ld->ld_version, dn, LDAP_AUTH_SASL, 127 mechanism, cred ); 128 } 129 130 if( rc == -1 ) { 131 ld->ld_errno = LDAP_ENCODING_ERROR; 132 ber_free( ber, 1 ); 133 return( -1 ); 134 } 135 136 /* Put Server Controls */ 137 if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) { 138 ber_free( ber, 1 ); 139 return ld->ld_errno; 140 } 141 142 if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) { 143 ld->ld_errno = LDAP_ENCODING_ERROR; 144 ber_free( ber, 1 ); 145 return ld->ld_errno; 146 } 147 148 149 /* send the message */ 150 *msgidp = ldap_send_initial_request( ld, LDAP_REQ_BIND, dn, ber, id ); 151 152 if(*msgidp < 0) 153 return ld->ld_errno; 154 155 return LDAP_SUCCESS; 156 } 157 158 159 int 160 ldap_sasl_bind_s( 161 LDAP *ld, 162 LDAP_CONST char *dn, 163 LDAP_CONST char *mechanism, 164 struct berval *cred, 165 LDAPControl **sctrls, 166 LDAPControl **cctrls, 167 struct berval **servercredp ) 168 { 169 int rc, msgid; 170 LDAPMessage *result; 171 struct berval *scredp = NULL; 172 173 Debug( LDAP_DEBUG_TRACE, "ldap_sasl_bind_s\n", 0, 0, 0 ); 174 175 /* do a quick !LDAPv3 check... ldap_sasl_bind will do the rest. */ 176 if( servercredp != NULL ) { 177 if (ld->ld_version < LDAP_VERSION3) { 178 ld->ld_errno = LDAP_NOT_SUPPORTED; 179 return ld->ld_errno; 180 } 181 *servercredp = NULL; 182 } 183 184 rc = ldap_sasl_bind( ld, dn, mechanism, cred, sctrls, cctrls, &msgid ); 185 186 if ( rc != LDAP_SUCCESS ) { 187 return( rc ); 188 } 189 190 #ifdef LDAP_CONNECTIONLESS 191 if (LDAP_IS_UDP(ld)) { 192 return( rc ); 193 } 194 #endif 195 196 if ( ldap_result( ld, msgid, LDAP_MSG_ALL, NULL, &result ) == -1 || !result ) { 197 return( ld->ld_errno ); /* ldap_result sets ld_errno */ 198 } 199 200 /* parse the results */ 201 scredp = NULL; 202 if( servercredp != NULL ) { 203 rc = ldap_parse_sasl_bind_result( ld, result, &scredp, 0 ); 204 } 205 206 if ( rc != LDAP_SUCCESS ) { 207 ldap_msgfree( result ); 208 return( rc ); 209 } 210 211 rc = ldap_result2error( ld, result, 1 ); 212 213 if ( rc == LDAP_SUCCESS || rc == LDAP_SASL_BIND_IN_PROGRESS ) { 214 if( servercredp != NULL ) { 215 *servercredp = scredp; 216 scredp = NULL; 217 } 218 } 219 220 if ( scredp != NULL ) { 221 ber_bvfree(scredp); 222 } 223 224 return rc; 225 } 226 227 228 /* 229 * Parse BindResponse: 230 * 231 * BindResponse ::= [APPLICATION 1] SEQUENCE { 232 * COMPONENTS OF LDAPResult, 233 * serverSaslCreds [7] OCTET STRING OPTIONAL } 234 * 235 * LDAPResult ::= SEQUENCE { 236 * resultCode ENUMERATED, 237 * matchedDN LDAPDN, 238 * errorMessage LDAPString, 239 * referral [3] Referral OPTIONAL } 240 */ 241 242 int 243 ldap_parse_sasl_bind_result( 244 LDAP *ld, 245 LDAPMessage *res, 246 struct berval **servercredp, 247 int freeit ) 248 { 249 ber_int_t errcode; 250 struct berval* scred; 251 252 ber_tag_t tag; 253 BerElement *ber; 254 255 Debug( LDAP_DEBUG_TRACE, "ldap_parse_sasl_bind_result\n", 0, 0, 0 ); 256 257 assert( ld != NULL ); 258 assert( LDAP_VALID( ld ) ); 259 assert( res != NULL ); 260 261 if( servercredp != NULL ) { 262 if( ld->ld_version < LDAP_VERSION2 ) { 263 return LDAP_NOT_SUPPORTED; 264 } 265 *servercredp = NULL; 266 } 267 268 if( res->lm_msgtype != LDAP_RES_BIND ) { 269 ld->ld_errno = LDAP_PARAM_ERROR; 270 return ld->ld_errno; 271 } 272 273 scred = NULL; 274 275 if ( ld->ld_error ) { 276 LDAP_FREE( ld->ld_error ); 277 ld->ld_error = NULL; 278 } 279 if ( ld->ld_matched ) { 280 LDAP_FREE( ld->ld_matched ); 281 ld->ld_matched = NULL; 282 } 283 284 /* parse results */ 285 286 ber = ber_dup( res->lm_ber ); 287 288 if( ber == NULL ) { 289 ld->ld_errno = LDAP_NO_MEMORY; 290 return ld->ld_errno; 291 } 292 293 if ( ld->ld_version < LDAP_VERSION2 ) { 294 tag = ber_scanf( ber, "{iA}", 295 &errcode, &ld->ld_error ); 296 297 if( tag == LBER_ERROR ) { 298 ber_free( ber, 0 ); 299 ld->ld_errno = LDAP_DECODING_ERROR; 300 return ld->ld_errno; 301 } 302 303 } else { 304 ber_len_t len; 305 306 tag = ber_scanf( ber, "{eAA" /*}*/, 307 &errcode, &ld->ld_matched, &ld->ld_error ); 308 309 if( tag == LBER_ERROR ) { 310 ber_free( ber, 0 ); 311 ld->ld_errno = LDAP_DECODING_ERROR; 312 return ld->ld_errno; 313 } 314 315 tag = ber_peek_tag(ber, &len); 316 317 if( tag == LDAP_TAG_REFERRAL ) { 318 /* skip 'em */ 319 if( ber_scanf( ber, "x" ) == LBER_ERROR ) { 320 ber_free( ber, 0 ); 321 ld->ld_errno = LDAP_DECODING_ERROR; 322 return ld->ld_errno; 323 } 324 325 tag = ber_peek_tag(ber, &len); 326 } 327 328 if( tag == LDAP_TAG_SASL_RES_CREDS ) { 329 if( ber_scanf( ber, "O", &scred ) == LBER_ERROR ) { 330 ber_free( ber, 0 ); 331 ld->ld_errno = LDAP_DECODING_ERROR; 332 return ld->ld_errno; 333 } 334 } 335 } 336 337 ber_free( ber, 0 ); 338 339 if ( servercredp != NULL ) { 340 *servercredp = scred; 341 342 } else if ( scred != NULL ) { 343 ber_bvfree( scred ); 344 } 345 346 ld->ld_errno = errcode; 347 348 if ( freeit ) { 349 ldap_msgfree( res ); 350 } 351 352 return( LDAP_SUCCESS ); 353 } 354 355 int 356 ldap_pvt_sasl_getmechs ( LDAP *ld, char **pmechlist ) 357 { 358 /* we need to query the server for supported mechs anyway */ 359 LDAPMessage *res, *e; 360 char *attrs[] = { "supportedSASLMechanisms", NULL }; 361 char **values, *mechlist; 362 int rc; 363 364 Debug( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_getmech\n", 0, 0, 0 ); 365 366 rc = ldap_search_s( ld, "", LDAP_SCOPE_BASE, 367 NULL, attrs, 0, &res ); 368 369 if ( rc != LDAP_SUCCESS ) { 370 return ld->ld_errno; 371 } 372 373 e = ldap_first_entry( ld, res ); 374 if ( e == NULL ) { 375 ldap_msgfree( res ); 376 if ( ld->ld_errno == LDAP_SUCCESS ) { 377 ld->ld_errno = LDAP_NO_SUCH_OBJECT; 378 } 379 return ld->ld_errno; 380 } 381 382 values = ldap_get_values( ld, e, "supportedSASLMechanisms" ); 383 if ( values == NULL ) { 384 ldap_msgfree( res ); 385 ld->ld_errno = LDAP_NO_SUCH_ATTRIBUTE; 386 return ld->ld_errno; 387 } 388 389 mechlist = ldap_charray2str( values, " " ); 390 if ( mechlist == NULL ) { 391 LDAP_VFREE( values ); 392 ldap_msgfree( res ); 393 ld->ld_errno = LDAP_NO_MEMORY; 394 return ld->ld_errno; 395 } 396 397 LDAP_VFREE( values ); 398 ldap_msgfree( res ); 399 400 *pmechlist = mechlist; 401 402 return LDAP_SUCCESS; 403 } 404 405 /* 406 * ldap_sasl_interactive_bind_s - interactive SASL authentication 407 * 408 * This routine uses interactive callbacks. 409 * 410 * LDAP_SUCCESS is returned upon success, the ldap error code 411 * otherwise. 412 */ 413 int 414 ldap_sasl_interactive_bind_s( 415 LDAP *ld, 416 LDAP_CONST char *dn, /* usually NULL */ 417 LDAP_CONST char *mechs, 418 LDAPControl **serverControls, 419 LDAPControl **clientControls, 420 unsigned flags, 421 LDAP_SASL_INTERACT_PROC *interact, 422 void *defaults ) 423 { 424 int rc; 425 char *smechs = NULL; 426 427 #if defined( LDAP_R_COMPILE ) && defined( HAVE_CYRUS_SASL ) 428 ldap_pvt_thread_mutex_lock( &ldap_int_sasl_mutex ); 429 #endif 430 #ifdef LDAP_CONNECTIONLESS 431 if( LDAP_IS_UDP(ld) ) { 432 /* Just force it to simple bind, silly to make the user 433 * ask all the time. No, we don't ever actually bind, but I'll 434 * let the final bind handler take care of saving the cdn. 435 */ 436 rc = ldap_simple_bind( ld, dn, NULL ); 437 rc = rc < 0 ? rc : 0; 438 goto done; 439 } else 440 #endif 441 442 #ifdef HAVE_CYRUS_SASL 443 if( mechs == NULL || *mechs == '\0' ) { 444 mechs = ld->ld_options.ldo_def_sasl_mech; 445 } 446 #endif 447 448 if( mechs == NULL || *mechs == '\0' ) { 449 rc = ldap_pvt_sasl_getmechs( ld, &smechs ); 450 if( rc != LDAP_SUCCESS ) { 451 goto done; 452 } 453 454 Debug( LDAP_DEBUG_TRACE, 455 "ldap_sasl_interactive_bind_s: server supports: %s\n", 456 smechs, 0, 0 ); 457 458 mechs = smechs; 459 460 } else { 461 Debug( LDAP_DEBUG_TRACE, 462 "ldap_sasl_interactive_bind_s: user selected: %s\n", 463 mechs, 0, 0 ); 464 } 465 466 rc = ldap_int_sasl_bind( ld, dn, mechs, 467 serverControls, clientControls, 468 flags, interact, defaults ); 469 470 done: 471 #if defined( LDAP_R_COMPILE ) && defined( HAVE_CYRUS_SASL ) 472 ldap_pvt_thread_mutex_unlock( &ldap_int_sasl_mutex ); 473 #endif 474 if ( smechs ) LDAP_FREE( smechs ); 475 476 return rc; 477 } 478 479 #ifdef HAVE_CYRUS_SASL 480 481 #ifdef HAVE_SASL_SASL_H 482 #include <sasl/sasl.h> 483 #else 484 #include <sasl.h> 485 #endif 486 487 #endif /* HAVE_CYRUS_SASL */ 488 489 static int 490 sb_sasl_generic_remove( Sockbuf_IO_Desc *sbiod ); 491 492 static int 493 sb_sasl_generic_setup( Sockbuf_IO_Desc *sbiod, void *arg ) 494 { 495 struct sb_sasl_generic_data *p; 496 struct sb_sasl_generic_install *i; 497 498 assert( sbiod != NULL ); 499 500 i = (struct sb_sasl_generic_install *)arg; 501 502 p = LBER_MALLOC( sizeof( *p ) ); 503 if ( p == NULL ) 504 return -1; 505 p->ops = i->ops; 506 p->ops_private = i->ops_private; 507 p->sbiod = sbiod; 508 p->flags = 0; 509 ber_pvt_sb_buf_init( &p->sec_buf_in ); 510 ber_pvt_sb_buf_init( &p->buf_in ); 511 ber_pvt_sb_buf_init( &p->buf_out ); 512 513 sbiod->sbiod_pvt = p; 514 515 p->ops->init( p, &p->min_send, &p->max_send, &p->max_recv ); 516 517 if ( ber_pvt_sb_grow_buffer( &p->sec_buf_in, p->min_send ) < 0 ) { 518 sb_sasl_generic_remove( sbiod ); 519 sock_errset(ENOMEM); 520 return -1; 521 } 522 523 return 0; 524 } 525 526 static int 527 sb_sasl_generic_remove( Sockbuf_IO_Desc *sbiod ) 528 { 529 struct sb_sasl_generic_data *p; 530 531 assert( sbiod != NULL ); 532 533 p = (struct sb_sasl_generic_data *)sbiod->sbiod_pvt; 534 535 p->ops->fini(p); 536 537 ber_pvt_sb_buf_destroy( &p->sec_buf_in ); 538 ber_pvt_sb_buf_destroy( &p->buf_in ); 539 ber_pvt_sb_buf_destroy( &p->buf_out ); 540 LBER_FREE( p ); 541 sbiod->sbiod_pvt = NULL; 542 return 0; 543 } 544 545 static ber_len_t 546 sb_sasl_generic_pkt_length( 547 struct sb_sasl_generic_data *p, 548 const unsigned char *buf, 549 int debuglevel ) 550 { 551 ber_len_t size; 552 553 assert( buf != NULL ); 554 555 size = buf[0] << 24 556 | buf[1] << 16 557 | buf[2] << 8 558 | buf[3]; 559 560 if ( size > p->max_recv ) { 561 /* somebody is trying to mess me up. */ 562 ber_log_printf( LDAP_DEBUG_ANY, debuglevel, 563 "sb_sasl_generic_pkt_length: " 564 "received illegal packet length of %lu bytes\n", 565 (unsigned long)size ); 566 size = 16; /* this should lead to an error. */ 567 } 568 569 return size + 4; /* include the size !!! */ 570 } 571 572 /* Drop a processed packet from the input buffer */ 573 static void 574 sb_sasl_generic_drop_packet ( 575 struct sb_sasl_generic_data *p, 576 int debuglevel ) 577 { 578 ber_slen_t len; 579 580 len = p->sec_buf_in.buf_ptr - p->sec_buf_in.buf_end; 581 if ( len > 0 ) 582 AC_MEMCPY( p->sec_buf_in.buf_base, p->sec_buf_in.buf_base + 583 p->sec_buf_in.buf_end, len ); 584 585 if ( len >= 4 ) { 586 p->sec_buf_in.buf_end = sb_sasl_generic_pkt_length(p, 587 (unsigned char *) p->sec_buf_in.buf_base, debuglevel); 588 } 589 else { 590 p->sec_buf_in.buf_end = 0; 591 } 592 p->sec_buf_in.buf_ptr = len; 593 } 594 595 static ber_slen_t 596 sb_sasl_generic_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) 597 { 598 struct sb_sasl_generic_data *p; 599 ber_slen_t ret, bufptr; 600 601 assert( sbiod != NULL ); 602 assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); 603 604 p = (struct sb_sasl_generic_data *)sbiod->sbiod_pvt; 605 606 /* Are there anything left in the buffer? */ 607 ret = ber_pvt_sb_copy_out( &p->buf_in, buf, len ); 608 bufptr = ret; 609 len -= ret; 610 611 if ( len == 0 ) 612 return bufptr; 613 614 p->ops->reset_buf( p, &p->buf_in ); 615 616 /* Read the length of the packet */ 617 while ( p->sec_buf_in.buf_ptr < 4 ) { 618 ret = LBER_SBIOD_READ_NEXT( sbiod, p->sec_buf_in.buf_base + 619 p->sec_buf_in.buf_ptr, 620 4 - p->sec_buf_in.buf_ptr ); 621 #ifdef EINTR 622 if ( ( ret < 0 ) && ( errno == EINTR ) ) 623 continue; 624 #endif 625 if ( ret <= 0 ) 626 return bufptr ? bufptr : ret; 627 628 p->sec_buf_in.buf_ptr += ret; 629 } 630 631 /* The new packet always starts at p->sec_buf_in.buf_base */ 632 ret = sb_sasl_generic_pkt_length(p, (unsigned char *) p->sec_buf_in.buf_base, 633 sbiod->sbiod_sb->sb_debug ); 634 635 /* Grow the packet buffer if neccessary */ 636 if ( ( p->sec_buf_in.buf_size < (ber_len_t) ret ) && 637 ber_pvt_sb_grow_buffer( &p->sec_buf_in, ret ) < 0 ) 638 { 639 sock_errset(ENOMEM); 640 return -1; 641 } 642 p->sec_buf_in.buf_end = ret; 643 644 /* Did we read the whole encrypted packet? */ 645 while ( p->sec_buf_in.buf_ptr < p->sec_buf_in.buf_end ) { 646 /* No, we have got only a part of it */ 647 ret = p->sec_buf_in.buf_end - p->sec_buf_in.buf_ptr; 648 649 ret = LBER_SBIOD_READ_NEXT( sbiod, p->sec_buf_in.buf_base + 650 p->sec_buf_in.buf_ptr, ret ); 651 #ifdef EINTR 652 if ( ( ret < 0 ) && ( errno == EINTR ) ) 653 continue; 654 #endif 655 if ( ret <= 0 ) 656 return bufptr ? bufptr : ret; 657 658 p->sec_buf_in.buf_ptr += ret; 659 } 660 661 /* Decode the packet */ 662 ret = p->ops->decode( p, &p->sec_buf_in, &p->buf_in ); 663 664 /* Drop the packet from the input buffer */ 665 sb_sasl_generic_drop_packet( p, sbiod->sbiod_sb->sb_debug ); 666 667 if ( ret != 0 ) { 668 ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug, 669 "sb_sasl_generic_read: failed to decode packet\n" ); 670 sock_errset(EIO); 671 return -1; 672 } 673 674 bufptr += ber_pvt_sb_copy_out( &p->buf_in, (char*) buf + bufptr, len ); 675 676 return bufptr; 677 } 678 679 static ber_slen_t 680 sb_sasl_generic_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) 681 { 682 struct sb_sasl_generic_data *p; 683 int ret; 684 ber_len_t len2; 685 686 assert( sbiod != NULL ); 687 assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); 688 689 p = (struct sb_sasl_generic_data *)sbiod->sbiod_pvt; 690 691 /* Is there anything left in the buffer? */ 692 if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) { 693 ret = ber_pvt_sb_do_write( sbiod, &p->buf_out ); 694 if ( ret < 0 ) return ret; 695 696 /* Still have something left?? */ 697 if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) { 698 sock_errset(EAGAIN); 699 return -1; 700 } 701 } 702 703 len2 = p->max_send - 100; /* For safety margin */ 704 len2 = len > len2 ? len2 : len; 705 706 /* If we're just retrying a partial write, tell the 707 * caller it's done. Let them call again if there's 708 * still more left to write. 709 */ 710 if ( p->flags & LDAP_PVT_SASL_PARTIAL_WRITE ) { 711 p->flags ^= LDAP_PVT_SASL_PARTIAL_WRITE; 712 return len2; 713 } 714 715 /* now encode the next packet. */ 716 p->ops->reset_buf( p, &p->buf_out ); 717 718 ret = p->ops->encode( p, buf, len2, &p->buf_out ); 719 720 if ( ret != 0 ) { 721 ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug, 722 "sb_sasl_generic_write: failed to encode packet\n" ); 723 sock_errset(EIO); 724 return -1; 725 } 726 727 ret = ber_pvt_sb_do_write( sbiod, &p->buf_out ); 728 729 if ( ret < 0 ) { 730 /* error? */ 731 int err = sock_errno(); 732 /* caller can retry this */ 733 if ( err == EAGAIN || err == EWOULDBLOCK || err == EINTR ) 734 p->flags |= LDAP_PVT_SASL_PARTIAL_WRITE; 735 return ret; 736 } else if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) { 737 /* partial write? pretend nothing got written */ 738 len2 = 0; 739 p->flags |= LDAP_PVT_SASL_PARTIAL_WRITE; 740 } 741 742 /* return number of bytes encoded, not written, to ensure 743 * no byte is encoded twice (even if only sent once). 744 */ 745 return len2; 746 } 747 748 static int 749 sb_sasl_generic_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) 750 { 751 struct sb_sasl_generic_data *p; 752 753 p = (struct sb_sasl_generic_data *)sbiod->sbiod_pvt; 754 755 if ( opt == LBER_SB_OPT_DATA_READY ) { 756 if ( p->buf_in.buf_ptr != p->buf_in.buf_end ) return 1; 757 } 758 759 return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg ); 760 } 761 762 Sockbuf_IO ldap_pvt_sockbuf_io_sasl_generic = { 763 sb_sasl_generic_setup, /* sbi_setup */ 764 sb_sasl_generic_remove, /* sbi_remove */ 765 sb_sasl_generic_ctrl, /* sbi_ctrl */ 766 sb_sasl_generic_read, /* sbi_read */ 767 sb_sasl_generic_write, /* sbi_write */ 768 NULL /* sbi_close */ 769 }; 770 771 int ldap_pvt_sasl_generic_install( 772 Sockbuf *sb, 773 struct sb_sasl_generic_install *install_arg ) 774 { 775 Debug( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_generic_install\n", 776 0, 0, 0 ); 777 778 /* don't install the stuff unless security has been negotiated */ 779 780 if ( !ber_sockbuf_ctrl( sb, LBER_SB_OPT_HAS_IO, 781 &ldap_pvt_sockbuf_io_sasl_generic ) ) 782 { 783 #ifdef LDAP_DEBUG 784 ber_sockbuf_add_io( sb, &ber_sockbuf_io_debug, 785 LBER_SBIOD_LEVEL_APPLICATION, (void *)"sasl_generic_" ); 786 #endif 787 ber_sockbuf_add_io( sb, &ldap_pvt_sockbuf_io_sasl_generic, 788 LBER_SBIOD_LEVEL_APPLICATION, install_arg ); 789 } 790 791 return LDAP_SUCCESS; 792 } 793 794 void ldap_pvt_sasl_generic_remove( Sockbuf *sb ) 795 { 796 ber_sockbuf_remove_io( sb, &ldap_pvt_sockbuf_io_sasl_generic, 797 LBER_SBIOD_LEVEL_APPLICATION ); 798 #ifdef LDAP_DEBUG 799 ber_sockbuf_remove_io( sb, &ber_sockbuf_io_debug, 800 LBER_SBIOD_LEVEL_APPLICATION ); 801 #endif 802 } 803