--- libraries/libldap/sasl.c 2001/07/06 01:13:43 1.36
+++ libraries/libldap/sasl.c 2009/01/21 23:40:21 1.73
@@ -1,7 +1,16 @@
-/* $OpenLDAP: pkg/ldap/libraries/libldap/sasl.c,v 1.35 2001/06/14 22:14:56 kurt Exp $ */
-/*
- * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
- * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+/* $OpenLDAP: pkg/ldap/libraries/libldap/sasl.c,v 1.72 2008/10/09 09:33:49 hyc Exp $ */
+/* This work is part of OpenLDAP Software .
+ *
+ * Copyright 1998-2009 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * .
*/
/*
@@ -10,10 +19,8 @@
* name DistinguishedName, -- who
* authentication CHOICE {
* simple [0] OCTET STRING -- passwd
-#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
- * krbv42ldap [1] OCTET STRING
- * krbv42dsa [2] OCTET STRING
-#endif
+ * krbv42ldap [1] OCTET STRING -- OBSOLETE
+ * krbv42dsa [2] OCTET STRING -- OBSOLETE
* sasl [3] SaslCredentials -- LDAPv3
* }
* }
@@ -27,10 +34,10 @@
#include "portable.h"
-#include
#include
#include
+#include
#include
#include
#include
@@ -60,6 +67,7 @@ ldap_sasl_bind(
{
BerElement *ber;
int rc;
+ ber_int_t id;
Debug( LDAP_DEBUG_TRACE, "ldap_sasl_bind\n", 0, 0, 0 );
@@ -71,13 +79,8 @@ ldap_sasl_bind(
rc = ldap_int_client_controls( ld, cctrls );
if( rc != LDAP_SUCCESS ) return rc;
- if( msgidp == NULL ) {
- ld->ld_errno = LDAP_PARAM_ERROR;
- return ld->ld_errno;
- }
-
if( mechanism == LDAP_SASL_SIMPLE ) {
- if( dn == NULL && cred != NULL ) {
+ if( dn == NULL && cred != NULL && cred->bv_len ) {
/* use default binddn */
dn = ld->ld_defbinddn;
}
@@ -97,26 +100,27 @@ ldap_sasl_bind(
return ld->ld_errno;
}
- assert( BER_VALID( ber ) );
+ assert( LBER_VALID( ber ) );
+ LDAP_NEXT_MSGID( ld, id );
if( mechanism == LDAP_SASL_SIMPLE ) {
/* simple bind */
rc = ber_printf( ber, "{it{istON}" /*}*/,
- ++ld->ld_msgid, LDAP_REQ_BIND,
+ id, LDAP_REQ_BIND,
ld->ld_version, dn, LDAP_AUTH_SIMPLE,
cred );
- } else if ( cred == NULL || !cred->bv_len ) {
- /* SASL bind w/o creditials */
+ } else if ( cred == NULL || cred->bv_val == NULL ) {
+ /* SASL bind w/o credentials */
rc = ber_printf( ber, "{it{ist{sN}N}" /*}*/,
- ++ld->ld_msgid, LDAP_REQ_BIND,
+ id, LDAP_REQ_BIND,
ld->ld_version, dn, LDAP_AUTH_SASL,
mechanism );
} else {
- /* SASL bind w/ creditials */
+ /* SASL bind w/ credentials */
rc = ber_printf( ber, "{it{ist{sON}N}" /*}*/,
- ++ld->ld_msgid, LDAP_REQ_BIND,
+ id, LDAP_REQ_BIND,
ld->ld_version, dn, LDAP_AUTH_SASL,
mechanism, cred );
}
@@ -139,14 +143,9 @@ ldap_sasl_bind(
return ld->ld_errno;
}
-#ifndef LDAP_NOCACHE
- if ( ld->ld_cache != NULL ) {
- ldap_flush_cache( ld );
- }
-#endif /* !LDAP_NOCACHE */
/* send the message */
- *msgidp = ldap_send_initial_request( ld, LDAP_REQ_BIND, dn, ber );
+ *msgidp = ldap_send_initial_request( ld, LDAP_REQ_BIND, dn, ber, id );
if(*msgidp < 0)
return ld->ld_errno;
@@ -186,7 +185,13 @@ ldap_sasl_bind_s(
return( rc );
}
- if ( ldap_result( ld, msgid, 1, NULL, &result ) == -1 ) {
+#ifdef LDAP_CONNECTIONLESS
+ if (LDAP_IS_UDP(ld)) {
+ return( rc );
+ }
+#endif
+
+ if ( ldap_result( ld, msgid, LDAP_MSG_ALL, NULL, &result ) == -1 || !result ) {
return( ld->ld_errno ); /* ldap_result sets ld_errno */
}
@@ -196,7 +201,7 @@ ldap_sasl_bind_s(
rc = ldap_parse_sasl_bind_result( ld, result, &scredp, 0 );
}
- if ( rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS ) {
+ if ( rc != LDAP_SUCCESS ) {
ldap_msgfree( result );
return( rc );
}
@@ -251,10 +256,6 @@ ldap_parse_sasl_bind_result(
assert( LDAP_VALID( ld ) );
assert( res != NULL );
- if ( ld == NULL || res == NULL ) {
- return LDAP_PARAM_ERROR;
- }
-
if( servercredp != NULL ) {
if( ld->ld_version < LDAP_VERSION2 ) {
return LDAP_NOT_SUPPORTED;
@@ -288,7 +289,7 @@ ldap_parse_sasl_bind_result(
}
if ( ld->ld_version < LDAP_VERSION2 ) {
- tag = ber_scanf( ber, "{ia}",
+ tag = ber_scanf( ber, "{iA}",
&errcode, &ld->ld_error );
if( tag == LBER_ERROR ) {
@@ -300,7 +301,7 @@ ldap_parse_sasl_bind_result(
} else {
ber_len_t len;
- tag = ber_scanf( ber, "{iaa" /*}*/,
+ tag = ber_scanf( ber, "{eAA" /*}*/,
&errcode, &ld->ld_matched, &ld->ld_error );
if( tag == LBER_ERROR ) {
@@ -346,7 +347,7 @@ ldap_parse_sasl_bind_result(
ldap_msgfree( res );
}
- return( ld->ld_errno );
+ return( LDAP_SUCCESS );
}
int
@@ -419,29 +420,44 @@ ldap_sasl_interactive_bind_s(
void *defaults )
{
int rc;
+ char *smechs = NULL;
#if defined( LDAP_R_COMPILE ) && defined( HAVE_CYRUS_SASL )
ldap_pvt_thread_mutex_lock( &ldap_int_sasl_mutex );
#endif
+#ifdef LDAP_CONNECTIONLESS
+ if( LDAP_IS_UDP(ld) ) {
+ /* Just force it to simple bind, silly to make the user
+ * ask all the time. No, we don't ever actually bind, but I'll
+ * let the final bind handler take care of saving the cdn.
+ */
+ rc = ldap_simple_bind( ld, dn, NULL );
+ rc = rc < 0 ? rc : 0;
+ goto done;
+ } else
+#endif
+#ifdef HAVE_CYRUS_SASL
+ if( mechs == NULL || *mechs == '\0' ) {
+ mechs = ld->ld_options.ldo_def_sasl_mech;
+ }
+#endif
+
if( mechs == NULL || *mechs == '\0' ) {
- char *smechs;
-
rc = ldap_pvt_sasl_getmechs( ld, &smechs );
-
if( rc != LDAP_SUCCESS ) {
goto done;
}
Debug( LDAP_DEBUG_TRACE,
- "ldap_interactive_sasl_bind_s: server supports: %s\n",
+ "ldap_sasl_interactive_bind_s: server supports: %s\n",
smechs, 0, 0 );
mechs = smechs;
} else {
Debug( LDAP_DEBUG_TRACE,
- "ldap_interactive_sasl_bind_s: user selected: %s\n",
+ "ldap_sasl_interactive_bind_s: user selected: %s\n",
mechs, 0, 0 );
}
@@ -453,6 +469,309 @@ done:
#if defined( LDAP_R_COMPILE ) && defined( HAVE_CYRUS_SASL )
ldap_pvt_thread_mutex_unlock( &ldap_int_sasl_mutex );
#endif
+ if ( smechs ) LDAP_FREE( smechs );
return rc;
}
+
+#ifdef HAVE_CYRUS_SASL
+
+#ifdef HAVE_SASL_SASL_H
+#include
+#else
+#include
+#endif
+
+#endif /* HAVE_CYRUS_SASL */
+
+static int
+sb_sasl_generic_remove( Sockbuf_IO_Desc *sbiod );
+
+static int
+sb_sasl_generic_setup( Sockbuf_IO_Desc *sbiod, void *arg )
+{
+ struct sb_sasl_generic_data *p;
+ struct sb_sasl_generic_install *i;
+
+ assert( sbiod != NULL );
+
+ i = (struct sb_sasl_generic_install *)arg;
+
+ p = LBER_MALLOC( sizeof( *p ) );
+ if ( p == NULL )
+ return -1;
+ p->ops = i->ops;
+ p->ops_private = i->ops_private;
+ p->sbiod = sbiod;
+ 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 );
+
+ sbiod->sbiod_pvt = p;
+
+ p->ops->init( p, &p->min_send, &p->max_send, &p->max_recv );
+
+ if ( ber_pvt_sb_grow_buffer( &p->sec_buf_in, p->min_send ) < 0 ) {
+ sb_sasl_generic_remove( sbiod );
+ sock_errset(ENOMEM);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+sb_sasl_generic_remove( Sockbuf_IO_Desc *sbiod )
+{
+ struct sb_sasl_generic_data *p;
+
+ assert( sbiod != NULL );
+
+ p = (struct sb_sasl_generic_data *)sbiod->sbiod_pvt;
+
+ p->ops->fini(p);
+
+ 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_generic_pkt_length(
+ struct sb_sasl_generic_data *p,
+ const unsigned char *buf,
+ int debuglevel )
+{
+ ber_len_t size;
+
+ assert( buf != NULL );
+
+ size = buf[0] << 24
+ | buf[1] << 16
+ | buf[2] << 8
+ | buf[3];
+
+ if ( size > p->max_recv ) {
+ /* somebody is trying to mess me up. */
+ ber_log_printf( LDAP_DEBUG_ANY, debuglevel,
+ "sb_sasl_generic_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_generic_drop_packet (
+ struct sb_sasl_generic_data *p,
+ int debuglevel )
+{
+ ber_slen_t len;
+
+ len = p->sec_buf_in.buf_ptr - p->sec_buf_in.buf_end;
+ if ( len > 0 )
+ AC_MEMCPY( p->sec_buf_in.buf_base, p->sec_buf_in.buf_base +
+ p->sec_buf_in.buf_end, len );
+
+ if ( len >= 4 ) {
+ p->sec_buf_in.buf_end = sb_sasl_generic_pkt_length(p,
+ (unsigned char *) p->sec_buf_in.buf_base, debuglevel);
+ }
+ else {
+ p->sec_buf_in.buf_end = 0;
+ }
+ p->sec_buf_in.buf_ptr = len;
+}
+
+static ber_slen_t
+sb_sasl_generic_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
+{
+ struct sb_sasl_generic_data *p;
+ ber_slen_t ret, bufptr;
+
+ assert( sbiod != NULL );
+ assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
+
+ p = (struct sb_sasl_generic_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;
+
+ p->ops->reset_buf( p, &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 +
+ p->sec_buf_in.buf_ptr,
+ 4 - p->sec_buf_in.buf_ptr );
+#ifdef EINTR
+ if ( ( ret < 0 ) && ( errno == EINTR ) )
+ continue;
+#endif
+ if ( ret <= 0 )
+ return bufptr ? bufptr : ret;
+
+ p->sec_buf_in.buf_ptr += ret;
+ }
+
+ /* The new packet always starts at p->sec_buf_in.buf_base */
+ ret = sb_sasl_generic_pkt_length(p, (unsigned char *) p->sec_buf_in.buf_base,
+ sbiod->sbiod_sb->sb_debug );
+
+ /* Grow the packet buffer if neccessary */
+ if ( ( p->sec_buf_in.buf_size < (ber_len_t) ret ) &&
+ ber_pvt_sb_grow_buffer( &p->sec_buf_in, ret ) < 0 )
+ {
+ sock_errset(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 bufptr ? bufptr : ret;
+
+ p->sec_buf_in.buf_ptr += ret;
+ }
+
+ /* Decode the packet */
+ ret = p->ops->decode( p, &p->sec_buf_in, &p->buf_in );
+
+ /* Drop the packet from the input buffer */
+ sb_sasl_generic_drop_packet( p, sbiod->sbiod_sb->sb_debug );
+
+ if ( ret != 0 ) {
+ ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug,
+ "sb_sasl_generic_read: failed to decode packet\n" );
+ sock_errset(EIO);
+ return -1;
+ }
+
+ bufptr += ber_pvt_sb_copy_out( &p->buf_in, (char*) buf + bufptr, len );
+
+ return bufptr;
+}
+
+static ber_slen_t
+sb_sasl_generic_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
+{
+ struct sb_sasl_generic_data *p;
+ int ret;
+
+ assert( sbiod != NULL );
+ assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
+
+ p = (struct sb_sasl_generic_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;
+
+ /* Still have something left?? */
+ if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) {
+ sock_errset(EAGAIN);
+ return -1;
+ }
+ }
+
+ /* now encode the next packet. */
+ p->ops->reset_buf( p, &p->buf_out );
+
+ if ( len > p->max_send - 100 ) {
+ len = p->max_send - 100; /* For safety margin */
+ }
+
+ ret = p->ops->encode( p, buf, len, &p->buf_out );
+
+ if ( ret != 0 ) {
+ ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug,
+ "sb_sasl_generic_write: failed to encode packet\n" );
+ sock_errset(EIO);
+ return -1;
+ }
+
+ ret = ber_pvt_sb_do_write( sbiod, &p->buf_out );
+
+ /* return number of bytes encoded, not written, to ensure
+ * no byte is encoded twice (even if only sent once).
+ */
+ return len;
+}
+
+static int
+sb_sasl_generic_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
+{
+ struct sb_sasl_generic_data *p;
+
+ p = (struct sb_sasl_generic_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_generic = {
+ sb_sasl_generic_setup, /* sbi_setup */
+ sb_sasl_generic_remove, /* sbi_remove */
+ sb_sasl_generic_ctrl, /* sbi_ctrl */
+ sb_sasl_generic_read, /* sbi_read */
+ sb_sasl_generic_write, /* sbi_write */
+ NULL /* sbi_close */
+};
+
+int ldap_pvt_sasl_generic_install(
+ Sockbuf *sb,
+ struct sb_sasl_generic_install *install_arg )
+{
+ Debug( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_generic_install\n",
+ 0, 0, 0 );
+
+ /* 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_generic ) )
+ {
+#ifdef LDAP_DEBUG
+ ber_sockbuf_add_io( sb, &ber_sockbuf_io_debug,
+ LBER_SBIOD_LEVEL_APPLICATION, (void *)"sasl_generic_" );
+#endif
+ ber_sockbuf_add_io( sb, &ldap_pvt_sockbuf_io_sasl_generic,
+ LBER_SBIOD_LEVEL_APPLICATION, install_arg );
+ }
+
+ return LDAP_SUCCESS;
+}
+
+void ldap_pvt_sasl_generic_remove( Sockbuf *sb )
+{
+ ber_sockbuf_remove_io( sb, &ldap_pvt_sockbuf_io_sasl_generic,
+ LBER_SBIOD_LEVEL_APPLICATION );
+#ifdef LDAP_DEBUG
+ ber_sockbuf_remove_io( sb, &ber_sockbuf_io_debug,
+ LBER_SBIOD_LEVEL_APPLICATION );
+#endif
+}