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