]> git.sur5r.net Git - openldap/blobdiff - libraries/libldap/tls.c
Revised ITS#799 fix from Steve Sonntag <vtag@novell.com>
[openldap] / libraries / libldap / tls.c
index 3ecb5f4c4044ca7bb84a0e08601794445354a78b..2070e28d80da407566d3d95f0a001809996f71f2 100644 (file)
@@ -8,8 +8,6 @@
 
 #include "portable.h"
 
-#ifdef HAVE_TLS
-
 #include <stdio.h>
 
 #include <ac/stdlib.h>
 #include <ac/string.h>
 #include <ac/time.h>
 #include <ac/unistd.h>
+#include <ac/param.h>
 
 #include "ldap-int.h"
 
+#ifdef HAVE_TLS
+
 #ifdef LDAP_R_COMPILE
 #include <ldap_pvt_thread.h>
 #endif
@@ -59,6 +60,8 @@ static DH * tls_tmp_dh_cb( SSL *ssl, int is_export, int key_length );
 
 static SSL_CTX *tls_def_ctx = NULL;
 
+static int tls_seed_PRNG( const char *randfile );
+
 #ifdef LDAP_R_COMPILE
 /*
  * provide mutexes for the SSLeay library.
@@ -95,7 +98,7 @@ static void tls_init_threads( void )
 #endif /* LDAP_R_COMPILE */
 
 /*
- * Initialize tls system. Should be called only once.
+ * Initialize TLS subsystem. Should be called only once.
  */
 int
 ldap_pvt_tls_init( void )
@@ -103,15 +106,17 @@ ldap_pvt_tls_init( void )
        static int tls_initialized = 0;
 
        if ( tls_initialized ) return 0;
+       tls_initialized = 1;
 
        (void) tls_seed_PRNG( tls_opt_randfile );
 
-       tls_initialized = 1;
 #ifdef LDAP_R_COMPILE
        tls_init_threads();
 #endif
+
        SSL_load_error_strings();
        SSLeay_add_ssl_algorithms();
+
        /* FIXME: mod_ssl does this */
        X509V3_add_standard_extensions();
        return 0;
@@ -197,9 +202,11 @@ ldap_pvt_tls_init_def_ctx( void )
                if ( tls_opt_trace ) {
                        SSL_CTX_set_info_callback( tls_def_ctx, tls_info_cb );
                }
-               SSL_CTX_set_verify( tls_def_ctx, (tls_opt_require_cert) ?
+               SSL_CTX_set_verify( tls_def_ctx,
+                       tls_opt_require_cert ?
                        (SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT) :
-                       SSL_VERIFY_PEER, tls_verify_cb );
+                       SSL_VERIFY_NONE,
+                       tls_verify_cb );
                SSL_CTX_set_tmp_rsa_callback( tls_def_ctx, tls_tmp_rsa_cb );
                /* SSL_CTX_set_tmp_dh_callback( tls_def_ctx, tls_tmp_dh_cb ); */
        }
@@ -626,6 +633,7 @@ ldap_pvt_tls_accept( Sockbuf *sb, void *ctx_arg )
 #endif
                return -1;
        }
+
        return 0;
 }
 
@@ -646,7 +654,8 @@ ldap_pvt_tls_sb_handle( Sockbuf *sb )
                ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_SSL, (void *)&p );
                return p;
        }
-               return NULL;
+
+       return NULL;
 }
 
 void *
@@ -655,20 +664,58 @@ ldap_pvt_tls_get_handle( LDAP *ld )
        return ldap_pvt_tls_sb_handle( ld->ld_sb );
 }
 
+int
+ldap_pvt_tls_get_strength( void *s )
+{
+    SSL_CIPHER *c;
+
+    c = SSL_get_current_cipher((SSL *)s);
+    return SSL_CIPHER_get_bits(c, NULL);
+}
+
+
 const char *
-ldap_pvt_tls_get_peer( LDAP *ld )
+ldap_pvt_tls_get_peer( void *s )
 {
-    return NULL;
+    X509 *x;
+    X509_NAME *xn;
+    char buf[2048], *p;
+
+    x = SSL_get_peer_certificate((SSL *)s);
+
+    if (!x)
+       return NULL;
+    
+    xn = X509_get_subject_name(x);
+    p = LDAP_STRDUP(X509_NAME_oneline(xn, buf, sizeof(buf)));
+    X509_free(x);
+    return p;
 }
 
 const char *
-ldap_pvt_tls_get_peer_issuer( LDAP *ld )
+ldap_pvt_tls_get_peer_issuer( void *s )
 {
+#if 0  /* currently unused; see ldap_pvt_tls_get_peer() if needed */
+    X509 *x;
+    X509_NAME *xn;
+    char buf[2048], *p;
+
+    x = SSL_get_peer_certificate((SSL *)s);
+
+    if (!x)
+       return NULL;
+    
+    xn = X509_get_issuer_name(x);
+    p = LDAP_STRDUP(X509_NAME_oneline(xn, buf, sizeof(buf)));
+    X509_free(x);
+    return p;
+#else
     return NULL;
+#endif
 }
 
 int
-ldap_pvt_tls_config( struct ldapoptions *lo, int option, const char *arg )
+ldap_int_tls_config( struct ldapoptions *lo, int option, const char *arg )
 {
        int i;
 
@@ -699,9 +746,9 @@ ldap_pvt_tls_config( struct ldapoptions *lo, int option, const char *arg )
                if (i >= 0)
                        return ldap_pvt_tls_set_option( lo, option, &i );
                return -1;
-       default:
-               return -1;
        }
+
+       return -1;
 }
 
 int
@@ -780,30 +827,30 @@ ldap_pvt_tls_set_option( struct ldapoptions *lo, int option, void *arg )
 
        switch( option ) {
        case LDAP_OPT_X_TLS_CACERTFILE:
-               if ( tls_opt_cacertfile ) free( tls_opt_cacertfile );
+               if ( tls_opt_cacertfile ) LDAP_FREE( tls_opt_cacertfile );
                tls_opt_cacertfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL;
                break;
        case LDAP_OPT_X_TLS_CACERTDIR:
-               if ( tls_opt_cacertdir ) free( tls_opt_cacertdir );
+               if ( tls_opt_cacertdir ) LDAP_FREE( tls_opt_cacertdir );
                tls_opt_cacertdir = arg ? LDAP_STRDUP( (char *) arg ) : NULL;
                break;
        case LDAP_OPT_X_TLS_CERTFILE:
-               if ( tls_opt_certfile ) free( tls_opt_certfile );
+               if ( tls_opt_certfile ) LDAP_FREE( tls_opt_certfile );
                tls_opt_certfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL;
                break;
        case LDAP_OPT_X_TLS_KEYFILE:
-               if ( tls_opt_keyfile ) free( tls_opt_keyfile );
+               if ( tls_opt_keyfile ) LDAP_FREE( tls_opt_keyfile );
                tls_opt_keyfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL;
                break;
        case LDAP_OPT_X_TLS_REQUIRE_CERT:
                tls_opt_require_cert = * (int *) arg;
                break;
        case LDAP_OPT_X_TLS_CIPHER_SUITE:
-               if ( tls_opt_ciphersuite ) free( tls_opt_ciphersuite );
+               if ( tls_opt_ciphersuite ) LDAP_FREE( tls_opt_ciphersuite );
                tls_opt_ciphersuite = arg ? LDAP_STRDUP( (char *) arg ) : NULL;
                break;
        case LDAP_OPT_X_TLS_RANDOM_FILE:
-               if (tls_opt_randfile ) free (tls_opt_randfile );
+               if (tls_opt_randfile ) LDAP_FREE (tls_opt_randfile );
                tls_opt_randfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL;
                break;
        default:
@@ -815,8 +862,7 @@ ldap_pvt_tls_set_option( struct ldapoptions *lo, int option, void *arg )
 int
 ldap_pvt_tls_start ( LDAP *ld, Sockbuf *sb, void *ctx_arg )
 {
-       /* Make sure tls is initialized, including PRNG properly seeded. */
-       ldap_pvt_tls_init();
+       (void) ldap_pvt_tls_init();
 
        /*
         * Fortunately, the lib uses blocking io...
@@ -947,9 +993,7 @@ tls_seed_PRNG( const char *randfile )
 {
 #ifndef URANDOM_DEVICE
        /* no /dev/urandom (or equiv) */
-
-       char buffer[1024];
-       static int egdsocket = 0;
+       char buffer[MAXPATHLEN];
 
        if (randfile == NULL) {
                /* The seed file is $RANDFILE if defined, otherwise $HOME/.rnd.
@@ -957,17 +1001,16 @@ tls_seed_PRNG( const char *randfile )
                 * an error occurs.    - From RAND_file_name() man page.
                 * The fact is that when $HOME is NULL, .rnd is used.
                 */
-               randfile = RAND_file_name(buffer, sizeof( buffer ));
+               randfile = RAND_file_name( buffer, sizeof( buffer ) );
 
        } else if (RAND_egd(randfile) > 0) {
                /* EGD socket */
-               egdsocket = 1;
                return 0;
        }
 
        if (randfile == NULL) {
                Debug( LDAP_DEBUG_ANY,
-                       "TLS: Use configuration file or $RANDFILE to define seed file",
+                       "TLS: Use configuration file or $RANDFILE to define seed PRNG\n",
                        0, 0, 0);
                return -1;
        }
@@ -976,7 +1019,7 @@ tls_seed_PRNG( const char *randfile )
 
        if (RAND_status() == 0) {
                Debug( LDAP_DEBUG_ANY,
-                       "TLS: PRNG has not been seeded with enough data",
+                       "TLS: PRNG not been seeded with enough data\n",
                        0, 0, 0);
                return -1;
        }
@@ -992,7 +1035,42 @@ tls_tmp_dh_cb( SSL *ssl, int is_export, int key_length )
        return NULL;
 }
 #endif
+#endif
+
+int
+ldap_start_tls_s ( LDAP *ld,
+       LDAPControl **serverctrls,
+       LDAPControl **clientctrls )
+{
+#ifdef HAVE_TLS
+       int rc;
+       char *rspoid = NULL;
+       struct berval *rspdata = NULL;
+
+       /* XXYYZ: this initiates operaton only on default connection! */
 
+       if ( ldap_pvt_tls_inplace( ld->ld_sb ) != 0 ) {
+               return LDAP_LOCAL_ERROR;
+       }
+
+       rc = ldap_extended_operation_s( ld, LDAP_EXOP_START_TLS,
+               NULL, serverctrls, clientctrls, &rspoid, &rspdata );
+       if ( rc != LDAP_SUCCESS ) {
+               return rc;
+       }
+
+       if ( rspoid != NULL ) {
+               LDAP_FREE(rspoid);
+       }
+
+       if ( rspdata != NULL ) {
+               ber_bvfree( rspdata );
+       }
+
+       rc = ldap_pvt_tls_start( ld, ld->ld_sb, ld->ld_options.ldo_tls_ctx );
+       return rc;
 #else
-static int dummy;
+       return LDAP_NOT_SUPPORTED;
 #endif
+}
+