#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
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.
#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 )
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;
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 ); */
}
#endif
return -1;
}
+
return 0;
}
ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_SSL, (void *)&p );
return p;
}
- return NULL;
+
+ return NULL;
}
void *
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;
if (i >= 0)
return ldap_pvt_tls_set_option( lo, option, &i );
return -1;
- default:
- return -1;
}
+
+ return -1;
}
int
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:
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...
{
#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.
* 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;
}
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;
}
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
+}
+