#include <ac/string.h>
#include <ac/time.h>
#include <ac/unistd.h>
+#include <ac/param.h>
#include "ldap-int.h"
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 );
return p;
}
+char *
+ldap_pvt_tls_get_peer_hostname( void *s )
+{
+ 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);
+
+ if ( X509_NAME_get_text_by_NID(xn, NID_commonName, buf, sizeof(buf)) == -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 )
{
+ 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;
+ 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;
}