getdn.c getentry.c getattr.c getvalues.c addentry.c \
        request.c os-ip.c url.c pagectrl.c sortctrl.c vlvctrl.c \
        init.c options.c print.c string.c util-int.c schema.c \
-       charray.c tls.c os-local.c dnssrv.c utf-8.c utf-8-conv.c \
+       charray.c os-local.c dnssrv.c utf-8.c utf-8-conv.c \
+       tls2.c tls_o.c tls_g.c tls_m.c \
        turn.c ppolicy.c dds.c txn.c ldap_sync.c stctrl.c \
        assertion.c deref.c
 
        getdn.lo getentry.lo getattr.lo getvalues.lo addentry.lo \
        request.lo os-ip.lo url.lo pagectrl.lo sortctrl.lo vlvctrl.lo \
        init.lo options.lo print.lo string.lo util-int.lo schema.lo \
-       charray.lo tls.lo os-local.lo dnssrv.lo utf-8.lo utf-8-conv.lo \
+       charray.lo os-local.lo dnssrv.lo utf-8.lo utf-8-conv.lo \
+       tls2.lo tls_o.lo tls_g.lo tls_m.lo \
        turn.lo ppolicy.lo dds.lo txn.lo ldap_sync.lo stctrl.lo \
        assertion.lo deref.lo
 
 
 
 struct tls_impl;
 
-typedef struct tls_ctx {
-       struct tls_impl *tc_impl;
-} tls_ctx;
+struct tls_ctx;
+struct tls_session;
 
-typedef struct tls_session {
-       struct tls_impl *ts_impl;
-       void *ts_session;
-} tls_session;
+typedef struct tls_ctx tls_ctx;
+typedef struct tls_session tls_session;
 
 typedef int (TI_tls_init)(void);
 typedef void (TI_tls_destroy)(void);
        int ti_inited;
 } tls_impl;
 
+extern tls_impl ldap_int_tls_impl;
+
 #endif /* _LDAP_TLS_H */
 
 #include <ldap_pvt_thread.h>
 #endif
 
-#ifdef HAVE_GNUTLS
-extern tls_impl ldap_int_gnutls_impl;
-#endif
-
-#ifdef HAVE_OPENSSL
-extern tls_impl ldap_int_openssl_impl;
-#endif
-
-#ifdef HAVE_MOZNSS
-extern tls_impl ldap_int_moznss_impl;
-#endif
-
-static tls_impl *tls_impls[] = {
-#ifdef HAVE_OPENSSL
-       &ldap_int_openssl_impl,
-#endif
-#ifdef HAVE_GNUTLS
-       &ldap_int_gnutls_impl,
-#endif
-#ifdef HAVE_MOZNSS
-       &ldap_int_moznss_impl,
-#endif
-       NULL
-};
+static tls_impl *tls_imp = &ldap_int_tls_impl;
 
 #endif /* HAVE_TLS */
 
 void
 ldap_pvt_tls_ctx_free ( void *c )
 {
-       tls_ctx *ctx = c;
-
-       if ( !ctx ) return;
-
-       ctx->tc_impl->ti_ctx_free( ctx );
+       if ( !c ) return;
+       tls_imp->ti_ctx_free( c );
 }
 
 static void
 {
        if ( !ctx ) return;
 
-       ctx->tc_impl->ti_ctx_ref( ctx );
+       tls_imp->ti_ctx_ref( ctx );
 }
 
 #ifdef LDAP_R_COMPILE
 
        ldap_int_tls_destroy( lo );
 
-       for ( i=0; tls_impls[i]; i++ ) {
-               if ( tls_impls[i]->ti_inited ) {
-                       tls_impls[i]->ti_tls_destroy();
-               }
-       }
+       tls_imp->ti_tls_destroy();
 }
 
 /*
 {
        struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT();   
 
-       return tls_init( tls_impls[lo->ldo_tls_impl] );
+       return tls_init( tls_imp );
 }
 
 /*
 ldap_int_tls_init_ctx( struct ldapoptions *lo, int is_server )
 {
        int i, rc = 0;
-       tls_impl *ti = tls_impls[lo->ldo_tls_impl];
+       tls_impl *ti = tls_imp;
        struct ldaptls lts = lo->ldo_tls_info;
 
        if ( lo->ldo_tls_ctx )
                ctx = lo->ldo_tls_ctx;
        }
 
-       ssl = ctx->tc_impl->ti_session_new( ctx, is_server );
+       ssl = tls_imp->ti_session_new( ctx, is_server );
        if ( ssl == NULL ) {
                Debug( LDAP_DEBUG_ANY,"TLS: can't create ssl handle.\n",0,0,0);
                return NULL;
        sb->sb_trans_needs_read  = 0;
        sb->sb_trans_needs_write = 0;
 
-       return ssl->ts_impl->ti_session_upflags( sb, ssl, rc );
+       return tls_imp->ti_session_upflags( sb, ssl, rc );
 }
 
 /*
                ber_sockbuf_add_io( sb, &ber_sockbuf_io_debug,
                        LBER_SBIOD_LEVEL_TRANSPORT, (void *)"tls_" );
 #endif
-               ber_sockbuf_add_io( sb, ssl->ts_impl->ti_sbio,
+               ber_sockbuf_add_io( sb, tls_imp->ti_sbio,
                        LBER_SBIOD_LEVEL_TRANSPORT, (void *)ssl );
 
                lo = LDAP_INT_GLOBAL_OPT();   
                        lo->ldo_tls_connect_cb( ld, ssl, ctx, lo->ldo_tls_connect_arg );
        }
 
-       err = ssl->ts_impl->ti_session_connect( ld, ssl );
+       err = tls_imp->ti_session_connect( ld, ssl );
 
 #ifdef HAVE_WINSOCK
        errno = WSAGetLastError();
                        return 1;
                }
 
-               msg = ssl->ts_impl->ti_session_errmsg( err, buf, sizeof(buf) );
+               msg = tls_imp->ti_session_errmsg( err, buf, sizeof(buf) );
                if ( msg ) {
                        if ( ld->ld_error ) {
                                LDAP_FREE( ld->ld_error );
                Debug( LDAP_DEBUG_ANY,"TLS: can't connect: %s.\n",
                        ld->ld_error ? ld->ld_error : "" ,0,0);
 
-               ber_sockbuf_remove_io( sb, ssl->ts_impl->ti_sbio,
+               ber_sockbuf_remove_io( sb, tls_imp->ti_sbio,
                        LBER_SBIOD_LEVEL_TRANSPORT );
 #ifdef LDAP_DEBUG
                ber_sockbuf_remove_io( sb, &ber_sockbuf_io_debug,
                ber_sockbuf_add_io( sb, &ber_sockbuf_io_debug,
                        LBER_SBIOD_LEVEL_TRANSPORT, (void *)"tls_" );
 #endif
-               ber_sockbuf_add_io( sb, ssl->ts_impl->ti_sbio,
+               ber_sockbuf_add_io( sb, tls_imp->ti_sbio,
                        LBER_SBIOD_LEVEL_TRANSPORT, (void *)ssl );
        }
 
-       err = ssl->ts_impl->ti_session_accept( ssl );
+       err = tls_imp->ti_session_accept( ssl );
 
 #ifdef HAVE_WINSOCK
        errno = WSAGetLastError();
                if ( update_flags( sb, ssl, err )) return 1;
 
                Debug( LDAP_DEBUG_ANY,"TLS: can't accept: %s.\n",
-                       ssl->ts_impl->ti_session_errmsg( err, buf, sizeof(buf) ),0,0 );
+                       tls_imp->ti_session_errmsg( err, buf, sizeof(buf) ),0,0 );
 
-               ber_sockbuf_remove_io( sb, ssl->ts_impl->ti_sbio,
+               ber_sockbuf_remove_io( sb, tls_imp->ti_sbio,
                        LBER_SBIOD_LEVEL_TRANSPORT );
 #ifdef LDAP_DEBUG
                ber_sockbuf_remove_io( sb, &ber_sockbuf_io_debug,
        struct berval bvdn;
        int rc;
 
-       rc = session->ts_impl->ti_session_peer_dn( session, &bvdn );
+       rc = tls_imp->ti_session_peer_dn( session, &bvdn );
        if ( rc ) return rc;
 
        rc = ldap_X509dn2bv( &bvdn, dn, 
 {
        tls_session *session = s;
 
-       return session->ts_impl->ti_session_chkhost( ld, session, name_in );
+       return tls_imp->ti_session_chkhost( ld, session, name_in );
 }
 
 int
                host = "localhost";
        }
 
-       (void) tls_init( tls_impls[ld->ld_options.ldo_tls_impl] );
+       (void) tls_init( tls_imp );
 
        /*
         * Fortunately, the lib uses blocking io...
 {
        tls_session *session = s;
 
-       return session->ts_impl->ti_session_strength( session );
+       return tls_imp->ti_session_strength( session );
 }
 
 
        struct berval der_dn;
        int rc;
 
-       session->ts_impl->ti_session_my_dn( session, &der_dn );
+       tls_imp->ti_session_my_dn( session, &der_dn );
        rc = ldap_X509dn2bv(&der_dn, dn, (LDAPDN_rewrite_func *)func, flags );
        return rc;
 #else /* !HAVE_TLS */
 
 } tls_cipher_suite;
 
 typedef struct tlsg_ctx {
-       tls_impl *tc_impl;
        struct ldapoptions *lo;
        gnutls_certificate_credentials_t cred;
        gnutls_dh_params_t dh_params;
 } tlsg_ctx;
 
 typedef struct tlsg_session {
-       tls_impl *ts_impl;
        gnutls_session_t session;
        tlsg_ctx *ctx;
        struct berval peer_der_dn;
 
 static int tlsg_parse_ciphers( tlsg_ctx *ctx, char *suites );
 static int tlsg_cert_verify( tlsg_session *s );
-extern tls_impl ldap_int_gnutls_impl;
 
 #ifdef LDAP_R_COMPILE
 
                        ber_memfree( ctx );
                        return NULL;
                }
-               ctx->tc_impl = &ldap_int_gnutls_impl;
                ctx->refcount = 1;
 #ifdef LDAP_R_COMPILE
                ldap_pvt_thread_mutex_init( &ctx->ref_mutex );
                return NULL;
 
        session->ctx = c;
-       session->ts_impl = &ldap_int_gnutls_impl;
        gnutls_init( &session->session, is_server ? GNUTLS_SERVER : GNUTLS_CLIENT );
        gnutls_set_default_priority( session->session );
        if ( c->kx_list ) {
        return 0;
 }
 
-tls_impl ldap_int_gnutls_impl = {
+tls_impl ldap_int_tls_impl = {
        "GnuTLS",
 
        tlsg_init,
 
 #include <ssl.h>
 
 typedef struct tlsm_ctx {
-       tls_impl *tc_impl;
        PRFileDesc *tc_model;
        int tc_refcnt;
 #ifdef LDAP_R_COMPILE
 #endif
 } tlsm_ctx;
 
-typedef struct tlsm_session {
-       tls_impl *ts_impl;
-       PRFileDesc *ts_session;
-} tlsm_session;
+typedef PRFileDesc tlsm_session;
 
 static PRDescIdentity  tlsm_layer_id;
 
 static const PRIOMethods tlsm_PR_methods;
 
-extern tls_impl ldap_int_moznss_impl;
+extern tls_impl ldap_int_tls_impl;
 
 #ifdef LDAP_R_COMPILE
 
                if ( fd ) {
                        ctx->tc_model = SSL_ImportFD( NULL, fd );
                        if ( ctx->tc_model ) {
-                               ctx->tc_impl = &ldap_int_moznss_impl;
                                ctx->tc_refcnt = 1;
 #ifdef LDAP_R_COMPILE
                                ldap_pvt_thread_mutex_init( &ctx->tc_refmutex );
        tlsm_session *session;
        PRFileDesc *fd;
 
-       session = LDAP_MALLOC( sizeof (*session) );
-       if ( !session )
-               return NULL;
-
        fd = PR_CreateIOLayerStub(tlsm_layer_id, &tlsm_PR_methods);
        if ( !fd ) {
-               LDAP_FREE( session );
                return NULL;
        }
 
-       session->ts_session = SSL_ImportFD( c->tc_model, fd );
-       if ( !session->ts_session ) {
+       session = SSL_ImportFD( c->tc_model, fd );
+       if ( !session ) {
                PR_DELETE( fd );
-               LDAP_FREE( session );
                return NULL;
        }
 
-       session->ts_impl = &ldap_int_moznss_impl;
-
-       SSL_ResetHandshake( session->ts_session, is_server );
+       SSL_ResetHandshake( session, is_server );
 
        return (tls_session *)session;
 } 
 {
        tlsm_session *s = (tlsm_session *)session;
 
-       return SSL_ForceHandshake( s->ts_session );
+       return SSL_ForceHandshake( s );
 }
 
 static int
        int rc;
 
        /* By default, NSS checks the cert hostname for us */
-       rc = SSL_SetURL( s->ts_session, ld->ld_options.ldo_defludp->lud_host );
-       return SSL_ForceHandshake( s->ts_session );
+       rc = SSL_SetURL( s, ld->ld_options.ldo_defludp->lud_host );
+       return SSL_ForceHandshake( s );
 }
 
 static int
        tlsm_session *s = (tlsm_session *)session;
        CERTCertificate *cert;
 
-       cert = SSL_LocalCertificate( s->ts_session );
+       cert = SSL_LocalCertificate( s );
        if (!cert) return LDAP_INVALID_CREDENTIALS;
 
        der_dn->bv_val = cert->derSubject.data;
        tlsm_session *s = (tlsm_session *)session;
        CERTCertificate *cert;
 
-       cert = SSL_PeerCertificate( s->ts_session );
+       cert = SSL_PeerCertificate( s );
        if (!cert) return LDAP_INVALID_CREDENTIALS;
        
        der_dn->bv_val = cert->derSubject.data;
        tlsm_session *s = (tlsm_session *)session;
        int rc, keySize;
 
-       rc = SSL_SecurityStatus( s->ts_session, NULL, NULL, NULL, &keySize,
+       rc = SSL_SecurityStatus( s, NULL, NULL, NULL, &keySize,
                NULL, NULL );
        return rc ? 0 : keySize;
 }
                return -1;
        }
 
-       fd = PR_GetIdentitiesLayer( session->ts_session, tlsm_layer_id );
+       fd = PR_GetIdentitiesLayer( session, tlsm_layer_id );
        if ( !fd ) {
                LBER_FREE( p );
                return -1;
        assert( sbiod->sbiod_pvt != NULL );
 
        p = (struct tls_data *)sbiod->sbiod_pvt;
-       PR_Close( p->session->ts_session );
-       LBER_FREE( p->session );
+       PR_Close( p->session );
        LBER_FREE( sbiod->sbiod_pvt );
        sbiod->sbiod_pvt = NULL;
        return 0;
        assert( sbiod->sbiod_pvt != NULL );
 
        p = (struct tls_data *)sbiod->sbiod_pvt;
-       PR_Shutdown( p->session->ts_session, PR_SHUTDOWN_BOTH );
+       PR_Shutdown( p->session, PR_SHUTDOWN_BOTH );
        return 0;
 }
 
                return 1;
                
        } else if ( opt == LBER_SB_OPT_DATA_READY ) {
-        PRPollDesc pd = { p->session->ts_session, PR_POLL_READ, 0 };
+        PRPollDesc pd = { p->session, PR_POLL_READ, 0 };
         if( PR_Poll( &pd, 1, 1 ) > 0 ) {
             return 1;
                }
 
        p = (struct tls_data *)sbiod->sbiod_pvt;
 
-       ret = PR_Recv( p->session->ts_session, buf, len, 0, PR_INTERVAL_NO_TIMEOUT );
+       ret = PR_Recv( p->session, buf, len, 0, PR_INTERVAL_NO_TIMEOUT );
        if ( ret < 0 ) {
                err = PR_GetError();
                if ( err == PR_PENDING_INTERRUPT_ERROR || err == PR_WOULD_BLOCK_ERROR ) {
 
        p = (struct tls_data *)sbiod->sbiod_pvt;
 
-       ret = PR_Send( p->session->ts_session, (char *)buf, len, 0, PR_INTERVAL_NO_TIMEOUT );
+       ret = PR_Send( p->session, (char *)buf, len, 0, PR_INTERVAL_NO_TIMEOUT );
        if ( ret < 0 ) {
                err = PR_GetError();
                if ( err == PR_PENDING_INTERRUPT_ERROR || err == PR_WOULD_BLOCK_ERROR ) {
 
 #include <ssl.h>
 #endif
 
-typedef struct tlso_ctx {
-       tls_impl *tc_impl;
-       SSL_CTX *tc_ctx;
-       int tc_refcnt;
-} tlso_ctx;
-
-typedef struct tlso_session {
-       tls_impl *ts_impl;
-       SSL *ts_session;
-} tlso_session;
-
-extern tls_impl ldap_int_openssl_impl;
+typedef SSL_CTX tlso_ctx;
+typedef SSL tlso_session;
 
 static int  tlso_opt_trace = 1;
 
 static tls_ctx *
 tlso_ctx_new( struct ldapoptions *lo )
 {
-       tlso_ctx *ctx = LDAP_MALLOC( sizeof(tlso_ctx) );
-       if ( ctx ) {
-               ctx->tc_ctx = SSL_CTX_new( SSLv23_method() );
-               if ( ctx->tc_ctx ) {
-                       ctx->tc_impl = &ldap_int_openssl_impl;
-                       ctx->tc_refcnt = 1;
-               } else {
-                       LDAP_FREE( ctx );
-                       ctx = NULL;
-               }
-       }
-       return (tls_ctx *)ctx;
+       return (tls_ctx *) SSL_CTX_new( SSLv23_method() );
 }
 
 static void
 tlso_ctx_ref( tls_ctx *ctx )
 {
        tlso_ctx *c = (tlso_ctx *)ctx;
-       c->tc_refcnt++;
+       CRYPTO_add( &c->references, 1, CRYPTO_LOCK_SSL_CTX );
 }
 
 static void
 tlso_ctx_free ( tls_ctx *ctx )
 {
        tlso_ctx *c = (tlso_ctx *)ctx;
-       c->tc_refcnt--;
-       if ( c->tc_refcnt < 1 ) {
-               SSL_CTX_free( c->tc_ctx );
-               LDAP_FREE( c );
-       }
+       SSL_CTX_free( c );
 }
 
 /*
 static int
 tlso_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server )
 {
-       tlso_ctx *tc = (tlso_ctx *)lo->ldo_tls_ctx;
-       SSL_CTX *ctx = tc->tc_ctx;
+       tlso_ctx *ctx = (tlso_ctx *)lo->ldo_tls_ctx;
        int i;
 
        if ( is_server ) {
 tlso_session_new( tls_ctx *ctx, int is_server )
 {
        tlso_ctx *c = (tlso_ctx *)ctx;
-       tlso_session *s = LDAP_MALLOC( sizeof(tlso_session));
-       if ( s ) {
-               s->ts_session = SSL_new( c->tc_ctx );
-               if ( s->ts_session ) {
-                       s->ts_impl = &ldap_int_openssl_impl;
-               } else {
-                       LDAP_FREE( s );
-                       s = NULL;
-               }
-       }
-       return (tls_session *)s;
+       return (tls_session *)SSL_new( c );
 }
 
 static int
        tlso_session *s = (tlso_session *)sess;
 
        /* Caller expects 0 = success, OpenSSL returns 1 = success */
-       return SSL_connect( s->ts_session ) - 1;
+       return SSL_connect( s ) - 1;
 }
 
 static int
        tlso_session *s = (tlso_session *)sess;
 
        /* Caller expects 0 = success, OpenSSL returns 1 = success */
-       return SSL_accept( s->ts_session ) - 1;
+       return SSL_accept( s ) - 1;
 }
 
 static int
        tlso_session *s = (tlso_session *)sess;
 
        /* 1 was subtracted above, offset it back now */
-       rc = SSL_get_error(s->ts_session, rc+1);
+       rc = SSL_get_error(s, rc+1);
        if (rc == SSL_ERROR_WANT_READ) {
                sb->sb_trans_needs_read  = 1;
                return 1;
        X509 *x;
        X509_NAME *xn;
 
-       x = SSL_get_certificate( s->ts_session );
+       x = SSL_get_certificate( s );
 
        if (!x) return LDAP_INVALID_CREDENTIALS;
        
 tlso_session_peer_dn( tls_session *sess, struct berval *der_dn )
 {
        tlso_session *s = (tlso_session *)sess;
-       X509 *x = tlso_get_cert( s->ts_session );
+       X509 *x = tlso_get_cert( s );
        X509_NAME *xn;
 
        if ( !x )
                name = name_in;
        }
 
-       x = tlso_get_cert(s->ts_session);
+       x = tlso_get_cert(s);
        if (!x) {
                Debug( LDAP_DEBUG_ANY,
                        "TLS: unable to get peer certificate.\n",
        tlso_session *s = (tlso_session *)sess;
        SSL_CIPHER *c;
 
-       c = SSL_get_current_cipher(s->ts_session);
+       c = SSL_get_current_cipher(s);
        return SSL_CIPHER_get_bits(c, NULL);
 }
 
        p->sbiod = sbiod;
        bio = BIO_new( &tlso_bio_method );
        bio->ptr = (void *)p;
-       SSL_set_bio( p->session->ts_session, bio, bio );
+       SSL_set_bio( p->session, bio, bio );
        sbiod->sbiod_pvt = p;
        return 0;
 }
        assert( sbiod->sbiod_pvt != NULL );
 
        p = (struct tls_data *)sbiod->sbiod_pvt;
-       SSL_free( p->session->ts_session );
-       LDAP_FREE( p->session );
+       SSL_free( p->session );
        LBER_FREE( sbiod->sbiod_pvt );
        sbiod->sbiod_pvt = NULL;
        return 0;
        assert( sbiod->sbiod_pvt != NULL );
 
        p = (struct tls_data *)sbiod->sbiod_pvt;
-       SSL_shutdown( p->session->ts_session );
+       SSL_shutdown( p->session );
        return 0;
 }
 
                return 1;
 
        } else if ( opt == LBER_SB_OPT_DATA_READY ) {
-               if( SSL_pending( p->session->ts_session ) > 0 ) {
+               if( SSL_pending( p->session ) > 0 ) {
                        return 1;
                }
        }
 
        p = (struct tls_data *)sbiod->sbiod_pvt;
 
-       ret = SSL_read( p->session->ts_session, (char *)buf, len );
+       ret = SSL_read( p->session, (char *)buf, len );
 #ifdef HAVE_WINSOCK
        errno = WSAGetLastError();
 #endif
-       err = SSL_get_error( p->session->ts_session, ret );
+       err = SSL_get_error( p->session, ret );
        if (err == SSL_ERROR_WANT_READ ) {
                sbiod->sbiod_sb->sb_trans_needs_read = 1;
                sock_errset(EWOULDBLOCK);
 
        p = (struct tls_data *)sbiod->sbiod_pvt;
 
-       ret = SSL_write( p->session->ts_session, (char *)buf, len );
+       ret = SSL_write( p->session, (char *)buf, len );
 #ifdef HAVE_WINSOCK
        errno = WSAGetLastError();
 #endif
-       err = SSL_get_error( p->session->ts_session, ret );
+       err = SSL_get_error( p->session, ret );
        if (err == SSL_ERROR_WANT_WRITE ) {
                sbiod->sbiod_sb->sb_trans_needs_write = 1;
                sock_errset(EWOULDBLOCK);
        return dh;
 }
 
-tls_impl ldap_int_openssl_impl = {
+tls_impl ldap_int_tls_impl = {
        "OpenSSL",
 
        tlso_init,