#include <ac/string.h>
#include <ac/time.h>
#include <ac/unistd.h>
+#include <ac/param.h>
#include "ldap-int.h"
#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 ( 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 );
ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_SSL, (void *)&p );
return p;
}
- return NULL;
+
+ return NULL;
}
void *
}
-const char *
+char *
ldap_pvt_tls_get_peer( void *s )
{
X509 *x;
return p;
}
+char *
+ldap_pvt_tls_get_peer_dn( void *s )
+{
+ X509 *x;
+ X509_NAME *xn;
+ char buf[2048], *p, *dn;
+
+ x = SSL_get_peer_certificate((SSL *)s);
+
+ if (!x) return NULL;
+
+ xn = X509_get_subject_name(x);
+ p = X509_NAME_oneline(xn, buf, sizeof(buf));
+
+ dn = ldap_dcedn2dn( p );
+
+ X509_free(x);
+ return dn;
+}
+
+char *
+ldap_pvt_tls_get_peer_hostname( void *s )
+{
+ X509 *x;
+ X509_NAME *xn;
+ char buf[2048], *p;
+ int ret;
+
+ x = SSL_get_peer_certificate((SSL *)s);
+
+ if (!x)
+ return NULL;
+
+ xn = X509_get_subject_name(x);
+
+ ret = X509_NAME_get_text_by_NID(xn, NID_commonName, buf, sizeof(buf));
+ if( ret == -1 ) {
+ X509_free(x);
+ return NULL;
+ }
+
+ p = LDAP_STRDUP(buf);
+ X509_free(x);
+ return p;
+}
+
const char *
ldap_pvt_tls_get_peer_issuer( void *s )
{
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();
+ char *peer_cert_cn, *peer_hostname;
+ void *ssl;
+
+ (void) ldap_pvt_tls_init();
/*
* Fortunately, the lib uses blocking io...
return LDAP_CONNECT_ERROR;
}
- /* FIXME: hostname of server must be compared with name in
- * certificate....
+ ssl = (void *) ldap_pvt_tls_sb_handle( sb );
+ /*
+ * compare hostname of server with name in certificate
*/
+ peer_cert_cn = ldap_pvt_tls_get_peer_hostname( ssl );
+ if ( !peer_cert_cn ) {
+ /* could not get hostname from peer certificate */
+ Debug( LDAP_DEBUG_ANY,
+ "TLS: unable to get common name from peer certificate.\n",
+ 0, 0, 0 );
+ return LDAP_LOCAL_ERROR;
+ }
+
+ peer_hostname = ldap_host_connected_to( sb );
+ if ( !peer_hostname ) {
+ /* could not lookup hostname */
+ Debug( LDAP_DEBUG_ANY,
+ "TLS: unable to reverse lookup peer hostname.\n",
+ 0, 0, 0 );
+ LDAP_FREE( peer_cert_cn );
+ return LDAP_LOCAL_ERROR;
+ }
+
+ if ( strcasecmp(peer_hostname, peer_cert_cn) != 0 ) {
+ Debug( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match "
+ "common name in certificate (%s).",
+ peer_hostname, peer_cert_cn, 0 );
+ LDAP_FREE( peer_cert_cn );
+ LDAP_FREE( peer_hostname );
+ return LDAP_CONNECT_ERROR;
+
+ } else {
+ LDAP_FREE( peer_cert_cn );
+ LDAP_FREE( peer_hostname );
+ }
+
+ /*
+ * set SASL properties to TLS ssf and authid
+ */
+ {
+ const char *authid;
+ ber_len_t ssf;
+
+ /* we need to let SASL know */
+ ssf = ldap_pvt_tls_get_strength( ssl );
+ authid = ldap_pvt_tls_get_peer( ssl );
+
+ (void) ldap_int_sasl_external( ld, authid, ssf );
+ }
return LDAP_SUCCESS;
}
{
#ifndef URANDOM_DEVICE
/* no /dev/urandom (or equiv) */
-
- char buffer[1024];
- static int egdsocket = 0;
+ long total=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;
}
- RAND_load_file(randfile, -1);
+ total = RAND_load_file(randfile, -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;
}
+
+ /* assume if there was enough bits to seed that it's okay
+ * to write derived bits to the file
+ */
+ RAND_write_file(randfile);
+
#endif
return 0;
int
ldap_start_tls_s ( LDAP *ld,
- LDAPControl **serverctrls,
- LDAPControl **clientctrls )
+ LDAPControl **serverctrls,
+ LDAPControl **clientctrls )
{
#ifdef HAVE_TLS
- LDAPConn *lc;
int rc;
char *rspoid = NULL;
struct berval *rspdata = NULL;
- if (ld->ld_conns == NULL) {
- rc = ldap_open_defconn( ld );
- if (rc != LDAP_SUCCESS)
- return(rc);
+ /* XXYYZ: this initiates operaton only on default connection! */
+
+ if ( ldap_pvt_tls_inplace( ld->ld_sb ) != 0 ) {
+ return LDAP_LOCAL_ERROR;
}
- for (lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next) {
- if (ldap_pvt_tls_inplace(lc->lconn_sb) != 0)
- return LDAP_OPERATIONS_ERROR;
-
- /* XXYYZ: this initiates operaton only on default connection! */
- 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, lc->lconn_sb, ld->ld_options.ldo_tls_ctx );
- if (rc != LDAP_SUCCESS)
- return rc;
+ rc = ldap_extended_operation_s( ld, LDAP_EXOP_START_TLS,
+ NULL, serverctrls, clientctrls, &rspoid, &rspdata );
+ if ( rc != LDAP_SUCCESS ) {
+ return rc;
}
- return LDAP_SUCCESS;
+
+ 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
return LDAP_NOT_SUPPORTED;
#endif