#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 );
}
-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 )
{
- 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) */
+ long total=0;
char buffer[MAXPATHLEN];
if (randfile == NULL) {
if (randfile == NULL) {
Debug( LDAP_DEBUG_ANY,
- "TLS: Use configuration file or $RANDFILE to define seed PRNG",
+ "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 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;