Changeset 268


Ignore:
Timestamp:
05/09/07 08:48:00 (5 years ago)
Author:
ludovic.rousseau
Message:

ldap-patches from Sandro Wefel
http://www.opensc-project.org/pipermail/opensc-devel/2007-April/009764.html

which offers:

  • support for more than one LDAP server as fallback system
  • support of secure connection (SSL+TLS) because someone may use simple authentication with username and password
  • multiple certificates per attribute
  • LDAP-URI support
  • selection of base, one-level or subtree search
  • timeout support and a somewhat enhanced documentation.
Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/configure.in

    r242 r268  
    7777        ]) 
    7878fi 
     79if test "$with_ldap" \!= "no"; then 
     80  AC_CHECK_FUNCS(ldap_init ldap_initialize) 
     81  AC_CHECK_FUNCS(ldap_set_option ldap_get_option)   
     82  AC_CHECK_FUNCS(ldap_start_tls ldap_start_tls_s) 
     83fi       
    7984AC_SUBST(LDAP_CFLAGS) 
    8085AC_SUBST(LDAP_LIBS) 
  • trunk/doc/pam_pkcs11.xml

    r228 r268  
    16641664        This mapper is still under development. 
    16651665</para> 
     1666<para> 
     1667ldap_mapper configuration file shows like: 
     1668<screen> 
     1669  # Directory ( ldap style ) mapper 
     1670  mapper ldap { 
     1671        debug = false; 
     1672        module = /usr/lib/pam_pkcs11/ldap_mapper.so; 
     1673        ldaphost = ""; 
     1674        ldapport = ; 
     1675        URI = ""; 
     1676        scope = 2; 
     1677        binddn = "cn=pam,o=example,c=com"; 
     1678        passwd = ""; 
     1679        base = "ou=People,o=example,c=com"; 
     1680        attribute = "userCertificate"; 
     1681        filter = "<![CDATA[(&(objectClass=posixAccount)(uid=%s))]]>" 
     1682        # SSL/TLS-Settings 
     1683        ssl = tls 
     1684        # tls_randfile = ... 
     1685        tls_cacertfile = /etc/ssl/cacert.pem 
     1686        # tls_cacertdir = ... 
     1687        tls_checkpeer = 0 
     1688        #tls_ciphers = ... 
     1689        #tls_cert = ... 
     1690        #tls_key = ... 
     1691  } 
     1692</screen> 
     1693The following options are recognized by 
     1694 
     1695<varlistentry> 
     1696<term><token>ldaphost</token></term> 
     1697<listitem>The FQDN (hostname) oder IP-address of the ldap server.</listitem> 
     1698</varlistentry> 
     1699 
     1700<varlistentry> 
     1701<term><token>URI</token></term> 
     1702<listitem>A space separated list of LDAP URIs. The URIs are used in the given order. 
     1703If a ldaphost is also submitted, it will be appended to the URI list. 
     1704</listitem> 
     1705</varlistentry> 
     1706 
     1707<varlistentry> 
     1708<term><token>ldapport</token></term> 
     1709<listitem>The LDAP Port on the server (default: 
     1710389 for LDAP and LDAP-TLS and 636 for SSL) 
     1711</listitem> 
     1712</varlistentry> 
     1713 
     1714<varlistentry> 
     1715 <term><token>scope</token></term> 
     1716 <listitem>Scope of search: 0-2 
     1717        <itemizedlist> 
     1718                <listitem><option> 0 </option> "base", search only the basedn 
     1719                </listitem> 
     1720         
     1721                <listitem><option> 1 </option> "one", only the set of records one 
     1722            level below the basedn is searched (default)  
     1723            </listitem> 
     1724         
     1725                <listitem><option> 2 </option> "sub"  means the union of entries  
     1726                at the "base" level and all levels below are searched  
     1727                </listitem> 
     1728        </itemizedlist> 
     1729 </listitem> 
     1730         
     1731</varlistentry> 
     1732 
     1733<varlistentry> 
     1734<term><token>binddn</token></term> 
     1735<listitem>The bind-DN if needed. 
     1736</listitem> 
     1737</varlistentry> 
     1738 
     1739<varlistentry> 
     1740<term><token>passwd</token></term> 
     1741<listitem>Password for bind-DN 
     1742</listitem> 
     1743</varlistentry> 
     1744 
     1745<varlistentry> 
     1746<term><token>base</token></term> 
     1747<listitem>The DN of the searchbase (see scope) 
     1748</listitem> 
     1749</varlistentry> 
     1750 
     1751<varlistentry> 
     1752<term><token>attribute</token></term> 
     1753<listitem>The user attribute in LDAP entry, which contains  
     1754the certificate. This can be an multi-value attribute. That 
     1755implies you can store more than one certificate under this 
     1756attribute. All certificates are utilized. 
     1757</listitem> 
     1758</varlistentry> 
     1759 
     1760 
     1761<varlistentry> 
     1762<term><token>filter</token></term> 
     1763<listitem>LDAP filter string. You can use ist to restrict 
     1764the entries returned by the LDAP server, e.g. by checking 
     1765other attributes of the user entry. 
     1766%s is substituted by the user name. 
     1767 
     1768<![CDATA[(&(objectClass=posixAccount)(uid=%s))]]> 
     1769means, only that 
     1770LDAP entry is returned which has an objectClass  
     1771"posixAccount" and the uid with the user name. 
     1772 
     1773<lineannotation>IMPORTANT NOTE:</lineannotation> The filter string 
     1774must be choosen in such a way that only one entry for the user is  
     1775returned. If an user has more certifactes than these should be  
     1776collected under the attribute. 
     1777</listitem> 
     1778</varlistentry> 
     1779 
     1780<varlistentry> 
     1781<term><token>ssl</token></term> 
     1782<listitem>Enable or disable the usage of TLS or SSL 
     1783        <itemizedlist> 
     1784                <listitem><option> off </option>   TLS/SSL off(default) 
     1785                </listitem> 
     1786         
     1787                <listitem><option> tls </option>   enable TLS  
     1788            </listitem> 
     1789         
     1790                <listitem><option> on|ssl </option>   enable SSL 
     1791                </listitem> 
     1792        </itemizedlist> 
     1793</listitem> 
     1794</varlistentry> 
     1795 
     1796<varlistentry> 
     1797<term><token>tls_randfile</token></term> 
     1798<listitem>Specifies the path to an entropy source. 
     1799</listitem> 
     1800</varlistentry> 
     1801 
     1802<varlistentry> 
     1803<term><token>tls_cacertfile</token></term> 
     1804<listitem>Specifies the path to the X.509 certificate for peer authentication. 
     1805</listitem> 
     1806</varlistentry> 
     1807 
     1808<varlistentry> 
     1809<term><token>tls_cacertdir</token></term> 
     1810<listitem>Specifies the directory containing X.509 certificates for peer authentication. 
     1811</listitem> 
     1812</varlistentry> 
     1813 
     1814<varlistentry> 
     1815<term><token>tls_checkpeer</token></term> 
     1816<listitem>Specifies whether to require and verify the server certificate or not. 
     1817<option> 1 </option>  check the certificate  
     1818<option> 0 </option>  off (default) 
     1819</listitem> 
     1820</varlistentry> 
     1821 
     1822<varlistentry> 
     1823<term><token>tls_ciphers</token></term> 
     1824<listitem>Specifies the ciphers to use. 
     1825</listitem> 
     1826</varlistentry> 
     1827 
     1828<varlistentry> 
     1829<term><token>tls_cert</token></term> 
     1830<listitem>Specifies the path to the file containing the local certificate for client TLS authentication if required. 
     1831</listitem> 
     1832</varlistentry> 
     1833 
     1834<varlistentry> 
     1835<term><token>tls_key</token></term> 
     1836<listitem>Specifies the path to the file containing the private key for client TLS authentication. 
     1837</listitem> 
     1838</varlistentry> 
     1839 
     1840</para> 
     1841 
     1842 
     1843 
    16661844</sect2> 
    16671845 
  • trunk/etc/pam_pkcs11.conf.example

    r225 r268  
    182182        debug = false; 
    183183        module = /usr/lib/pam_pkcs11/ldap_mapper.so; 
    184         # where base directory resides 
    185         basedir = /etc/pam_pkcs11/mapdir; 
    186         # hostname of ldap server 
    187         ldaphost = "localhost"; 
    188         # Port on ldap server to connect 
    189         ldapport = 389; 
    190         # Scope of search: 0 = x, 1 = y, 2 = z 
    191         scope = 2; 
    192         # DN to bind with. Must have read-access for user entries under "base" 
    193         binddn = "cn=pam,o=example,c=com"; 
     184        # hostname of ldap server (use LDAP-URI for more then one) 
     185        ldaphost = ""; 
     186        # Port on ldap server to connect, this is also the default 
     187        #   if no port is given in URI below 
     188        #   if empty, then 389 for TLS and 636 for SSL is used 
     189        ldapport = ; 
     190        # space separted list of LDAP URIs (URIs are used by given order) 
     191        URI = ""; 
     192        # Scope of search: 0-2 
     193        #   Default is 1 = "one", meaning the set of records one 
     194        #   level below the basedn. 
     195        #   0 = "base"  means search only the basedn, and 
     196        #   2 = "sub"  means the union of entries at the "base" level 
     197        #   and ? all or "one" level below ??? FIXME 
     198        scope = 2; 
     199        # DN to bind with. Must have read-access for user entries 
     200        # under "base" 
     201        binddn = "cn=pam,o=example,c=com"; 
    194202        # Password for above DN 
    195         passwd = "test"; 
     203        passwd = ""; 
    196204        # Searchbase for user entries 
    197         base = "ou=People,o=example,c=com"; 
     205        base = "ou=People,o=example,c=com"; 
    198206        # Attribute of user entry which contains the certificate 
    199         attribute = "userCertificate"; 
    200         # Searchfilter for user entry. Must only let pass user entry for the login user. 
    201         filter = "(&(objectClass=posixAccount)(uid=%s))" 
     207        attribute = "userCertificate"; 
     208        # Searchfilter for user entry. Must only let pass user entry 
     209        # for the login user. 
     210        filter = "(&(objectClass=posixAccount)(uid=%s))" 
     211        # SSL/TLS-Switch 
     212        #   This is a global switch, you can't switch between 
     213        #   SSL or TLS and non secured connections per URI! 
     214        #   values: off (standard), tls or on (ssl) or ssl 
     215        ssl = tls 
     216        # SSL specific settings 
     217        # tls_randfile = ... 
     218        tls_cacertfile = /etc/ssl/cacert.pem 
     219        # tls_cacertdir = ... 
     220        tls_checkpeer = 0 
     221        #tls_ciphers = ... 
     222        #tls_cert = ... 
     223        #tls_key = ... 
    202224  } 
    203225 
  • trunk/src/mappers/ldap_mapper.c

    r238 r268  
    2222 */ 
    2323 
     24/* 
     25 * Sandro Wefel (SaW) <sandro.wefel@informatik.uni-halle.de> added 
     26 *  TLS/SSL support (see autofs-ldap and libnss-ldap) 
     27 *  multiple LDAP-Server support 
     28 *  multi-value certificate entries 
     29 */ 
     30 
    2431#define __LDAP_MAPPER_C_ 
    2532 
     
    4956*/ 
    5057 
     58 
     59static const int LDAP_CONFIG_URI_MAX = 10; 
     60 
     61 
    5162/* 
    52 * TODO: Support for LDAPS Connection 
    53 */ 
     63 * TODO:  
     64 * - Support for SASL-AUTH not included yet, I can't test it 
     65 *   
     66 * - ldap_unbind (*ld) crash if you connect to a SSL port but have set TLS intead SSL 
     67 *   - no idea why!? 
     68 *   - you got no error-massage from your application 
     69 *   - believe skip ldap_unbind (*ld) for a bind handle isn't a good solution 
     70 *  
     71 * - implement searchtimeout 
     72 * - implement ignorecase 
     73 */ 
     74 
     75 
     76enum ldap_ssl_options 
     77{ 
     78  SSL_OFF, 
     79  SSL_LDAPS, 
     80  SSL_START_TLS 
     81}; 
     82 
     83typedef enum ldap_ssl_options ldap_ssl_options_t; 
     84 
     85#ifndef LDAPS_PORT 
     86#define LDAPS_PORT 636 
     87#endif  
     88 
    5489 
    5590/*** Internal vars *****************************************************/ 
    5691 
    57 static const char *ldaphost="localhost"; 
    58 static int ldapport=389; 
    59 static int scope=0; /* 0: LDAP_SCOPE_BASE, 1: LDAP_SCOPE_ONE, 2: LDAP_SCOPE_SUB */ 
     92/* Host and Port */ 
     93static const char *ldaphost=""; 
     94static int ldapport=0; 
     95/* or URI (allow multiple hosts) */ 
     96static const char *ldapURI=""; 
     97static int scope=1; /* 0: LDAP_SCOPE_BASE, 1: LDAP_SCOPE_ONE, 2: LDAP_SCOPE_SUB */ 
    6098static const char *binddn=""; 
    6199static const char *passwd=""; 
     
    65103static int searchtimeout=20; 
    66104static int ignorecase=0; 
    67 static const X509 *ldap_x509; 
     105static const X509 **ldap_x509; 
     106static int certcnt=0; 
     107 
     108static ldap_ssl_options_t ssl_on = SSL_OFF; 
     109#if defined HAVE_LDAP_START_TLS_S || (defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS)) 
     110/* TLS/SSL specific options */ 
     111static const char *tls_randfile=""; 
     112static const char *tls_cacertfile=""; 
     113static const char *tls_cacertdir=""; 
     114static int tls_checkpeer=-1; 
     115static const char *tls_ciphers=""; 
     116static const char *tls_cert="";  
     117static const char *tls_key=""; 
     118#endif 
     119 
     120static int ldapVersion = 3;              
     121#ifdef HAVE_LDAP_SET_OPTION 
     122static int timeout = 8;                 // 8 seconds        
     123#endif 
     124static int bind_timelimit = 2;  // Timelimit for BIND 
     125 
     126static const int sscope[] = { 
     127        LDAP_SCOPE_BASE,  
     128        LDAP_SCOPE_ONELEVEL,  
     129        LDAP_SCOPE_SUBTREE}; 
    68130 
    69131/*** Internal funcs ****************************************************/ 
     132 
     133 
     134static int do_init (LDAP ** ld, const char *uri, int ldapdefport) 
     135{ 
     136        int rc; 
     137        int ldaps; 
     138        char uribuf[512]; 
     139        char *p; 
     140         
     141        DBG("do_init():"); 
     142 
     143        ldaps = (strncasecmp (uri, "ldaps://", sizeof ("ldaps://") - 1) == 0); 
     144        p = strchr (uri, ':'); 
     145        /* we should be looking for the second instance to find the port number */ 
     146        if (p != NULL) 
     147        { 
     148                p = strchr (p, ':'); 
     149        } 
     150 
     151#ifdef HAVE_LDAP_INITIALIZE 
     152        if (p == NULL && 
     153                ((ldaps && ldapdefport != LDAPS_PORT) || (!ldaps && ldapdefport != LDAP_PORT))) 
     154        { 
     155                /* No port specified in URI and non-default port specified */ 
     156                snprintf (uribuf, sizeof (uribuf), "%s:%d", uri, ldapdefport); 
     157                uri = uribuf; 
     158        } 
     159        rc = ldap_initialize (ld, uri); 
     160#else 
     161        // TODO: !HAVE_LDAP_INITIALIZE => no ldaps:// possible? 
     162        if (strncasecmp (uri, "ldap://", sizeof ("ldap://") - 1) != 0) 
     163    { 
     164                return LDAP_UNAVAILABLE; 
     165    } 
     166 
     167        uri += sizeof ("ldap://") - 1; 
     168        p = strchr (uri, ':'); 
     169 
     170        if (p != NULL) 
     171    { 
     172                size_t urilen = (p - uri); 
     173                 
     174                if (urilen >= sizeof (uribuf)) 
     175                { 
     176                        return LDAP_UNAVAILABLE; 
     177                } 
     178                 
     179                memcpy (uribuf, uri, urilen); 
     180                uribuf[urilen] = '\0'; 
     181                 
     182                ldapdefport = atoi (p + 1); 
     183                uri = uribuf; 
     184        } 
     185 
     186# ifdef HAVE_LDAP_INIT 
     187        *ld = ldap_init (uri, defport); 
     188# else 
     189        *ld = ldap_open (uri, defport); 
     190# endif 
     191        rc = (*ld == NULL) ? LDAP_SERVER_DOWN : LDAP_SUCCESS; 
     192 
     193#endif /* HAVE_LDAP_INITIALIZE */ 
     194 
     195        if (rc == LDAP_SUCCESS && *ld == NULL) 
     196        { 
     197                rc = LDAP_UNAVAILABLE; 
     198        } 
     199        return rc; 
     200} 
     201 
     202 
     203#if defined HAVE_LDAP_START_TLS_S || (defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS)) 
     204/*  
     205 * Set the ssl option 
     206 */ 
     207static int do_ssl_options (LDAP *ldap_connection) 
     208{ 
     209        int rc; 
     210 
     211        DBG("do_ssl_options"); 
     212 
     213#ifdef LDAP_OPT_X_TLS_RANDOM_FILE 
     214        if (strncmp(tls_randfile,"",1)) 
     215        { 
     216 
     217                /* rand file */ 
     218                rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_RANDOM_FILE, 
     219                    tls_randfile); 
     220                if (rc != LDAP_SUCCESS) 
     221                { 
     222                        DBG("do_ssl_options: Setting of LDAP_OPT_X_TLS_RANDOM_FILE failed"); 
     223                        return LDAP_OPERATIONS_ERROR; 
     224                } 
     225        } 
     226#endif /* LDAP_OPT_X_TLS_RANDOM_FILE */ 
     227 
     228        if (strncmp(tls_cacertfile,"",1)) 
     229        { 
     230                /* ca cert file */ 
     231                rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTFILE, 
     232                        tls_cacertfile); 
     233                if (rc != LDAP_SUCCESS) 
     234                { 
     235                        DBG("do_ssl_options: Setting of LDAP_OPT_X_TLS_CACERTFILE failed"); 
     236                        return LDAP_OPERATIONS_ERROR; 
     237                } 
     238        } 
     239 
     240        if (strncmp(tls_cacertdir,"",1)) 
     241    { 
     242                /* ca cert directory */ 
     243                rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTDIR, 
     244                                    tls_cacertdir); 
     245                if (rc != LDAP_SUCCESS) 
     246                { 
     247                        DBG("do_ssl_options: Setting of LDAP_OPT_X_TLS_CACERTDIR failed"); 
     248                        return LDAP_OPERATIONS_ERROR; 
     249                } 
     250    } 
     251 
     252        /* the cert have to be checked ? */ 
     253        if (tls_checkpeer > -1) 
     254        { 
     255                rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, 
     256                        &tls_checkpeer); 
     257                if (rc != LDAP_SUCCESS) 
     258                { 
     259                        DBG("do_ssl_options: Setting of LDAP_OPT_X_TLS_REQUIRE_CERT failed"); 
     260                        return LDAP_OPERATIONS_ERROR; 
     261                } 
     262        } 
     263 
     264        if (strncmp(tls_ciphers,"",1)) 
     265    { 
     266                /* set cipher suite, certificate and private key: */ 
     267                rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CIPHER_SUITE, 
     268                        tls_ciphers); 
     269                if (rc != LDAP_SUCCESS) 
     270                { 
     271                        DBG("do_ssl_options: Setting of LDAP_OPT_X_TLS_CIPHER_SUITE failed"); 
     272                        return LDAP_OPERATIONS_ERROR; 
     273                } 
     274        } 
     275 
     276        /* where is the requiered cert */ 
     277        if (strncmp(tls_cert,"",1)) 
     278    { 
     279            rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CERTFILE,  
     280                tls_cert); 
     281            if (rc != LDAP_SUCCESS) 
     282                { 
     283                        DBG("do_ssl_options: Setting of LDAP_OPT_X_TLS_CERTFILE failed"); 
     284                        return LDAP_OPERATIONS_ERROR; 
     285                } 
     286    } 
     287 
     288        /* where is the key */ 
     289        if (strncmp(tls_key,"",1)) 
     290        { 
     291                rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_KEYFILE,  
     292                        tls_key); 
     293                if (rc != LDAP_SUCCESS) 
     294                { 
     295                        DBG("do_ssl_options: Setting of LDAP_OPT_X_TLS_KEYFILE failed"); 
     296                        return LDAP_OPERATIONS_ERROR; 
     297                } 
     298        } 
     299        return LDAP_SUCCESS; 
     300} 
     301#endif 
     302 
     303 
     304static int 
     305do_bind (LDAP * ldap_connection, int timelimit) 
     306{ 
     307        int rc; 
     308        int rv; 
     309        struct timeval tv; 
     310        LDAPMessage *result; 
     311 
     312        /* 
     313         * set timelimit in ld for select() call in ldap_pvt_connect()  
     314         * function implemented in libldap2's os-ip.c 
     315         */ 
     316        tv.tv_sec = timelimit; 
     317        tv.tv_usec = 0; 
     318 
     319DBG2("do_bind(): bind DN=\"%s\" pass=\"%s\"",binddn,passwd); 
     320 
     321        /* LDAPv3 doesn't need bind at all,  
     322         * nevertheless, if no binddn is given than bind anonymous */ 
     323        if ( ! strncmp(binddn,"",1) ) { 
     324                rv = ldap_simple_bind(ldap_connection, NULL, NULL); 
     325        } else { 
     326                rv = ldap_simple_bind(ldap_connection, binddn, passwd); 
     327        } 
     328 
     329        if (rv < 0) 
     330        { 
     331DBG("do_bind: rv < 0"); 
     332                 
     333#if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER) 
     334                if (ldap_get_option (ldap_connection, LDAP_OPT_ERROR_NUMBER, &rc) != 
     335            LDAP_SUCCESS) 
     336                { 
     337                  rc = LDAP_UNAVAILABLE; 
     338                } 
     339#else 
     340                rc = ldap_connection->ld_errno; 
     341#endif /* LDAP_OPT_ERROR_NUMBER */ 
     342                /* Notify if we failed. */ 
     343                DBG3("could not connect to LDAP server as %s - %d - %s", 
     344                  binddn, rc, ldap_err2string (rc)); 
     345 
     346                return rc; 
     347        } 
     348 
     349        rc = ldap_result (ldap_connection, rv, 0, &tv, &result); 
     350        if (rc > 0) 
     351        { 
     352DBG1("do_bind rc=%d", rc); 
     353                //debug ("<== do_bind"); 
     354                return ldap_result2error (ldap_connection, result, 1); 
     355        } 
     356 
     357        /* took too long */ 
     358        if (rc == 0) 
     359        { 
     360DBG("do_bind rc=0"); 
     361                 
     362                ldap_abandon (ldap_connection, rv); 
     363        } 
     364 
     365DBG("do_bind return -1"); 
     366        return -1; 
     367} 
     368 
     369/* 
     370 * Opes connection to an LDAP server 
     371 * uri must be one URI 
     372 */ 
     373static int do_open (LDAP **ld, const char* uri, int defport, ldap_ssl_options_t ssl_on) 
     374{ 
     375         
     376#if defined(LDAP_OPT_NETWORK_TIMEOUT) || defined(HAVE_LDAP_START_TLS)    
     377        struct timeval tv; 
     378#endif 
     379#ifdef HAVE_LDAP_START_TLS 
     380        struct timeval *tvp; 
     381        LDAPMessage *res = NULL; 
     382        int msgid; 
     383#endif   
     384        int rc; 
     385 
     386        rc = do_init (ld, uri, defport); 
     387         
     388        if (rc != LDAP_SUCCESS) 
     389        { 
     390                DBG("do_open(): do_init failed"); 
     391                return rc; 
     392    } 
     393 
     394        if( ! *ld) 
     395        { 
     396                DBG("do_open(): internal error - assert (*ld != NULL)"); 
     397                return(-2); 
     398        } 
     399 
     400#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_PROTOCOL_VERSION) 
     401        ldap_set_option (*ld, LDAP_OPT_PROTOCOL_VERSION, &ldapVersion); 
     402#endif /* LDAP_OPT_PROTOCOL_VERSION */ 
     403 
     404#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_NETWORK_TIMEOUT) 
     405//      ldap_set_option (*ld, LDAP_OPT_NETWORK_TIMEOUT, &timeout); 
     406 
     407        rc = ldap_set_option(*ld, LDAP_OPT_NETWORK_TIMEOUT, &timeout); 
     408        if ( rc != LDAP_SUCCESS ) { 
     409                DBG2("Warning: failed to set connection timeout to %d: %s", timeout, ldap_err2string(rc)); 
     410        } else 
     411                DBG1("Set connection timeout to %d", timeout); 
     412#endif /* LDAP_OPT_NETWORK_TIMEOUT */ 
     413 
     414#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_NETWORK_TIMEOUT) 
     415        tv.tv_sec = bind_timelimit; 
     416        tv.tv_usec = 0; 
     417        ldap_set_option (*ld, LDAP_OPT_NETWORK_TIMEOUT, &tv); 
     418#endif /* LDAP_OPT_NETWORK_TIMEOUT */ 
     419 
     420 
     421#if defined(HAVE_LDAP_START_TLS_S) || defined(HAVE_LDAP_START_TLS) 
     422        if (ssl_on == SSL_START_TLS) 
     423    { 
     424                int version; 
     425 
     426                // we need V3 at least 
     427                if (ldap_get_option(*ld, LDAP_OPT_PROTOCOL_VERSION, 
     428                                                        &version) == LDAP_OPT_SUCCESS) 
     429                { 
     430                        if (ldapVersion < LDAP_VERSION3) 
     431                        { 
     432                                ldapVersion = LDAP_VERSION3; 
     433                                ldap_set_option (*ld, LDAP_OPT_PROTOCOL_VERSION, 
     434                                                &ldapVersion); 
     435                } 
     436                } 
     437 
     438                /* set up SSL context */ 
     439                if (do_ssl_options (*ld) != LDAP_SUCCESS) 
     440                { 
     441                        ldap_unbind (*ld); 
     442                        DBG("do_open(): SSL setup failed"); 
     443                        return LDAP_UNAVAILABLE; 
     444                } 
     445 
     446#ifdef HAVE_LDAP_START_TLS 
     447 
     448                DBG("do_open(): do_start_tls"); 
     449                rc = ldap_start_tls (*ld, NULL, NULL, &msgid); 
     450                if (rc != LDAP_SUCCESS) 
     451                { 
     452                  DBG1("do_open(): ldap_start_tls failed: %s", ldap_err2string (rc)); 
     453                  return rc; 
     454                } 
     455 
     456                if (bind_timelimit == LDAP_NO_LIMIT) 
     457                { 
     458                        tvp = NULL; 
     459        } 
     460                else 
     461        { 
     462                tv.tv_sec = bind_timelimit; 
     463                tv.tv_usec = 0; 
     464                tvp = &tv; 
     465        } 
     466 
     467                rc = ldap_result (*ld, msgid, 1, tvp, &res); 
     468                if (rc == -1) 
     469                { 
     470#if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER) 
     471                        if (ldap_get_option (*ld, LDAP_OPT_ERROR_NUMBER, &rc) != LDAP_SUCCESS) 
     472                        { 
     473                                rc = LDAP_UNAVAILABLE; 
     474                        } 
     475#else 
     476                        rc = ld->ld_errno; 
     477#endif /* LDAP_OPT_ERROR_NUMBER */ 
     478 
     479                        DBG1("do_open(): ldap_start_tls failed: %s", ldap_err2string (rc)); 
     480                        return rc; 
     481                } 
     482 
     483                rc = ldap_result2error (*ld, res, 1); 
     484                if (rc != LDAP_SUCCESS) 
     485                { 
     486                        DBG1("do_open(): ldap_result2error failed: %s)", ldap_err2string (rc)); 
     487                        return rc; 
     488                } 
     489 
     490                rc = ldap_install_tls (*ld); 
     491#else 
     492                rc = ldap_start_tls_s (*ld, NULL, NULL); 
     493#endif /* HAVE_LDAP_START_TLS */ 
     494 
     495                if (rc == LDAP_SUCCESS) 
     496                { 
     497                        DBG("do_open(): TLS startup succeeded"); 
     498                } 
     499                else 
     500                { 
     501                        ldap_unbind (*ld); 
     502                        DBG2("do_open(): TLS startup failed for LDAP server %s: %s", 
     503                             uri, ldap_err2string (rc)); 
     504                    return rc; 
     505                } 
     506        } 
     507        else 
     508#endif /* HAVE_LDAP_START_TLS_S || HAVE_LDAP_START_TLS */ 
     509 
     510        /* 
     511         * If SSL is desired, then enable it. 
     512         */ 
     513        if (ssl_on == SSL_LDAPS) 
     514    { 
     515#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS) 
     516                int tls = LDAP_OPT_X_TLS_HARD; 
     517                if (ldap_set_option (*ld, LDAP_OPT_X_TLS, &tls) != 
     518                        LDAP_SUCCESS) 
     519                { 
     520                        ldap_unbind (*ld); 
     521                        DBG("do_open(): TLS setup failed"); 
     522                        return LDAP_UNAVAILABLE; 
     523                } 
     524 
     525                /* set up SSL context */ 
     526                if (do_ssl_options (*ld) != LDAP_SUCCESS) 
     527                { 
     528                        ldap_unbind (*ld); 
     529                        DBG("do_open(): SSL setup failed"); 
     530                        return LDAP_UNAVAILABLE; 
     531                } 
     532#endif           
     533    } 
     534         
     535        rc = do_bind (*ld, bind_timelimit); 
     536        if (rc != LDAP_SUCCESS) 
     537        { 
     538                DBG2("do_open(): failed to bind to LDAP server %s: %s", 
     539                         uri, ldap_err2string (rc)); 
     540                ldap_unbind (*ld); 
     541        } 
     542        return rc; 
     543} 
     544 
     545/* 
     546 * add singe URI to array of uris 
     547 */ 
     548int ldap_add_uri (char **uris, const char *a_uri, char **buffer, size_t *buflen) 
     549{ 
     550        int i; 
     551        size_t uri_len; 
     552 
     553        for (i = 0; uris[i] != NULL; i++) 
     554    ; 
     555 
     556        if (i == LDAP_CONFIG_URI_MAX) 
     557        { 
     558                DBG("maximum number of URIs exceeded"); 
     559                return -1; 
     560        } 
     561 
     562        uri_len = strlen (a_uri); 
     563 
     564        if (*buflen < uri_len + 1) 
     565        { 
     566                DBG("buffer to small for URI"); 
     567                return -1; 
     568        } 
     569 
     570        memcpy (*buffer, a_uri, uri_len + 1); 
     571 
     572        uris[i] = *buffer; 
     573        uris[i + 1] = NULL; 
     574 
     575        *buffer += uri_len + 1; 
     576        *buflen -= uri_len + 1; 
     577 
     578        DBG1("added URI %s", a_uri); 
     579 
     580        return 0; 
     581} 
     582 
     583 
    70584 
    71585/** 
    72586* Get certificate from LDAP-Server. 
    73587*/ 
     588// not global then  
     589//  static int ldap_get_certificate(const char *login, X509*** ldap_x509) { 
    74590static int ldap_get_certificate(const char *login) { 
    75591        LDAP *ldap_connection; 
     
    82598        char filter_str[100]; 
    83599        char *attrs[2]; 
     600        int rv; 
     601        void *bv_val; 
     602 
     603        char uri[4096]; 
     604        char uribuf[4096]; 
     605        char *uris[LDAP_CONFIG_URI_MAX + 1]; 
     606        const char *p; 
     607        int current_uri = 0, start_uri = 0; 
     608 
     609        uris[0] = NULL; 
    84610 
    85611        attrs[0] = (char *)attribute; 
    86612        attrs[1] = NULL; 
    87          
    88613 
    89614        DBG1("ldap_get_certificate(): begin login = %s", login); 
    90615 
     616        // Put the login to the %s in Filterstring 
    91617        snprintf(filter_str, sizeof(filter_str), filter, login);  
    92618 
    93619        DBG1("ldap_get_certificate(): filter_str = %s", filter_str); 
    94620         
    95         ldap_connection = ldap_init(ldaphost, ldapport); 
    96         if ( NULL == ldap_connection) { 
    97                 DBG("ldap_init() failed"); 
     621        // parse and split URI config entry   
     622        char *buffer = uribuf; 
     623    size_t buflen = sizeof (uribuf); 
     624 
     625        strncpy(uri, ldapURI, sizeof (uri)-1); 
     626 
     627        /* Add a space separated list of URIs */ 
     628        // TODO: no spaces in one URI allowed => URL-encoding?  
     629        if(strncmp(ldapURI,"",1)) 
     630                for (p = uri; p != NULL; ) 
     631                { 
     632                        char *q = strchr (p, ' '); 
     633                        if (q != NULL) 
     634                                *q = '\0'; 
     635                         
     636                        if( strlen(p) > 1 ) // SAW: don't add spaces    
     637                                rv = ldap_add_uri (uris, p, &buffer, &buflen); 
     638                         
     639                        p = (q != NULL) ? ++q : NULL; 
     640                         
     641                        if (rv) 
     642                                break; 
     643                } 
     644    // set the default port if no port is given 
     645        if (ldapport == 0) 
     646    { 
     647                if (ssl_on == SSL_LDAPS) 
     648                { 
     649                  ldapport = LDAPS_PORT; 
     650                } 
     651                else 
     652                { 
     653                  ldapport = LDAP_PORT; 
     654                } 
     655        } 
     656 
     657        // add ldaphost to uris if set, nevermind "uri" is set in config 
     658        if( strlen(ldaphost) > 1 ) 
     659        { 
     660                /* No port specified in URI and non-default port specified */ 
     661                snprintf (uri, sizeof (uri), "%s%s:%d",  
     662                       ssl_on == SSL_LDAPS ? "ldaps://" : "ldap://", 
     663                       ldaphost, ldapport); 
     664                rv = ldap_add_uri (uris, uri, &buffer, &buflen); 
     665        } 
     666 
     667        if (uris[0] == NULL) 
     668    { 
     669                DBG("ldap_get_certificate(): Nor URI or useable Host entry found"); 
    98670                return(-1); 
    99         } 
    100  
    101         if ( 0 != ldap_simple_bind_s(ldap_connection, binddn, passwd)) { 
    102                 DBG("ldap_simple_bind_s() failed"); 
     671    } 
     672         
     673        /* Attempt to connect to specified URI in order until do_open succeed */ 
     674        start_uri = current_uri; 
     675        do 
     676        { 
     677                if(uris[current_uri] != NULL) 
     678                        DBG1("ldap_get_certificate(): try do_open for %s", uris[current_uri]); 
     679                rv = do_open(&ldap_connection, uris[current_uri], ldapport, ssl_on); 
     680                //  hot-fix, because in some circumstances an LDAP_SERVER_DOWN is returned   
     681                if (rv != LDAP_UNAVAILABLE && rv != LDAP_SERVER_DOWN) 
     682                        break; 
     683                current_uri++; 
     684                 
     685                if (uris[current_uri] == NULL) 
     686                        current_uri = 0; 
     687        } 
     688        while (current_uri != start_uri); 
     689         
     690        if( rv != LDAP_SUCCESS ) 
     691        { 
     692                DBG("ldap_get_certificate(): do_open failed"); 
    103693                return(-2); 
    104694        } 
    105695 
    106         if ( LDAP_SUCCESS != ldap_search_s(ldap_connection, base, LDAP_SCOPE_SUBTREE, filter_str, attrs, 0, &res)) { 
    107                 DBG("ldap_search_s() failed"); 
     696        /* TODO: (1) The problem: if an working uri is found it is used 
     697             and if there is an (SSL-)error, no other one is tried 
     698             (2) There is no session, so we don't know which LDAP_Server 
     699             is the last with a successful connection. So we try the same 
     700             server again. Perhaps create a state file/smem/etc. ? 
     701    */ 
     702 
     703        rv = ldap_search_s( 
     704                                ldap_connection,  
     705                                base,  
     706                                sscope[scope],  
     707                                filter_str,  
     708                                attrs,  
     709                                0,  
     710                                &res); 
     711        if ( rv != LDAP_SUCCESS ) { 
     712                DBG1("ldap_search_s() failed: %s", ldap_err2string(rv)); 
    108713                ldap_unbind_s(ldap_connection); 
    109714                return(-3); 
     
    112717                DBG1("ldap_get_certificate(): entries = %d", entries); 
    113718 
     719                if( entries > 1 ) { 
     720                        DBG("!  Warning, more than one entry found. Please choose \"filter\" and");  
     721                        DBG("!  \"attribute\" in ldap mapper config section of your config,"); 
     722                        DBG("!  that only one entry with one attribute is matched"); 
     723                        DBG("!  Maybe there is an other problem in ldap with not unique user"); 
     724                        DBG("!  entries in your LDAP server."); 
     725                } 
     726                                 
    114727                /* Only first entry is used. "filter" and "attribute"  
    115728                 *  should be choosen, so that only one entry with 
    116729                 * one attribute is returned */ 
    117730                if ( NULL == (entry = ldap_first_entry(ldap_connection, res))){ 
    118                         DBG("ldap_first_entry() failed"); 
     731                        DBG("ldap_first_entry() failed: %s"); 
    119732                        ldap_unbind_s(ldap_connection); 
    120733                        return(-4); 
     
    129742                DBG1("attribute name = %s", name); 
    130743 
    131                 /* TODO: Add support for multi-value attribute for usercertificate */ 
    132744                bvals = ldap_get_values_len(ldap_connection, entry, name); 
    133                 ldap_x509 = d2i_X509(NULL, (unsigned char **) &bvals[0]->bv_val, bvals[0]->bv_len); 
    134                 if (NULL == ldap_x509) { 
    135                         DBG("d2i_X509() failed"); 
    136                         ldap_msgfree(res); 
    137                         ldap_unbind_s(ldap_connection); 
    138                         return(-6); 
    139                 }else { 
    140                         DBG("d2i_X509(): success"); 
     745                certcnt = ldap_count_values_len(bvals); 
     746 
     747                DBG1("number auf usercertificates = %d", certcnt); 
     748         
     749                //*ldap_x509 = malloc(sizeof(X509*) * certcnt ); 
     750                ldap_x509 = malloc(sizeof(X509*) * certcnt ); 
     751                 
     752                rv = 0; 
     753                while(rv < certcnt ) 
     754                { 
     755                        // SaW: not nifty, but otherwise gcc doesn't optimize 
     756                        bv_val = &bvals[rv]->bv_val; 
     757                        ldap_x509[rv] = d2i_X509(NULL, ((const unsigned char **) bv_val), bvals[rv]->bv_len); 
     758                        if (NULL == ldap_x509) { 
     759                                DBG1("d2i_X509() failed for certificate %d", rv); 
     760                                free(ldap_x509);                                 
     761                                certcnt=0; 
     762                                ldap_msgfree(res); 
     763                                ldap_unbind_s(ldap_connection); 
     764                                return(-6); 
     765                        }else { 
     766                                DBG1("d2i_X509(): success for certificate %d", rv); 
     767                        } 
     768                        rv++; 
    141769                } 
    142770                ldap_msgfree(res); 
     771                // TODO: this leads to a segfault, but the doc said ... 
     772                //      ldap_value_free_len(bvals); 
    143773        } 
    144774        if ( 0 != (ret = ldap_unbind_s(ldap_connection))) { 
     
    156786        ldaphost = scconf_get_str(blk,"ldaphost",ldaphost); 
    157787        ldapport = scconf_get_int(blk,"ldapport",ldapport); 
     788        ldapURI = scconf_get_str(blk,"uri",ldapURI); 
    158789        scope = scconf_get_int(blk,"scope",scope); 
    159790        binddn = scconf_get_str(blk,"binddn",binddn); 
     
    165796        searchtimeout = scconf_get_int(blk,"searchtimeout",searchtimeout); 
    166797 
     798        const char *ssltls =  scconf_get_str(blk,"ssl","off"); 
     799        if (! strncasecmp (ssltls, "tls", 3))  
     800                ssl_on = SSL_START_TLS; 
     801        else if( ! strncasecmp (ssltls, "on", 2)) 
     802                ssl_on = SSL_LDAPS; 
     803        else if( ! strncasecmp (ssltls, "ssl", 3)) 
     804                ssl_on = SSL_LDAPS; 
     805                 
     806#if defined HAVE_LDAP_START_TLS_S || (defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS)) 
     807        /* TLS specific options */ 
     808        tls_randfile = scconf_get_str(blk,"tls_randfile",tls_randfile); 
     809        tls_cacertfile = scconf_get_str(blk,"tls_cacertfile",tls_cacertfile); 
     810        tls_cacertdir = scconf_get_str(blk,"tls_cacertdir",tls_cacertdir); 
     811        tls_checkpeer=scconf_get_int(blk,"tls_checkpeer",tls_checkpeer); 
     812        tls_ciphers = scconf_get_str(blk,"tls_ciphers",tls_ciphers); 
     813        tls_cert = scconf_get_str(blk,"tls_cert",tls_cert);  
     814        tls_key = scconf_get_str(blk,"tls_key",tls_key); 
     815#endif 
     816 
     817 
    167818        set_debug_level(debug); 
     819DBG1("test ssltls = %s", ssltls); 
    168820 
    169821        DBG("LDAP mapper started."); 
    170         DBG1("debug      = %d", debug); 
    171         DBG1("ignorecase = %d", ignorecase); 
    172         DBG1("ldaphost   = %s", ldaphost); 
    173         DBG1("ldapport   = %d", ldapport); 
    174         DBG1("scope      = %d", scope); 
    175         DBG1("binddn     = %s", binddn); 
    176         DBG1("passwd     = %s", passwd); 
    177         DBG1("base       = %s", base); 
    178         DBG1("attribute  = %s", attribute); 
    179         DBG1("filter     = %s", filter); 
     822        DBG1("debug         = %d", debug); 
     823        DBG1("ignorecase    = %d", ignorecase); 
     824        DBG1("ldaphost      = %s", ldaphost); 
     825        DBG1("ldapport      = %d", ldapport); 
     826        DBG1("ldapURI       = %s", ldapURI); 
     827        DBG1("scope         = %d", scope); 
     828        DBG1("binddn        = %s", binddn); 
     829        DBG1("passwd        = %s", passwd); 
     830        DBG1("base          = %s", base); 
     831        DBG1("attribute     = %s", attribute); 
     832        DBG1("filter        = %s", filter); 
     833        DBG1("searchtimeout = %d", searchtimeout); 
     834        DBG1("ssl_on        = %d", ssl_on); 
     835#if defined HAVE_LDAP_START_TLS_S || (defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS)) 
     836        DBG1("tls_randfile  = %s", tls_randfile); 
     837        DBG1("tls_cacertfile= %s", tls_cacertfile); 
     838        DBG1("tls_cacertdir = %s", tls_cacertdir); 
     839        DBG1("tls_checkpeer = %d", tls_checkpeer); 
     840        DBG1("tls_ciphers   = %s", tls_ciphers); 
     841        DBG1("tls_cert      = %s", tls_cert);  
     842        DBG1("tls_key       = %s", tls_key);     
     843#endif 
    180844        return 1; 
    181845 
     
    194858 
    195859static int ldap_mapper_match_user(X509 *x509, const char *login, void *context) { 
     860        //X509 **ldap_x509 = 0; 
    196861        int match_found = 0; 
    197  
     862        int i=0; 
     863 
     864        //if ( 1 != ldap_get_certificate(login, &ldap_x509)){ 
    198865        if ( 1 != ldap_get_certificate(login)){ 
    199866                DBG("ldap_get_certificate() failed"); 
     
    201868        } else { 
    202869                /* TODO: maybe compare public keys instead of hashes */ 
    203                 if ( 0 == X509_cmp(x509, ldap_x509)) { 
    204                         DBG("Certifcates matching"); 
    205                         match_found = 1; 
    206                 } else { 
    207                         DBG("Certifcates NOT matching"); 
    208                         match_found = 0; 
    209                 } 
     870                while( i<certcnt && !match_found ) { 
     871                        if ( 0 == X509_cmp(x509, ldap_x509[i])) { 
     872                                DBG1("Certificate %d is matching", i); 
     873                                match_found = 1; 
     874                        } else {  
     875                                DBG1("Certificate %d is NOT matching", i); 
     876                        } 
     877                        i++; 
     878                } 
     879                if (certcnt)  
     880                        free(ldap_x509); 
     881                certcnt=0; 
    210882        } 
    211883        return match_found; 
     
    229901        } 
    230902        endpwent(); 
     903 
     904#ifdef false 
     905        int res;         
     906        res= ldap_mapper_match_user(x509,"wefel",context); 
     907        if (res) { 
     908                        DBG("Certificate maps to user wefel"); 
     909                        found= clone_str("wefel"); 
     910        } else { 
     911                        DBG("Certificate map to user wefel failed"); 
     912        } 
     913#endif 
     914         
    231915        return found; 
    232916} 
     
    253937        mapper_module *pt; 
    254938 
    255         pt = init_mapper_st(blk,mapper_name); 
     939    pt = init_mapper_st(blk,mapper_name); 
    256940 
    257941        if (blk) { 
     
    261945                DBG1("No configuration entry for mapper '%s'. Assume defaults", mapper_name); 
    262946        } 
    263          
    264         return pt; 
    265 } 
     947    return pt; 
     948} 
Note: See TracChangeset for help on using the changeset viewer.