/* $OpenLDAP$ */
/*
- * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+ * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
* COPYING RESTRICTIONS APPLY, see COPYRIGHT file
*
* tls.c - Handle tls/ssl using SSLeay or OpenSSL.
#include <ac/errno.h>
#include <ac/socket.h>
#include <ac/string.h>
+#include <ac/ctype.h>
#include <ac/time.h>
#include <ac/unistd.h>
#include <ac/param.h>
static void tls_report_error( void );
-static void tls_info_cb( SSL *ssl, int where, int ret );
+static void tls_info_cb( const SSL *ssl, int where, int ret );
static int tls_verify_cb( int ok, X509_STORE_CTX *ctx );
static int tls_verify_ok( int ok, X509_STORE_CTX *ctx );
static RSA * tls_tmp_rsa_cb( SSL *ssl, int is_export, int key_length );
}
}
#endif
-done:
return ca_list;
}
ret = LBER_SBIOD_READ_NEXT( p->sbiod, buf, len );
BIO_clear_retry_flags( b );
- if ( ret < 0 && errno == EWOULDBLOCK ) {
- BIO_set_retry_read( b );
+ if ( ret < 0 ) {
+ int err = errno;
+ if ( err == EAGAIN || err == EWOULDBLOCK ) {
+ BIO_set_retry_read( b );
+ }
}
return ret;
ret = LBER_SBIOD_WRITE_NEXT( p->sbiod, (char *)buf, len );
BIO_clear_retry_flags( b );
- if ( ret < 0 && errno == EWOULDBLOCK ) {
- BIO_set_retry_write( b );
+ if ( ret < 0 ) {
+ int err = errno;
+ if ( err == EAGAIN || err == EWOULDBLOCK ) {
+ BIO_set_retry_write( b );
+ }
}
return ret;
return p;
}
+/* what kind of hostname were we given? */
+#define IS_DNS 0
+#define IS_IP4 1
+#define IS_IP6 2
+
int
ldap_pvt_tls_check_hostname( LDAP *ld, void *s, const char *name_in )
{
int i, ret = LDAP_LOCAL_ERROR;
X509 *x;
const char *name;
+ char *ptr;
+ int ntype = IS_DNS;
+#ifdef LDAP_PF_INET6
+ struct in6_addr addr;
+#else
+ struct in_addr addr;
+#endif
if( ldap_int_hostname &&
( !name_in || !strcasecmp( name_in, "localhost" ) ) )
return LDAP_SUCCESS;
}
+#ifdef LDAP_PF_INET6
+ if (name[0] == '[' && strchr(name, ']')) {
+ char *n2 = ldap_strdup(name+1);
+ *strchr(n2, ']') = 2;
+ if (inet_pton(AF_INET6, n2, &addr))
+ ntype = IS_IP6;
+ LDAP_FREE(n2);
+ } else
+#endif
+ if ((ptr = strrchr(name, '.')) && isdigit((unsigned char)ptr[1])) {
+ if (inet_aton(name, (struct in_addr *)&addr))
+ ntype = IS_IP4;
+ }
+
i = X509_get_ext_by_NID(x, NID_subject_alt_name, -1);
if (i >= 0) {
X509_EXTENSION *ex;
ex = X509_get_ext(x, i);
alt = X509V3_EXT_d2i(ex);
if (alt) {
- int n, len1, len2 = 0;
- char *domain;
+ int n, len1 = 0, len2 = 0;
+ char *domain = NULL;
GENERAL_NAME *gn;
- len1 = strlen(name);
- n = sk_GENERAL_NAME_num(alt);
- domain = strchr(name, '.');
- if (domain) {
- len2 = len1 - (domain-name);
+ if (ntype == IS_DNS) {
+ len1 = strlen(name);
+ domain = strchr(name, '.');
+ if (domain) {
+ len2 = len1 - (domain-name);
+ }
}
+ n = sk_GENERAL_NAME_num(alt);
for (i=0; i<n; i++) {
+ char *sn;
+ int sl;
gn = sk_GENERAL_NAME_value(alt, i);
if (gn->type == GEN_DNS) {
- char *sn = ASN1_STRING_data(gn->d.ia5);
- int sl = ASN1_STRING_length(gn->d.ia5);
+ if (ntype != IS_DNS) continue;
+
+ sn = ASN1_STRING_data(gn->d.ia5);
+ sl = ASN1_STRING_length(gn->d.ia5);
/* Is this an exact match? */
if ((len1 == sl) && !strncasecmp(name, sn, len1)) {
/* Is this a wildcard match? */
if ((*sn == '*') && domain && (len2 == sl-1) &&
- !strncasecmp(domain, sn+1, len2))
- {
+ !strncasecmp(domain, sn+1, len2)) {
break;
}
#if 0
- /* Is this a RFC 2549 style wildcard match? */
+ /* Is this a RFC 2459 style wildcard match? */
if ((*sn == '.') && domain && (len2 == sl) &&
- !strncasecmp(domain, sn, len2))
- {
+ !strncasecmp(domain, sn, len2)) {
break;
}
#endif
+ } else if (gn->type == GEN_IPADD) {
+ if (ntype == IS_DNS) continue;
+
+ sn = ASN1_STRING_data(gn->d.ia5);
+ sl = ASN1_STRING_length(gn->d.ia5);
+
+#ifdef LDAP_PF_INET6
+ if (ntype == IS_IP6 && sl != sizeof(struct in6_addr)) {
+ continue;
+ } else
+#endif
+ if (ntype == IS_IP4 && sl != sizeof(struct in_addr)) {
+ continue;
+ }
+ if (!memcmp(sn, &addr, sl)) {
+ break;
+ }
}
}
/*
* compare host with name(s) in certificate
*/
- ld->ld_errno = ldap_pvt_tls_check_hostname( ld, ssl, host );
- if (ld->ld_errno != LDAP_SUCCESS) {
- return ld->ld_errno;
+ if (tls_opt_require_cert != LDAP_OPT_X_TLS_NEVER) {
+ ld->ld_errno = ldap_pvt_tls_check_hostname( ld, ssl, host );
+ if (ld->ld_errno != LDAP_SUCCESS) {
+ return ld->ld_errno;
+ }
}
/*
/* Derived from openssl/apps/s_cb.c */
static void
-tls_info_cb( SSL *ssl, int where, int ret )
+tls_info_cb( const SSL *ssl, int where, int ret )
{
int w;
char *op;
- char *state = SSL_state_string_long( ssl );
+ char *state = (char *) SSL_state_string_long( (SSL *)ssl );
w = where & ~SSL_ST_MASK;
if ( w & SSL_ST_CONNECT ) {
#endif
} else if ( where & SSL_CB_ALERT ) {
- char *atype = SSL_alert_type_string_long( ret );
- char *adesc = SSL_alert_desc_string_long( ret );
+ char *atype = (char *) SSL_alert_type_string_long( ret );
+ char *adesc = (char *) SSL_alert_desc_string_long( ret );
op = ( where & SSL_CB_READ ) ? "read" : "write";
#ifdef HAVE_EBCDIC
if ( atype ) {