+static int
+update_flags( Sockbuf *sb, SSL * ssl, int rc )
+{
+ int err = SSL_get_error(ssl, rc);
+
+ sb->sb_trans_needs_read = 0;
+ sb->sb_trans_needs_write = 0;
+ if (err == SSL_ERROR_WANT_READ)
+ {
+ sb->sb_trans_needs_read = 1;
+ return 1;
+ } else if (err == SSL_ERROR_WANT_WRITE)
+ {
+ sb->sb_trans_needs_write = 1;
+ return 1;
+ } else if (err == SSL_ERROR_WANT_CONNECT)
+ {
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * TLS support for LBER Sockbufs
+ */
+
+struct tls_data {
+ SSL *ssl;
+ Sockbuf_IO_Desc *sbiod;
+};
+
+extern BIO_METHOD ldap_pvt_sb_bio_method;
+
+static int
+sb_tls_setup( Sockbuf_IO_Desc *sbiod, void *arg )
+{
+ struct tls_data *p;
+ BIO *bio;
+
+ assert( sbiod != NULL );
+
+ p = LBER_MALLOC( sizeof( *p ) );
+ if ( p == NULL )
+ return -1;
+
+ p->ssl = (SSL *)arg;
+ p->sbiod = sbiod;
+ bio = BIO_new( &ldap_pvt_sb_bio_method );
+ bio->ptr = (void *)p;
+ SSL_set_bio( p->ssl, bio, bio );
+ sbiod->sbiod_pvt = p;
+ return 0;
+}
+
+static int
+sb_tls_remove( Sockbuf_IO_Desc *sbiod )
+{
+ struct tls_data *p;
+
+ assert( sbiod != NULL );
+ assert( sbiod->sbiod_pvt != NULL );
+
+ p = (struct tls_data *)sbiod->sbiod_pvt;
+ SSL_free( p->ssl );
+ LBER_FREE( sbiod->sbiod_pvt );
+ sbiod->sbiod_pvt = NULL;
+ return 0;
+}
+
+static int
+sb_tls_close( Sockbuf_IO_Desc *sbiod )
+{
+ struct tls_data *p;
+
+ assert( sbiod != NULL );
+ assert( sbiod->sbiod_pvt != NULL );
+
+ p = (struct tls_data *)sbiod->sbiod_pvt;
+ SSL_shutdown( p->ssl );
+ return 0;
+}
+
+static int
+sb_tls_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
+{
+ struct tls_data *p;
+
+ assert( sbiod != NULL );
+ assert( sbiod->sbiod_pvt != NULL );
+
+ p = (struct tls_data *)sbiod->sbiod_pvt;
+
+ if ( opt == LBER_SB_OPT_GET_SSL ) {
+ *((SSL **)arg) = p->ssl;
+ return 1;
+
+ } else if ( opt == LBER_SB_OPT_DATA_READY ) {
+ if( SSL_pending( p->ssl ) > 0 ) {
+ return 1;
+ }
+ }
+
+ return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
+}
+
+static ber_slen_t
+sb_tls_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
+{
+ struct tls_data *p;
+ ber_slen_t ret;
+ int err;
+
+ assert( sbiod != NULL );
+ assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
+
+ p = (struct tls_data *)sbiod->sbiod_pvt;
+
+ ret = SSL_read( p->ssl, (char *)buf, len );
+#ifdef HAVE_WINSOCK
+ errno = WSAGetLastError();
+#endif
+ err = SSL_get_error( p->ssl, ret );
+ if (err == SSL_ERROR_WANT_READ ) {
+ sbiod->sbiod_sb->sb_trans_needs_read = 1;
+#ifdef WIN32
+ errno = EWOULDBLOCK;
+#endif
+ }
+ else
+ sbiod->sbiod_sb->sb_trans_needs_read = 0;
+ return ret;
+}
+
+static ber_slen_t
+sb_tls_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
+{
+ struct tls_data *p;
+ ber_slen_t ret;
+ int err;
+
+ assert( sbiod != NULL );
+ assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
+
+ p = (struct tls_data *)sbiod->sbiod_pvt;
+
+ ret = SSL_write( p->ssl, (char *)buf, len );
+#ifdef HAVE_WINSOCK
+ errno = WSAGetLastError();
+#endif
+ err = SSL_get_error( p->ssl, ret );
+ if (err == SSL_ERROR_WANT_WRITE ) {
+ sbiod->sbiod_sb->sb_trans_needs_write = 1;
+#ifdef WIN32
+ errno = EWOULDBLOCK;
+#endif
+ }
+ else
+ sbiod->sbiod_sb->sb_trans_needs_write = 0;
+ return ret;
+}
+
+Sockbuf_IO ldap_pvt_sockbuf_io_tls =