- return( ld->ld_errno );
-}
-
-#ifdef HAVE_CYRUS_SASL
-/*
-* Various Cyrus SASL related stuff.
-*/
-
-#define MAX_BUFF_SIZE 65536
-#define MIN_BUFF_SIZE 4096
-
-static char *
-array2str( char **a )
-{
- char *s, **v, *p;
- int len = 0;
-
- for ( v = a; *v != NULL; v++ ) {
- len += strlen( *v ) + 1; /* for a space */
- }
-
- if ( len == 0 ) {
- return NULL;
- }
-
- s = LDAP_MALLOC ( len ); /* last space holds \0 */
-
- if ( s == NULL ) {
- return NULL;
- }
-
- p = s;
- for ( v = a; *v != NULL; v++ ) {
- int len;
-
- if ( v != a ) {
- strncpy( p, " ", 1 );
- ++p;
- }
- len = strlen( *v );
- strncpy( p, *v, len );
- p += len;
- }
-
- *p = '\0';
-
- return s;
-}
-
-int ldap_pvt_sasl_init( void )
-{
- /* XXX not threadsafe */
- static int sasl_initialized = 0;
-
- if ( sasl_initialized ) {
- return 0;
- }
-#ifndef CSRIMALLOC
- sasl_set_alloc( ber_memalloc, ber_memcalloc, ber_memrealloc, ber_memfree );
-#endif /* CSRIMALLOC */
-
- if ( sasl_client_init( NULL ) == SASL_OK ) {
- sasl_initialized = 1;
- return 0;
- }
-
- return -1;
-}
-
-/*
- * SASL encryption support for LBER Sockbufs
- */
-
-struct sb_sasl_data {
- sasl_conn_t *sasl_context;
- Sockbuf_Buf sec_buf_in;
- Sockbuf_Buf buf_in;
- Sockbuf_Buf buf_out;
-};
-
-static int
-sb_sasl_setup( Sockbuf_IO_Desc *sbiod, void *arg )
-{
- struct sb_sasl_data *p;
-
- assert( sbiod != NULL );
-
- p = LBER_MALLOC( sizeof( *p ) );
- if ( p == NULL )
- return -1;
- p->sasl_context = (sasl_conn_t *)arg;
- ber_pvt_sb_buf_init( &p->sec_buf_in );
- ber_pvt_sb_buf_init( &p->buf_in );
- ber_pvt_sb_buf_init( &p->buf_out );
- if ( ber_pvt_sb_grow_buffer( &p->sec_buf_in, MIN_BUFF_SIZE ) < 0 ) {
- errno = ENOMEM;
- return -1;
- }
-
- sbiod->sbiod_pvt = p;
-
- return 0;
-}
-
-static int
-sb_sasl_remove( Sockbuf_IO_Desc *sbiod )
-{
- struct sb_sasl_data *p;
-
- assert( sbiod != NULL );
-
- p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
- ber_pvt_sb_buf_destroy( &p->sec_buf_in );
- ber_pvt_sb_buf_destroy( &p->buf_in );
- ber_pvt_sb_buf_destroy( &p->buf_out );
- LBER_FREE( p );
- sbiod->sbiod_pvt = NULL;
- return 0;
-}
-
-static ber_len_t
-sb_sasl_pkt_length( const char *buf, int debuglevel )
-{
- ber_len_t size;
- long tmp;
-
- assert( buf != NULL );
-
- tmp = *((long *)buf);
- size = ntohl( tmp );
-
- if ( size > MAX_BUFF_SIZE ) {
- /* somebody is trying to mess me up. */
- ber_log_printf( LDAP_DEBUG_ANY, debuglevel,
- "sb_sasl_pkt_length: received illegal packet length "
- "of %lu bytes\n", (unsigned long)size );
- size = 16; /* this should lead to an error. */
-}
-
- return size + 4; /* include the size !!! */
-}
-
-/* Drop a processed packet from the input buffer */
-static void
-sb_sasl_drop_packet ( Sockbuf_Buf *sec_buf_in, int debuglevel )
-{
- ber_slen_t len;
-
- len = sec_buf_in->buf_ptr - sec_buf_in->buf_end;
- if ( len > 0 )
- memmove( sec_buf_in->buf_base, sec_buf_in->buf_base +
- sec_buf_in->buf_end, len );
-
- if ( len >= 4 ) {
- sec_buf_in->buf_end = sb_sasl_pkt_length( sec_buf_in->buf_base,
- debuglevel);
- }
- else {
- sec_buf_in->buf_end = 0;
- }
- sec_buf_in->buf_ptr = len;
-}
-
-static ber_slen_t
-sb_sasl_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
-{
- struct sb_sasl_data *p;
- ber_slen_t ret, bufptr;
-
- assert( sbiod != NULL );
- assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
-
- p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
-
- /* Are there anything left in the buffer? */
- ret = ber_pvt_sb_copy_out( &p->buf_in, buf, len );
- bufptr = ret;
- len -= ret;
-
- if ( len == 0 )
- return bufptr;
-
- ber_pvt_sb_buf_destroy( &p->buf_in );
-
- /* Read the length of the packet */
- while ( p->sec_buf_in.buf_ptr < 4 ) {
- ret = LBER_SBIOD_READ_NEXT( sbiod, p->sec_buf_in.buf_base,
- 4 - p->sec_buf_in.buf_ptr );
-#ifdef EINTR
- if ( ( ret < 0 ) && ( errno == EINTR ) )
- continue;
-#endif
- if ( ret <= 0 )
- return ret;
-
- p->sec_buf_in.buf_ptr += ret;
- }
-
- /* The new packet always starts at p->sec_buf_in.buf_base */
- ret = sb_sasl_pkt_length( p->sec_buf_in.buf_base,
- sbiod->sbiod_sb->sb_debug );
-
- /* Grow the packet buffer if neccessary */
- if ( ( p->sec_buf_in.buf_size < ret ) &&
- ber_pvt_sb_grow_buffer( &p->sec_buf_in, ret ) < 0 ) {
- errno = ENOMEM;
- return -1;
- }
- p->sec_buf_in.buf_end = ret;
-
- /* Did we read the whole encrypted packet? */
- while ( p->sec_buf_in.buf_ptr < p->sec_buf_in.buf_end ) {
- /* No, we have got only a part of it */
- ret = p->sec_buf_in.buf_end - p->sec_buf_in.buf_ptr;
-
- ret = LBER_SBIOD_READ_NEXT( sbiod, p->sec_buf_in.buf_base +
- p->sec_buf_in.buf_ptr, ret );
-#ifdef EINTR
- if ( ( ret < 0 ) && ( errno == EINTR ) )
- continue;
-#endif
- if ( ret <= 0 )
- return ret;
-
- p->sec_buf_in.buf_ptr += ret;
- }
-
- /* Decode the packet */
- ret = sasl_decode( p->sasl_context, p->sec_buf_in.buf_base,
- p->sec_buf_in.buf_end, &p->buf_in.buf_base,
- (unsigned *)&p->buf_in.buf_end );
- if ( ret != SASL_OK ) {
- ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug,
- "sb_sasl_read: failed to decode packet: %s\n",
- sasl_errstring( ret, NULL, NULL ) );
- sb_sasl_drop_packet( &p->sec_buf_in,
- sbiod->sbiod_sb->sb_debug );
- errno = EIO;
- return -1;
- }
-
- /* Drop the packet from the input buffer */
- sb_sasl_drop_packet( &p->sec_buf_in, sbiod->sbiod_sb->sb_debug );
-
- p->buf_in.buf_size = p->buf_in.buf_end;
-
- bufptr += ber_pvt_sb_copy_out( &p->buf_in, (char*) buf + bufptr, len );
-
- return bufptr;
-}
-
-static ber_slen_t
-sb_sasl_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
-{
- struct sb_sasl_data *p;
- int ret;
-
- assert( sbiod != NULL );
- assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
-
- p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
-
- /* Are there anything left in the buffer? */
- if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) {
- ret = ber_pvt_sb_do_write( sbiod, &p->buf_out );
- if ( ret <= 0 )
- return ret;
- }
-
- /* now encode the next packet. */
- ber_pvt_sb_buf_destroy( &p->buf_out );
- ret = sasl_encode( p->sasl_context, buf, len, &p->buf_out.buf_base,
- (unsigned *)&p->buf_out.buf_size );
- if ( ret != SASL_OK ) {
- ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug,
- "sb_sasl_write: failed to encode packet: %s\n",
- sasl_errstring( ret, NULL, NULL ) );
- return -1;
- }
- p->buf_out.buf_end = p->buf_out.buf_size;
-
- ret = ber_pvt_sb_do_write( sbiod, &p->buf_out );
- if ( ret <= 0 )
- return ret;
- return len;
-}
-
-static int
-sb_sasl_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
-{
- struct sb_sasl_data *p;
-
- p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
-
- if ( opt == LBER_SB_OPT_DATA_READY ) {
- if ( p->buf_in.buf_ptr != p->buf_in.buf_end )
- return 1;
- }
-
- return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
-}
-
-Sockbuf_IO ldap_pvt_sockbuf_io_sasl =
-{
- sb_sasl_setup, /* sbi_setup */
- sb_sasl_remove, /* sbi_remove */
- sb_sasl_ctrl, /* sbi_ctrl */
- sb_sasl_read, /* sbi_read */
- sb_sasl_write, /* sbi_write */
- NULL /* sbi_close */
-};
-
-int ldap_pvt_sasl_install( Sockbuf *sb, void *ctx_arg )
-{
- /* don't install the stuff unless security has been negotiated */
-
- if ( !ber_sockbuf_ctrl( sb, LBER_SB_OPT_HAS_IO,
- &ldap_pvt_sockbuf_io_sasl ) )
- ber_sockbuf_add_io( sb, &ldap_pvt_sockbuf_io_sasl,
- LBER_SBIOD_LEVEL_APPLICATION, ctx_arg );
-
- return LDAP_SUCCESS;
-}
-
-static int
-sasl_err2ldap( int saslerr )
-{
- int rc;
-
- switch (saslerr) {
- case SASL_CONTINUE:
- rc = LDAP_MORE_RESULTS_TO_RETURN;
- break;
- case SASL_OK:
- rc = LDAP_SUCCESS;
- break;
- case SASL_FAIL:
- rc = LDAP_LOCAL_ERROR;
- break;
- case SASL_NOMEM:
- rc = LDAP_NO_MEMORY;
- break;
- case SASL_NOMECH:
- rc = LDAP_AUTH_UNKNOWN;
- break;
- case SASL_BADAUTH:
- rc = LDAP_AUTH_UNKNOWN;
- break;
- case SASL_NOAUTHZ:
- rc = LDAP_PARAM_ERROR;
- break;
- case SASL_TOOWEAK:
- case SASL_ENCRYPT:
- rc = LDAP_AUTH_UNKNOWN;
- break;
- default:
- rc = LDAP_LOCAL_ERROR;
- break;
- }
-
- assert( rc == LDAP_SUCCESS || LDAP_API_ERROR( rc ) );
- return rc;