Back to index

openldap  2.4.31
sasl.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 1998-2012 The OpenLDAP Foundation.
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted only as authorized by the OpenLDAP
00009  * Public License.
00010  *
00011  * A copy of this license is available in the file LICENSE in the
00012  * top-level directory of the distribution or, alternatively, at
00013  * <http://www.OpenLDAP.org/license.html>.
00014  */
00015 
00016 /*
00017  *     BindRequest ::= SEQUENCE {
00018  *            version              INTEGER,
00019  *            name          DistinguishedName,    -- who
00020  *            authentication       CHOICE {
00021  *                   simple        [0] OCTET STRING -- passwd
00022  *                   krbv42ldap    [1] OCTET STRING -- OBSOLETE
00023  *                   krbv42dsa     [2] OCTET STRING -- OBSOLETE
00024  *                   sasl          [3] SaslCredentials  -- LDAPv3
00025  *            }
00026  *     }
00027  *
00028  *     BindResponse ::= SEQUENCE {
00029  *            COMPONENTS OF LDAPResult,
00030  *            serverSaslCreds             OCTET STRING OPTIONAL -- LDAPv3
00031  *     }
00032  *
00033  */
00034 
00035 #include "portable.h"
00036 
00037 #include <stdio.h>
00038 
00039 #include <ac/socket.h>
00040 #include <ac/stdlib.h>
00041 #include <ac/string.h>
00042 #include <ac/time.h>
00043 #include <ac/errno.h>
00044 
00045 #include "ldap-int.h"
00046 
00047 /*
00048  * ldap_sasl_bind - bind to the ldap server (and X.500).
00049  * The dn (usually NULL), mechanism, and credentials are provided.
00050  * The message id of the request initiated is provided upon successful
00051  * (LDAP_SUCCESS) return.
00052  *
00053  * Example:
00054  *     ldap_sasl_bind( ld, NULL, "mechanism",
00055  *            cred, NULL, NULL, &msgid )
00056  */
00057 
00058 int
00059 ldap_sasl_bind(
00060        LDAP                 *ld,
00061        LDAP_CONST char      *dn,
00062        LDAP_CONST char      *mechanism,
00063        struct berval *cred,
00064        LDAPControl          **sctrls,
00065        LDAPControl          **cctrls,
00066        int                         *msgidp )
00067 {
00068        BerElement    *ber;
00069        int rc;
00070        ber_int_t id;
00071 
00072        Debug( LDAP_DEBUG_TRACE, "ldap_sasl_bind\n", 0, 0, 0 );
00073 
00074        assert( ld != NULL );
00075        assert( LDAP_VALID( ld ) );
00076        assert( msgidp != NULL );
00077 
00078        /* check client controls */
00079        rc = ldap_int_client_controls( ld, cctrls );
00080        if( rc != LDAP_SUCCESS ) return rc;
00081 
00082        if( mechanism == LDAP_SASL_SIMPLE ) {
00083               if( dn == NULL && cred != NULL && cred->bv_len ) {
00084                      /* use default binddn */
00085                      dn = ld->ld_defbinddn;
00086               }
00087 
00088        } else if( ld->ld_version < LDAP_VERSION3 ) {
00089               ld->ld_errno = LDAP_NOT_SUPPORTED;
00090               return ld->ld_errno;
00091        }
00092 
00093        if ( dn == NULL ) {
00094               dn = "";
00095        }
00096 
00097        /* create a message to send */
00098        if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
00099               ld->ld_errno = LDAP_NO_MEMORY;
00100               return ld->ld_errno;
00101        }
00102 
00103        assert( LBER_VALID( ber ) );
00104 
00105        LDAP_NEXT_MSGID( ld, id );
00106        if( mechanism == LDAP_SASL_SIMPLE ) {
00107               /* simple bind */
00108               rc = ber_printf( ber, "{it{istON}" /*}*/,
00109                      id, LDAP_REQ_BIND,
00110                      ld->ld_version, dn, LDAP_AUTH_SIMPLE,
00111                      cred );
00112               
00113        } else if ( cred == NULL || cred->bv_val == NULL ) {
00114               /* SASL bind w/o credentials */
00115               rc = ber_printf( ber, "{it{ist{sN}N}" /*}*/,
00116                      id, LDAP_REQ_BIND,
00117                      ld->ld_version, dn, LDAP_AUTH_SASL,
00118                      mechanism );
00119 
00120        } else {
00121               /* SASL bind w/ credentials */
00122               rc = ber_printf( ber, "{it{ist{sON}N}" /*}*/,
00123                      id, LDAP_REQ_BIND,
00124                      ld->ld_version, dn, LDAP_AUTH_SASL,
00125                      mechanism, cred );
00126        }
00127 
00128        if( rc == -1 ) {
00129               ld->ld_errno = LDAP_ENCODING_ERROR;
00130               ber_free( ber, 1 );
00131               return( -1 );
00132        }
00133 
00134        /* Put Server Controls */
00135        if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
00136               ber_free( ber, 1 );
00137               return ld->ld_errno;
00138        }
00139 
00140        if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) {
00141               ld->ld_errno = LDAP_ENCODING_ERROR;
00142               ber_free( ber, 1 );
00143               return ld->ld_errno;
00144        }
00145 
00146 
00147        /* send the message */
00148        *msgidp = ldap_send_initial_request( ld, LDAP_REQ_BIND, dn, ber, id );
00149 
00150        if(*msgidp < 0)
00151               return ld->ld_errno;
00152 
00153        return LDAP_SUCCESS;
00154 }
00155 
00156 
00157 int
00158 ldap_sasl_bind_s(
00159        LDAP                 *ld,
00160        LDAP_CONST char      *dn,
00161        LDAP_CONST char      *mechanism,
00162        struct berval *cred,
00163        LDAPControl          **sctrls,
00164        LDAPControl          **cctrls,
00165        struct berval **servercredp )
00166 {
00167        int    rc, msgid;
00168        LDAPMessage   *result;
00169        struct berval *scredp = NULL;
00170 
00171        Debug( LDAP_DEBUG_TRACE, "ldap_sasl_bind_s\n", 0, 0, 0 );
00172 
00173        /* do a quick !LDAPv3 check... ldap_sasl_bind will do the rest. */
00174        if( servercredp != NULL ) {
00175               if (ld->ld_version < LDAP_VERSION3) {
00176                      ld->ld_errno = LDAP_NOT_SUPPORTED;
00177                      return ld->ld_errno;
00178               }
00179               *servercredp = NULL;
00180        }
00181 
00182        rc = ldap_sasl_bind( ld, dn, mechanism, cred, sctrls, cctrls, &msgid );
00183 
00184        if ( rc != LDAP_SUCCESS ) {
00185               return( rc );
00186        }
00187 
00188 #ifdef LDAP_CONNECTIONLESS
00189        if (LDAP_IS_UDP(ld)) {
00190               return( rc );
00191        }
00192 #endif
00193 
00194        if ( ldap_result( ld, msgid, LDAP_MSG_ALL, NULL, &result ) == -1 || !result ) {
00195               return( ld->ld_errno );     /* ldap_result sets ld_errno */
00196        }
00197 
00198        /* parse the results */
00199        scredp = NULL;
00200        if( servercredp != NULL ) {
00201               rc = ldap_parse_sasl_bind_result( ld, result, &scredp, 0 );
00202        }
00203 
00204        if ( rc != LDAP_SUCCESS ) {
00205               ldap_msgfree( result );
00206               return( rc );
00207        }
00208 
00209        rc = ldap_result2error( ld, result, 1 );
00210 
00211        if ( rc == LDAP_SUCCESS || rc == LDAP_SASL_BIND_IN_PROGRESS ) {
00212               if( servercredp != NULL ) {
00213                      *servercredp = scredp;
00214                      scredp = NULL;
00215               }
00216        }
00217 
00218        if ( scredp != NULL ) {
00219               ber_bvfree(scredp);
00220        }
00221 
00222        return rc;
00223 }
00224 
00225 
00226 /*
00227 * Parse BindResponse:
00228 *
00229 *   BindResponse ::= [APPLICATION 1] SEQUENCE {
00230 *     COMPONENTS OF LDAPResult,
00231 *     serverSaslCreds  [7] OCTET STRING OPTIONAL }
00232 *
00233 *   LDAPResult ::= SEQUENCE {
00234 *     resultCode      ENUMERATED,
00235 *     matchedDN       LDAPDN,
00236 *     errorMessage    LDAPString,
00237 *     referral        [3] Referral OPTIONAL }
00238 */
00239 
00240 int
00241 ldap_parse_sasl_bind_result(
00242        LDAP                 *ld,
00243        LDAPMessage          *res,
00244        struct berval **servercredp,
00245        int                         freeit )
00246 {
00247        ber_int_t errcode;
00248        struct berval* scred;
00249 
00250        ber_tag_t tag;
00251        BerElement    *ber;
00252 
00253        Debug( LDAP_DEBUG_TRACE, "ldap_parse_sasl_bind_result\n", 0, 0, 0 );
00254 
00255        assert( ld != NULL );
00256        assert( LDAP_VALID( ld ) );
00257        assert( res != NULL );
00258 
00259        if( servercredp != NULL ) {
00260               if( ld->ld_version < LDAP_VERSION2 ) {
00261                      return LDAP_NOT_SUPPORTED;
00262               }
00263               *servercredp = NULL;
00264        }
00265 
00266        if( res->lm_msgtype != LDAP_RES_BIND ) {
00267               ld->ld_errno = LDAP_PARAM_ERROR;
00268               return ld->ld_errno;
00269        }
00270 
00271        scred = NULL;
00272 
00273        if ( ld->ld_error ) {
00274               LDAP_FREE( ld->ld_error );
00275               ld->ld_error = NULL;
00276        }
00277        if ( ld->ld_matched ) {
00278               LDAP_FREE( ld->ld_matched );
00279               ld->ld_matched = NULL;
00280        }
00281 
00282        /* parse results */
00283 
00284        ber = ber_dup( res->lm_ber );
00285 
00286        if( ber == NULL ) {
00287               ld->ld_errno = LDAP_NO_MEMORY;
00288               return ld->ld_errno;
00289        }
00290 
00291        if ( ld->ld_version < LDAP_VERSION2 ) {
00292               tag = ber_scanf( ber, "{iA}",
00293                      &errcode, &ld->ld_error );
00294 
00295               if( tag == LBER_ERROR ) {
00296                      ber_free( ber, 0 );
00297                      ld->ld_errno = LDAP_DECODING_ERROR;
00298                      return ld->ld_errno;
00299               }
00300 
00301        } else {
00302               ber_len_t len;
00303 
00304               tag = ber_scanf( ber, "{eAA" /*}*/,
00305                      &errcode, &ld->ld_matched, &ld->ld_error );
00306 
00307               if( tag == LBER_ERROR ) {
00308                      ber_free( ber, 0 );
00309                      ld->ld_errno = LDAP_DECODING_ERROR;
00310                      return ld->ld_errno;
00311               }
00312 
00313               tag = ber_peek_tag(ber, &len);
00314 
00315               if( tag == LDAP_TAG_REFERRAL ) {
00316                      /* skip 'em */
00317                      if( ber_scanf( ber, "x" ) == LBER_ERROR ) {
00318                             ber_free( ber, 0 );
00319                             ld->ld_errno = LDAP_DECODING_ERROR;
00320                             return ld->ld_errno;
00321                      }
00322 
00323                      tag = ber_peek_tag(ber, &len);
00324               }
00325 
00326               if( tag == LDAP_TAG_SASL_RES_CREDS ) {
00327                      if( ber_scanf( ber, "O", &scred ) == LBER_ERROR ) {
00328                             ber_free( ber, 0 );
00329                             ld->ld_errno = LDAP_DECODING_ERROR;
00330                             return ld->ld_errno;
00331                      }
00332               }
00333        }
00334 
00335        ber_free( ber, 0 );
00336 
00337        if ( servercredp != NULL ) {
00338               *servercredp = scred;
00339 
00340        } else if ( scred != NULL ) {
00341               ber_bvfree( scred );
00342        }
00343 
00344        ld->ld_errno = errcode;
00345 
00346        if ( freeit ) {
00347               ldap_msgfree( res );
00348        }
00349 
00350        return( LDAP_SUCCESS );
00351 }
00352 
00353 int
00354 ldap_pvt_sasl_getmechs ( LDAP *ld, char **pmechlist )
00355 {
00356        /* we need to query the server for supported mechs anyway */
00357        LDAPMessage *res, *e;
00358        char *attrs[] = { "supportedSASLMechanisms", NULL };
00359        char **values, *mechlist;
00360        int rc;
00361 
00362        Debug( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_getmech\n", 0, 0, 0 );
00363 
00364        rc = ldap_search_s( ld, "", LDAP_SCOPE_BASE,
00365               NULL, attrs, 0, &res );
00366 
00367        if ( rc != LDAP_SUCCESS ) {
00368               return ld->ld_errno;
00369        }
00370               
00371        e = ldap_first_entry( ld, res );
00372        if ( e == NULL ) {
00373               ldap_msgfree( res );
00374               if ( ld->ld_errno == LDAP_SUCCESS ) {
00375                      ld->ld_errno = LDAP_NO_SUCH_OBJECT;
00376               }
00377               return ld->ld_errno;
00378        }
00379 
00380        values = ldap_get_values( ld, e, "supportedSASLMechanisms" );
00381        if ( values == NULL ) {
00382               ldap_msgfree( res );
00383               ld->ld_errno = LDAP_NO_SUCH_ATTRIBUTE;
00384               return ld->ld_errno;
00385        }
00386 
00387        mechlist = ldap_charray2str( values, " " );
00388        if ( mechlist == NULL ) {
00389               LDAP_VFREE( values );
00390               ldap_msgfree( res );
00391               ld->ld_errno = LDAP_NO_MEMORY;
00392               return ld->ld_errno;
00393        } 
00394 
00395        LDAP_VFREE( values );
00396        ldap_msgfree( res );
00397 
00398        *pmechlist = mechlist;
00399 
00400        return LDAP_SUCCESS;
00401 }
00402 
00403 /*
00404  * ldap_sasl_interactive_bind - interactive SASL authentication
00405  *
00406  * This routine uses interactive callbacks.
00407  *
00408  * LDAP_SUCCESS is returned upon success, the ldap error code
00409  * otherwise. LDAP_SASL_BIND_IN_PROGRESS is returned if further
00410  * calls are needed.
00411  */
00412 int
00413 ldap_sasl_interactive_bind(
00414        LDAP *ld,
00415        LDAP_CONST char *dn, /* usually NULL */
00416        LDAP_CONST char *mechs,
00417        LDAPControl **serverControls,
00418        LDAPControl **clientControls,
00419        unsigned flags,
00420        LDAP_SASL_INTERACT_PROC *interact,
00421        void *defaults,
00422        LDAPMessage *result,
00423        const char **rmech,
00424        int *msgid )
00425 {
00426        char *smechs = NULL;
00427        int rc;
00428 
00429 #if defined( HAVE_CYRUS_SASL )
00430        LDAP_MUTEX_LOCK( &ldap_int_sasl_mutex );
00431 #endif
00432 #ifdef LDAP_CONNECTIONLESS
00433        if( LDAP_IS_UDP(ld) ) {
00434               /* Just force it to simple bind, silly to make the user
00435                * ask all the time. No, we don't ever actually bind, but I'll
00436                * let the final bind handler take care of saving the cdn.
00437                */
00438               rc = ldap_simple_bind( ld, dn, NULL );
00439               rc = rc < 0 ? rc : 0;
00440               goto done;
00441        } else
00442 #endif
00443 
00444        /* First time */
00445        if ( !result ) {
00446 
00447 #ifdef HAVE_CYRUS_SASL
00448        if( mechs == NULL || *mechs == '\0' ) {
00449               mechs = ld->ld_options.ldo_def_sasl_mech;
00450        }
00451 #endif
00452               
00453        if( mechs == NULL || *mechs == '\0' ) {
00454               /* FIXME: this needs to be asynchronous too;
00455                * perhaps NULL should be disallowed for async usage?
00456                */
00457               rc = ldap_pvt_sasl_getmechs( ld, &smechs );
00458               if( rc != LDAP_SUCCESS ) {
00459                      goto done;
00460               }
00461 
00462               Debug( LDAP_DEBUG_TRACE,
00463                      "ldap_sasl_interactive_bind: server supports: %s\n",
00464                      smechs, 0, 0 );
00465 
00466               mechs = smechs;
00467 
00468        } else {
00469               Debug( LDAP_DEBUG_TRACE,
00470                      "ldap_sasl_interactive_bind: user selected: %s\n",
00471                      mechs, 0, 0 );
00472        }
00473        }
00474        rc = ldap_int_sasl_bind( ld, dn, mechs,
00475               serverControls, clientControls,
00476               flags, interact, defaults, result, rmech, msgid );
00477 
00478 done:
00479 #if defined( HAVE_CYRUS_SASL )
00480        LDAP_MUTEX_UNLOCK( &ldap_int_sasl_mutex );
00481 #endif
00482        if ( smechs ) LDAP_FREE( smechs );
00483 
00484        return rc;
00485 }
00486 
00487 /*
00488  * ldap_sasl_interactive_bind_s - interactive SASL authentication
00489  *
00490  * This routine uses interactive callbacks.
00491  *
00492  * LDAP_SUCCESS is returned upon success, the ldap error code
00493  * otherwise.
00494  */
00495 int
00496 ldap_sasl_interactive_bind_s(
00497        LDAP *ld,
00498        LDAP_CONST char *dn, /* usually NULL */
00499        LDAP_CONST char *mechs,
00500        LDAPControl **serverControls,
00501        LDAPControl **clientControls,
00502        unsigned flags,
00503        LDAP_SASL_INTERACT_PROC *interact,
00504        void *defaults )
00505 {
00506        const char *rmech = NULL;
00507        LDAPMessage *result = NULL;
00508        int rc, msgid;
00509 
00510        do {
00511               rc = ldap_sasl_interactive_bind( ld, dn, mechs,
00512                      serverControls, clientControls,
00513                      flags, interact, defaults, result, &rmech, &msgid );
00514 
00515               ldap_msgfree( result );
00516 
00517               if ( rc != LDAP_SASL_BIND_IN_PROGRESS )
00518                      break;
00519 
00520 #ifdef LDAP_CONNECTIONLESS
00521               if (LDAP_IS_UDP(ld)) {
00522                      break;
00523               }
00524 #endif
00525 
00526               if ( ldap_result( ld, msgid, LDAP_MSG_ALL, NULL, &result ) == -1 || !result ) {
00527                      return( ld->ld_errno );     /* ldap_result sets ld_errno */
00528               }
00529        } while ( rc == LDAP_SASL_BIND_IN_PROGRESS );
00530 
00531        return rc;
00532 }
00533 
00534 #ifdef HAVE_CYRUS_SASL
00535 
00536 #ifdef HAVE_SASL_SASL_H
00537 #include <sasl/sasl.h>
00538 #else
00539 #include <sasl.h>
00540 #endif
00541 
00542 #endif /* HAVE_CYRUS_SASL */
00543 
00544 static int
00545 sb_sasl_generic_remove( Sockbuf_IO_Desc *sbiod );
00546 
00547 static int
00548 sb_sasl_generic_setup( Sockbuf_IO_Desc *sbiod, void *arg )
00549 {
00550        struct sb_sasl_generic_data *p;
00551        struct sb_sasl_generic_install     *i;
00552 
00553        assert( sbiod != NULL );
00554 
00555        i = (struct sb_sasl_generic_install *)arg;
00556 
00557        p = LBER_MALLOC( sizeof( *p ) );
00558        if ( p == NULL )
00559               return -1;
00560        p->ops = i->ops;
00561        p->ops_private = i->ops_private;
00562        p->sbiod = sbiod;
00563        p->flags = 0;
00564        ber_pvt_sb_buf_init( &p->sec_buf_in );
00565        ber_pvt_sb_buf_init( &p->buf_in );
00566        ber_pvt_sb_buf_init( &p->buf_out );
00567 
00568        sbiod->sbiod_pvt = p;
00569 
00570        p->ops->init( p, &p->min_send, &p->max_send, &p->max_recv );
00571 
00572        if ( ber_pvt_sb_grow_buffer( &p->sec_buf_in, p->min_send ) < 0 ) {
00573               sb_sasl_generic_remove( sbiod );
00574               sock_errset(ENOMEM);
00575               return -1;
00576        }
00577 
00578        return 0;
00579 }
00580 
00581 static int
00582 sb_sasl_generic_remove( Sockbuf_IO_Desc *sbiod )
00583 {
00584        struct sb_sasl_generic_data *p;
00585 
00586        assert( sbiod != NULL );
00587 
00588        p = (struct sb_sasl_generic_data *)sbiod->sbiod_pvt;
00589 
00590        p->ops->fini(p);
00591 
00592        ber_pvt_sb_buf_destroy( &p->sec_buf_in );
00593        ber_pvt_sb_buf_destroy( &p->buf_in );
00594        ber_pvt_sb_buf_destroy( &p->buf_out );
00595        LBER_FREE( p );
00596        sbiod->sbiod_pvt = NULL;
00597        return 0;
00598 }
00599 
00600 static ber_len_t
00601 sb_sasl_generic_pkt_length(
00602        struct sb_sasl_generic_data *p,
00603        const unsigned char *buf,
00604        int debuglevel )
00605 {
00606        ber_len_t            size;
00607 
00608        assert( buf != NULL );
00609 
00610        size = buf[0] << 24
00611               | buf[1] << 16
00612               | buf[2] << 8
00613               | buf[3];
00614 
00615        if ( size > p->max_recv ) {
00616               /* somebody is trying to mess me up. */
00617               ber_log_printf( LDAP_DEBUG_ANY, debuglevel,
00618                      "sb_sasl_generic_pkt_length: "
00619                      "received illegal packet length of %lu bytes\n",
00620                      (unsigned long)size );
00621               size = 16; /* this should lead to an error. */
00622        }
00623 
00624        return size + 4; /* include the size !!! */
00625 }
00626 
00627 /* Drop a processed packet from the input buffer */
00628 static void
00629 sb_sasl_generic_drop_packet (
00630        struct sb_sasl_generic_data *p,
00631        int debuglevel )
00632 {
00633        ber_slen_t                  len;
00634 
00635        len = p->sec_buf_in.buf_ptr - p->sec_buf_in.buf_end;
00636        if ( len > 0 )
00637               AC_MEMCPY( p->sec_buf_in.buf_base, p->sec_buf_in.buf_base +
00638                      p->sec_buf_in.buf_end, len );
00639 
00640        if ( len >= 4 ) {
00641               p->sec_buf_in.buf_end = sb_sasl_generic_pkt_length(p,
00642                      (unsigned char *) p->sec_buf_in.buf_base, debuglevel);
00643        }
00644        else {
00645               p->sec_buf_in.buf_end = 0;
00646        }
00647        p->sec_buf_in.buf_ptr = len;
00648 }
00649 
00650 static ber_slen_t
00651 sb_sasl_generic_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
00652 {
00653        struct sb_sasl_generic_data *p;
00654        ber_slen_t                  ret, bufptr;
00655 
00656        assert( sbiod != NULL );
00657        assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
00658 
00659        p = (struct sb_sasl_generic_data *)sbiod->sbiod_pvt;
00660 
00661        /* Are there anything left in the buffer? */
00662        ret = ber_pvt_sb_copy_out( &p->buf_in, buf, len );
00663        bufptr = ret;
00664        len -= ret;
00665 
00666        if ( len == 0 )
00667               return bufptr;
00668 
00669        p->ops->reset_buf( p, &p->buf_in );
00670 
00671        /* Read the length of the packet */
00672        while ( p->sec_buf_in.buf_ptr < 4 ) {
00673               ret = LBER_SBIOD_READ_NEXT( sbiod, p->sec_buf_in.buf_base +
00674                      p->sec_buf_in.buf_ptr,
00675                      4 - p->sec_buf_in.buf_ptr );
00676 #ifdef EINTR
00677               if ( ( ret < 0 ) && ( errno == EINTR ) )
00678                      continue;
00679 #endif
00680               if ( ret <= 0 )
00681                      return bufptr ? bufptr : ret;
00682 
00683               p->sec_buf_in.buf_ptr += ret;
00684        }
00685 
00686        /* The new packet always starts at p->sec_buf_in.buf_base */
00687        ret = sb_sasl_generic_pkt_length(p, (unsigned char *) p->sec_buf_in.buf_base,
00688               sbiod->sbiod_sb->sb_debug );
00689 
00690        /* Grow the packet buffer if neccessary */
00691        if ( ( p->sec_buf_in.buf_size < (ber_len_t) ret ) && 
00692               ber_pvt_sb_grow_buffer( &p->sec_buf_in, ret ) < 0 )
00693        {
00694               sock_errset(ENOMEM);
00695               return -1;
00696        }
00697        p->sec_buf_in.buf_end = ret;
00698 
00699        /* Did we read the whole encrypted packet? */
00700        while ( p->sec_buf_in.buf_ptr < p->sec_buf_in.buf_end ) {
00701               /* No, we have got only a part of it */
00702               ret = p->sec_buf_in.buf_end - p->sec_buf_in.buf_ptr;
00703 
00704               ret = LBER_SBIOD_READ_NEXT( sbiod, p->sec_buf_in.buf_base +
00705                      p->sec_buf_in.buf_ptr, ret );
00706 #ifdef EINTR
00707               if ( ( ret < 0 ) && ( errno == EINTR ) )
00708                      continue;
00709 #endif
00710               if ( ret <= 0 )
00711                      return bufptr ? bufptr : ret;
00712 
00713               p->sec_buf_in.buf_ptr += ret;
00714        }
00715 
00716        /* Decode the packet */
00717        ret = p->ops->decode( p, &p->sec_buf_in, &p->buf_in );
00718 
00719        /* Drop the packet from the input buffer */
00720        sb_sasl_generic_drop_packet( p, sbiod->sbiod_sb->sb_debug );
00721 
00722        if ( ret != 0 ) {
00723               ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug,
00724                      "sb_sasl_generic_read: failed to decode packet\n" );
00725               sock_errset(EIO);
00726               return -1;
00727        }
00728 
00729        bufptr += ber_pvt_sb_copy_out( &p->buf_in, (char*) buf + bufptr, len );
00730 
00731        return bufptr;
00732 }
00733 
00734 static ber_slen_t
00735 sb_sasl_generic_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
00736 {
00737        struct sb_sasl_generic_data *p;
00738        int                         ret;
00739        ber_len_t                   len2;
00740 
00741        assert( sbiod != NULL );
00742        assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
00743 
00744        p = (struct sb_sasl_generic_data *)sbiod->sbiod_pvt;
00745 
00746        /* Is there anything left in the buffer? */
00747        if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) {
00748               ret = ber_pvt_sb_do_write( sbiod, &p->buf_out );
00749               if ( ret < 0 ) return ret;
00750 
00751               /* Still have something left?? */
00752               if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) {
00753                      sock_errset(EAGAIN);
00754                      return -1;
00755               }
00756        }
00757 
00758        len2 = p->max_send - 100;   /* For safety margin */
00759        len2 = len > len2 ? len2 : len;
00760 
00761        /* If we're just retrying a partial write, tell the
00762         * caller it's done. Let them call again if there's
00763         * still more left to write.
00764         */
00765        if ( p->flags & LDAP_PVT_SASL_PARTIAL_WRITE ) {
00766               p->flags ^= LDAP_PVT_SASL_PARTIAL_WRITE;
00767               return len2;
00768        }
00769 
00770        /* now encode the next packet. */
00771        p->ops->reset_buf( p, &p->buf_out );
00772 
00773        ret = p->ops->encode( p, buf, len2, &p->buf_out );
00774 
00775        if ( ret != 0 ) {
00776               ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug,
00777                      "sb_sasl_generic_write: failed to encode packet\n" );
00778               sock_errset(EIO);
00779               return -1;
00780        }
00781 
00782        ret = ber_pvt_sb_do_write( sbiod, &p->buf_out );
00783 
00784        if ( ret < 0 ) {
00785               /* error? */
00786               int err = sock_errno();
00787               /* caller can retry this */
00788               if ( err == EAGAIN || err == EWOULDBLOCK || err == EINTR )
00789                      p->flags |= LDAP_PVT_SASL_PARTIAL_WRITE;
00790               return ret;
00791        } else if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) {
00792               /* partial write? pretend nothing got written */
00793               p->flags |= LDAP_PVT_SASL_PARTIAL_WRITE;
00794               sock_errset(EAGAIN);
00795               len2 = -1;
00796        }
00797 
00798        /* return number of bytes encoded, not written, to ensure
00799         * no byte is encoded twice (even if only sent once).
00800         */
00801        return len2;
00802 }
00803 
00804 static int
00805 sb_sasl_generic_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
00806 {
00807        struct sb_sasl_generic_data *p;
00808 
00809        p = (struct sb_sasl_generic_data *)sbiod->sbiod_pvt;
00810 
00811        if ( opt == LBER_SB_OPT_DATA_READY ) {
00812               if ( p->buf_in.buf_ptr != p->buf_in.buf_end ) return 1;
00813        }
00814 
00815        return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
00816 }
00817 
00818 Sockbuf_IO ldap_pvt_sockbuf_io_sasl_generic = {
00819        sb_sasl_generic_setup,             /* sbi_setup */
00820        sb_sasl_generic_remove,            /* sbi_remove */
00821        sb_sasl_generic_ctrl,              /* sbi_ctrl */
00822        sb_sasl_generic_read,              /* sbi_read */
00823        sb_sasl_generic_write,             /* sbi_write */
00824        NULL                 /* sbi_close */
00825 };
00826 
00827 int ldap_pvt_sasl_generic_install(
00828        Sockbuf *sb,
00829        struct sb_sasl_generic_install *install_arg )
00830 {
00831        Debug( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_generic_install\n",
00832               0, 0, 0 );
00833 
00834        /* don't install the stuff unless security has been negotiated */
00835 
00836        if ( !ber_sockbuf_ctrl( sb, LBER_SB_OPT_HAS_IO,
00837                      &ldap_pvt_sockbuf_io_sasl_generic ) )
00838        {
00839 #ifdef LDAP_DEBUG
00840               ber_sockbuf_add_io( sb, &ber_sockbuf_io_debug,
00841                      LBER_SBIOD_LEVEL_APPLICATION, (void *)"sasl_generic_" );
00842 #endif
00843               ber_sockbuf_add_io( sb, &ldap_pvt_sockbuf_io_sasl_generic,
00844                      LBER_SBIOD_LEVEL_APPLICATION, install_arg );
00845        }
00846 
00847        return LDAP_SUCCESS;
00848 }
00849 
00850 void ldap_pvt_sasl_generic_remove( Sockbuf *sb )
00851 {
00852        ber_sockbuf_remove_io( sb, &ldap_pvt_sockbuf_io_sasl_generic,
00853               LBER_SBIOD_LEVEL_APPLICATION );
00854 #ifdef LDAP_DEBUG
00855        ber_sockbuf_remove_io( sb, &ber_sockbuf_io_debug,
00856               LBER_SBIOD_LEVEL_APPLICATION );
00857 #endif
00858 }