]> git.sur5r.net Git - openldap/blobdiff - libraries/libldap/tls.c
blind fix of value_match when SLAP_NVALUES is set
[openldap] / libraries / libldap / tls.c
index 68f7e09b59210ed8c56be0560cf983d9563169af..d093739a6d8d17c6db7d0d251ae32f2bef8bd39d 100644 (file)
@@ -1,6 +1,6 @@
 /* $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.
@@ -15,6 +15,7 @@
 #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>
@@ -52,7 +53,7 @@ static char *tls_opt_randfile = NULL;
 
 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 );
@@ -409,7 +410,6 @@ get_ca_list( char * bundle, char * dir )
                }
        }
 #endif
-done:
        return ca_list;
 }
 
@@ -645,8 +645,11 @@ sb_tls_bio_read( BIO *b, char *buf, int len )
        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;
@@ -669,8 +672,11 @@ sb_tls_bio_write( BIO *b, const char *buf, int len )
        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;
@@ -945,12 +951,24 @@ ldap_pvt_tls_get_peer_hostname( void *s )
        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" ) ) )
@@ -977,6 +995,20 @@ ldap_pvt_tls_check_hostname( LDAP *ld, void *s, const char *name_in )
                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;
@@ -985,21 +1017,27 @@ ldap_pvt_tls_check_hostname( LDAP *ld, void *s, const char *name_in )
                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)) {
@@ -1008,19 +1046,34 @@ ldap_pvt_tls_check_hostname( LDAP *ld, void *s, const char *name_in )
 
                                        /* 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;
+                                       }
                                }
                        }
 
@@ -1340,9 +1393,11 @@ ldap_int_tls_start ( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv )
        /* 
         * 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;
+               }
        }
 
        /*
@@ -1366,11 +1421,11 @@ ldap_int_tls_start ( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv )
 
 /* 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 ) {
@@ -1398,8 +1453,8 @@ tls_info_cb( SSL *ssl, int where, int ret )
 #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 ) {