Back to index

lightning-sunbird  0.9+nobinonly
ldapsinit.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Mozilla Communicator client code, released
00015  * March 31, 1998.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*
00039  * ldapsinit.c
00040  */
00041 
00042 #if defined(NET_SSL)
00043 
00044 #if defined( _WINDOWS )
00045 #include <windows.h>
00046 #endif
00047 
00048 /* XXX:mhein The following is a workaround for the redefinition of */
00049 /*           const problem on OSF.  Fix to be provided by NSS */
00050 /*           This is a pretty benign workaround for us which */
00051 /*           should not cause problems in the future even if */
00052 /*           we forget to take it out :-) */
00053 
00054 #ifdef OSF1V4D
00055 #ifndef __STDC__
00056 #  define __STDC__
00057 #endif /* __STDC__ */
00058 #endif /* OSF1V4D */
00059 
00060 #include <errno.h>
00061 #include <nspr.h>
00062 #include <cert.h>
00063 #include <key.h>
00064 #include <ssl.h>
00065 #include <sslproto.h>
00066 #include <sslerr.h>
00067 #include <prnetdb.h>
00068 
00069 #include <ldap.h>
00070 #include <ldap_ssl.h>
00071 #include <ldappr.h>
00072 #include <pk11func.h>
00073 
00074 /*
00075  * Data structure to hold the standard NSPR I/O function pointers set by
00076  * libprldap.   We save them in our session data structure so we can call
00077  * them from our own I/O functions (we add functionality to support SSL
00078  * while using libprldap's functions as much as possible).
00079  */
00080 typedef struct ldapssl_std_functions {
00081     LDAP_X_EXTIOF_CLOSE_CALLBACK          *lssf_close_fn;
00082     LDAP_X_EXTIOF_CONNECT_CALLBACK        *lssf_connect_fn;
00083     LDAP_X_EXTIOF_DISPOSEHANDLE_CALLBACK  *lssf_disposehdl_fn;
00084 } LDAPSSLStdFunctions;
00085 
00086 
00087 
00088 /*
00089  * LDAP session data structure.
00090  */
00091 typedef struct ldapssl_session_info {
00092     int                     lssei_using_pcks_fns;
00093     char             *lssei_certnickname;
00094     char             *lssei_keypasswd;
00095     LDAPSSLStdFunctions     lssei_std_functions;
00096 } LDAPSSLSessionInfo;
00097 
00098 
00099 /*
00100  * LDAP socket data structure.
00101  */
00102 typedef struct ldapssl_socket_info {
00103     LDAPSSLSessionInfo      *soi_sessioninfo;    /* session info */
00104 } LDAPSSLSocketInfo;
00105 
00106 
00107 /* 
00108  * XXXceb  This is a hack until the new IO functions are done.
00109  * this function MUST be called before ldapssl_enable_clientauth.
00110  * right now, this function is called in ldapssl_pkcs_init();
00111  */
00112 
00113 static int using_pkcs_functions = 0;
00114 
00115 void set_using_pkcs_functions( int val )
00116 {
00117     using_pkcs_functions = val;
00118 }
00119 
00120 
00121 /* 
00122  * External functions... this function currently lives in clientinit.c
00123  */
00124 int get_ssl_strength( void );
00125 
00126 
00127 /*
00128  * Utility functions:
00129  */
00130 static void ldapssl_free_session_info( LDAPSSLSessionInfo **ssipp );
00131 static void ldapssl_free_socket_info( LDAPSSLSocketInfo **soipp );
00132 
00133 
00134 /*
00135  *  SSL Stuff 
00136  */
00137 
00138 static int ldapssl_AuthCertificate(void *certdbarg, PRFileDesc *fd,
00139        PRBool checkSig, PRBool isServer);
00140 
00141 /*
00142  * client auth stuff
00143  */
00144 static SECStatus get_clientauth_data( void *sessionarg, PRFileDesc *prfd,
00145        CERTDistNames *caNames,  CERTCertificate **pRetCert,
00146        SECKEYPrivateKey **pRetKey );
00147 static SECStatus get_keyandcert( LDAPSSLSessionInfo *ssip,
00148        CERTCertificate **pRetCert, SECKEYPrivateKey **pRetKey,
00149        char **errmsgp );
00150 static SECStatus check_clientauth_nicknames_and_passwd( LDAP *ld,
00151        LDAPSSLSessionInfo *ssip );
00152 static char *get_keypassword( PK11SlotInfo *slot, PRBool retry,
00153        void *sessionarg );
00154 
00155 /*
00156  * Like ldap_init(), except also install I/O routines from libsec so we
00157  * can support SSL.  If defsecure is non-zero, SSL is enabled for the
00158  * default connection as well.
00159  */
00160 LDAP *
00161 LDAP_CALL
00162 ldapssl_init( const char *defhost, int defport, int defsecure )
00163 {
00164     LDAP      *ld;
00165 
00166 
00167     if (0 ==defport)
00168        defport = LDAPS_PORT;
00169     
00170     if (( ld = ldap_init( defhost, defport )) == NULL ) {
00171        return( NULL );
00172     }
00173 
00174     if ( ldapssl_install_routines( ld ) < 0 || ldap_set_option( ld,
00175               LDAP_OPT_SSL, defsecure ? LDAP_OPT_ON : LDAP_OPT_OFF ) != 0 ) {
00176        PR_SetError( PR_UNKNOWN_ERROR, EINVAL );  /* XXXmcs: just a guess! */
00177        ldap_unbind( ld );
00178        return( NULL );
00179     }
00180 
00181     return( ld );
00182 }
00183 
00184 
00185 static int
00186 ldapssl_close(int s, struct lextiof_socket_private *socketarg)
00187 {
00188     PRLDAPSocketInfo soi;
00189     LDAPSSLSocketInfo       *ssoip;
00190     LDAPSSLSessionInfo      *sseip;
00191 
00192     memset( &soi, 0, sizeof(soi));
00193     soi.soinfo_size = PRLDAP_SOCKETINFO_SIZE;
00194     if ( prldap_get_socket_info( s, socketarg, &soi ) != LDAP_SUCCESS ) {
00195        return( -1 );
00196     }
00197 
00198     ssoip = (LDAPSSLSocketInfo *)soi.soinfo_appdata;
00199     sseip = ssoip->soi_sessioninfo;
00200 
00201     ldapssl_free_socket_info( (LDAPSSLSocketInfo **)&soi.soinfo_appdata );
00202 
00203     return( (*(sseip->lssei_std_functions.lssf_close_fn))( s, socketarg ));
00204 }
00205 
00206 
00207 static int
00208 do_ldapssl_connect(const char *hostlist, int defport, int timeout,
00209        unsigned long options, struct lextiof_session_private *sessionarg,
00210        struct lextiof_socket_private **socketargp, int clientauth )
00211 {
00212     int                     intfd = -1;
00213     PRBool           secure;
00214     PRLDAPSessionInfo       sei;
00215     PRLDAPSocketInfo soi;
00216     LDAPSSLSocketInfo       *ssoip = NULL;
00217     LDAPSSLSessionInfo      *sseip;
00218     PRFileDesc              *sslfd = NULL;
00219 
00220     /*
00221      * Determine if secure option is set.  Also, clear secure bit in options
00222      * the we pass to the standard connect() function (since it doesn't know
00223      * how to handle the secure option).
00224      */
00225     if ( 0 != ( options & LDAP_X_EXTIOF_OPT_SECURE )) {
00226        secure = PR_TRUE;
00227        options &= ~LDAP_X_EXTIOF_OPT_SECURE;
00228     } else {
00229        secure = PR_FALSE;
00230     }
00231 
00232     /*
00233      * Retrieve session info. so we can store a pointer to our session info.
00234      * in our socket info. later.
00235      */
00236     memset( &sei, 0, sizeof(sei));
00237     sei.seinfo_size = PRLDAP_SESSIONINFO_SIZE;
00238     if ( prldap_get_session_info( NULL, sessionarg, &sei ) != LDAP_SUCCESS ) {
00239        return( -1 );
00240     }
00241     sseip = (LDAPSSLSessionInfo *)sei.seinfo_appdata;
00242     
00243     /*
00244      * Call the standard connect() callback to make the TCP connection.  If it
00245      * succeeds, *socketargp is set.
00246      */
00247     intfd = (*(sseip->lssei_std_functions.lssf_connect_fn))( hostlist, defport,
00248               timeout, options, sessionarg, socketargp );
00249     if ( intfd < 0 ) {
00250        return( intfd );
00251     }
00252 
00253     /*
00254      * Retrieve socket info. so we have the PRFileDesc.
00255      */
00256     memset( &soi, 0, sizeof(soi));
00257     soi.soinfo_size = PRLDAP_SOCKETINFO_SIZE;
00258     if ( prldap_get_socket_info( intfd, *socketargp, &soi ) != LDAP_SUCCESS ) {
00259        goto close_socket_and_exit_with_error;
00260     }
00261 
00262     /*
00263      * Allocate a structure to hold our socket-specific data.
00264      */
00265     if ( NULL == ( ssoip = PR_Calloc( 1, sizeof( LDAPSSLSocketInfo )))) {
00266        goto close_socket_and_exit_with_error;
00267     }
00268     ssoip->soi_sessioninfo = sseip;
00269 
00270     /*
00271      * Add SSL layer and let the standard NSPR to LDAP layer and enable SSL.
00272      */
00273     if (( sslfd = SSL_ImportFD( NULL, soi.soinfo_prfd )) == NULL ) {
00274        goto close_socket_and_exit_with_error;
00275     }
00276 
00277     if ( SSL_OptionSet( sslfd, SSL_SECURITY, secure ) != SECSuccess ||
00278               SSL_OptionSet( sslfd, SSL_HANDSHAKE_AS_CLIENT, secure )
00279               != SECSuccess || ( secure && SSL_ResetHandshake( sslfd,
00280               PR_FALSE ) != SECSuccess )) {
00281        goto close_socket_and_exit_with_error;
00282     }
00283 
00284     /*
00285      * Set hostname which will be retrieved (depending on ssl strength) when
00286      * using client or server auth.
00287      */
00288     if ( SSL_SetURL( sslfd, hostlist ) != SECSuccess ) {
00289        goto close_socket_and_exit_with_error;
00290     }
00291 
00292     /*
00293      * Let the standard NSPR to LDAP layer know about the new socket and
00294      * our own socket-specific data.
00295      */
00296     soi.soinfo_prfd = sslfd;
00297     soi.soinfo_appdata = (void *)ssoip;
00298     if ( prldap_set_socket_info( intfd, *socketargp, &soi ) != LDAP_SUCCESS ) {
00299        goto close_socket_and_exit_with_error;
00300     }
00301     sslfd = NULL;    /* so we don't close the socket twice upon error */
00302 
00303     /*
00304      * Install certificate hook function.
00305      */
00306     SSL_AuthCertificateHook( soi.soinfo_prfd,
00307                           (SSLAuthCertificate)ldapssl_AuthCertificate, 
00308                           (void *)CERT_GetDefaultCertDB());
00309 
00310     if ( SSL_GetClientAuthDataHook( soi.soinfo_prfd,
00311               get_clientauth_data, clientauth ? sseip : NULL ) != 0 ) {
00312        goto close_socket_and_exit_with_error;
00313     }
00314 
00315     return( intfd ); /* success */
00316 
00317 close_socket_and_exit_with_error:
00318     if ( NULL != sslfd ) {
00319        PR_Close( sslfd );
00320     }
00321     if ( NULL != ssoip ) {
00322        ldapssl_free_socket_info( &ssoip );
00323     }
00324     if ( intfd >= 0 && NULL != *socketargp ) {
00325        (*(sseip->lssei_std_functions.lssf_close_fn))( intfd, *socketargp );
00326     }
00327     return( -1 );
00328 }
00329 
00330 
00331 static int
00332 ldapssl_connect(const char *hostlist, int defport, int timeout,
00333        unsigned long options, struct lextiof_session_private *sessionarg,
00334        struct lextiof_socket_private **socketargp )
00335 {
00336     return( do_ldapssl_connect( hostlist, defport, timeout, options,
00337               sessionarg, socketargp, 0 ));
00338 }
00339 
00340 
00341 static int
00342 ldapssl_clientauth_connect(const char *hostlist, int defport, int timeout,
00343        unsigned long options, struct lextiof_session_private *sessionarg,
00344        struct lextiof_socket_private **socketargp )
00345 {
00346     return( do_ldapssl_connect( hostlist, defport, timeout, options,
00347               sessionarg, socketargp, 1 ));
00348 }
00349 
00350 
00351 static void
00352 ldapssl_disposehandle(LDAP *ld, struct lextiof_session_private *sessionarg)
00353 {
00354     PRLDAPSessionInfo                            sei;
00355     LDAPSSLSessionInfo                           *sseip;
00356     LDAP_X_EXTIOF_DISPOSEHANDLE_CALLBACK  *disposehdl_fn;
00357 
00358     memset( &sei, 0, sizeof( sei ));
00359     sei.seinfo_size = PRLDAP_SESSIONINFO_SIZE;
00360     if ( prldap_get_session_info( ld, NULL, &sei ) == LDAP_SUCCESS ) {
00361        sseip = (LDAPSSLSessionInfo *)sei.seinfo_appdata;
00362        disposehdl_fn = sseip->lssei_std_functions.lssf_disposehdl_fn;
00363        ldapssl_free_session_info( &sseip );
00364        (*disposehdl_fn)( ld, sessionarg );
00365     }
00366 }
00367 
00368 
00369 /*
00370  * Install I/O routines from libsec and NSPR into libldap to allow libldap
00371  * to do SSL.
00372  *
00373  * We rely on libprldap to provide most of the functions, and then we override
00374  * a few of them to support SSL.
00375  */
00376 int
00377 LDAP_CALL
00378 ldapssl_install_routines( LDAP *ld )
00379 {
00380     struct ldap_x_ext_io_fns       iofns;
00381     LDAPSSLSessionInfo             *ssip;
00382     PRLDAPSessionInfo              sei;
00383 
00384     /* install standard NSPR functions */
00385     if ( prldap_install_routines(
00386               ld,
00387               1 /* shared -- we have to assume it is */ )
00388               != LDAP_SUCCESS ) {
00389        return( -1 );
00390     }
00391 
00392     /*
00393      * Allocate our own session information.
00394      */
00395     if ( NULL == ( ssip = (LDAPSSLSessionInfo *)PR_Calloc( 1,
00396               sizeof( LDAPSSLSessionInfo )))) {
00397        ldap_set_lderrno( ld, LDAP_NO_MEMORY, NULL, NULL );
00398        return( -1 );
00399     }
00400     ssip->lssei_using_pcks_fns = using_pkcs_functions;
00401 
00402     /*
00403      * override a few functions, saving a pointer to the standard function
00404      * in each case so we can call it from our SSL savvy functions.
00405      */
00406     memset( &iofns, 0, sizeof(iofns));
00407     iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
00408     if ( ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns ) < 0 ) {
00409        ldapssl_free_session_info( &ssip );
00410        return( -1 );
00411     }
00412 
00413     /* override socket, connect, and ioctl */
00414     ssip->lssei_std_functions.lssf_connect_fn = iofns.lextiof_connect;
00415     iofns.lextiof_connect = ldapssl_connect;
00416     ssip->lssei_std_functions.lssf_close_fn = iofns.lextiof_close;
00417     iofns.lextiof_close = ldapssl_close;
00418     ssip->lssei_std_functions.lssf_disposehdl_fn = iofns.lextiof_disposehandle;
00419     iofns.lextiof_disposehandle = ldapssl_disposehandle;
00420 
00421     if ( ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns ) < 0 ) {
00422        ldapssl_free_session_info( &ssip );
00423        return( -1 );
00424     }
00425 
00426     /*
00427      * Store session info. for later retrieval.
00428      */
00429     sei.seinfo_size = PRLDAP_SESSIONINFO_SIZE;
00430     sei.seinfo_appdata = (void *)ssip;
00431     if ( prldap_set_session_info( ld, NULL, &sei ) != LDAP_SUCCESS ) {
00432        return( -1 );
00433     }
00434 
00435     return( 0 );
00436 }
00437 
00438 
00439 int
00440 LDAP_CALL
00441 ldapssl_enable_clientauth( LDAP *ld, char *keynickname,
00442         char *keypasswd, char *certnickname )
00443 {
00444     struct ldap_x_ext_io_fns       iofns;
00445     LDAPSSLSessionInfo             *ssip;
00446     PRLDAPSessionInfo              sei;
00447 
00448     /*
00449      * Check parameters
00450      */
00451     if ( certnickname == NULL || keypasswd == NULL ) {
00452        ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
00453        return( -1 );
00454     }
00455 
00456     /*
00457      * Update session info. data structure.
00458      */
00459     sei.seinfo_size = PRLDAP_SESSIONINFO_SIZE;
00460     if ( prldap_get_session_info( ld, NULL, &sei ) != LDAP_SUCCESS ) {
00461        return( -1 );
00462     }
00463     ssip = (LDAPSSLSessionInfo *)sei.seinfo_appdata;
00464     if ( NULL == ssip ) {
00465        ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
00466        return( -1 );
00467     }
00468     ssip->lssei_certnickname = PL_strdup( certnickname );
00469     ssip->lssei_keypasswd = PL_strdup( keypasswd );
00470 
00471     if ( NULL == ssip->lssei_certnickname || NULL == ssip->lssei_keypasswd ) {
00472        ldap_set_lderrno( ld, LDAP_NO_MEMORY, NULL, NULL );
00473        return( -1 );
00474     }
00475 
00476     if ( check_clientauth_nicknames_and_passwd( ld, ssip ) != SECSuccess ) {
00477        return( -1 );
00478     }
00479 
00480     /*
00481      * replace standard SSL CONNECT function with client auth aware one
00482      */
00483     memset( &iofns, 0, sizeof(iofns));
00484     iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
00485     if ( ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns )
00486               != 0 ) {
00487        return( -1 );
00488     }
00489 
00490     if ( iofns.lextiof_connect != ldapssl_connect ) {
00491        /* standard SSL setup has not done */
00492        ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
00493        return( -1 );
00494     }
00495 
00496     iofns.lextiof_connect = ldapssl_clientauth_connect;
00497 
00498     if ( ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns )
00499               != 0 ) {
00500        return( -1 );
00501     }
00502 
00503     return( 0 );
00504 }
00505 
00506 
00507 static void
00508 ldapssl_free_session_info( LDAPSSLSessionInfo **ssipp )
00509 {
00510     if ( NULL != ssipp && NULL != *ssipp ) {
00511        if ( NULL != (*ssipp)->lssei_certnickname ) {
00512            PL_strfree( (*ssipp)->lssei_certnickname );
00513            (*ssipp)->lssei_certnickname = NULL;
00514        }
00515        if ( NULL != (*ssipp)->lssei_keypasswd ) {
00516            PL_strfree( (*ssipp)->lssei_keypasswd );
00517            (*ssipp)->lssei_keypasswd = NULL;
00518        }
00519        PR_Free( *ssipp );
00520        *ssipp = NULL;
00521     }
00522 }
00523 
00524 
00525 static void
00526 ldapssl_free_socket_info( LDAPSSLSocketInfo **soipp )
00527 {
00528     if ( NULL != soipp && NULL != *soipp ) {
00529        PR_Free( *soipp );
00530        *soipp = NULL;
00531     }
00532 }
00533 
00534 
00535 /* this function provides cert authentication.  This is called during 
00536  * the SSL_Handshake process.  Once the cert has been retrieved from
00537  * the server, the it is checked, using VerifyCertNow(), then 
00538  * the cn is checked against the host name, set with SSL_SetURL()
00539  */
00540 
00541 /*
00542  * XXXceb NOTE, this needs to be fixed to check for the MITM hack 980623
00543  */
00544 
00545 static int
00546 ldapssl_AuthCertificate(void *certdbarg, PRFileDesc *fd, PRBool checkSig,
00547        PRBool isServer)
00548 {
00549     SECStatus          rv = SECFailure;
00550     CERTCertDBHandle * handle;
00551     CERTCertificate * cert;
00552     SECCertUsage certUsage;
00553     char * hostname    = (char *)0;
00554     
00555     if (!certdbarg || !socket)
00556        return rv;
00557 
00558     if (LDAPSSL_AUTH_WEAK == get_ssl_strength() )
00559       return SECSuccess;
00560 
00561     handle = (CERTCertDBHandle *)certdbarg;
00562 
00563     if ( isServer ) {
00564        certUsage = certUsageSSLClient;
00565     } else {
00566        certUsage = certUsageSSLServer;
00567     }
00568     cert = SSL_PeerCertificate( fd );
00569     
00570     rv = CERT_VerifyCertNow(handle, cert, checkSig, certUsage, NULL);
00571 
00572     if ( rv != SECSuccess || isServer )
00573        return rv;
00574   
00575     if ( LDAPSSL_AUTH_CNCHECK == get_ssl_strength() )
00576       {
00577        /* cert is OK.  This is the client side of an SSL connection.
00578         * Now check the name field in the cert against the desired hostname.
00579         * NB: This is our only defense against Man-In-The-Middle (MITM) 
00580         * attacks!
00581         */
00582 
00583        hostname = SSL_RevealURL( fd );
00584 
00585        if (hostname && hostname[0]) {
00586          rv = CERT_VerifyCertName(cert, hostname);
00587        } else  {
00588          rv = SECFailure;
00589        }
00590        if (rv != SECSuccess)
00591          PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
00592       }
00593 
00594     return((int)rv);
00595 }
00596 
00597 
00598 /*
00599  * called during SSL client auth. when server wants our cert and key.
00600  * returns: SECSuccess if we succeeded and set *pRetCert and *pRetKey,
00601  *                   SECFailure otherwise.
00602  * if SECFailure is returned SSL will proceed without sending a cert.
00603  */
00604 
00605 static SECStatus
00606 get_clientauth_data( void *sessionarg, PRFileDesc *prfd,
00607         CERTDistNames *caNames,  CERTCertificate **pRetCert,
00608         SECKEYPrivateKey **pRetKey )
00609 
00610 {
00611     LDAPSSLSessionInfo      *ssip;
00612 
00613     if (( ssip = (LDAPSSLSessionInfo *)sessionarg ) == NULL ) {
00614        return( SECFailure );       /* client auth. not enabled */
00615     }
00616 
00617     return( get_keyandcert( ssip, pRetCert, pRetKey, NULL ));
00618 }
00619 
00620 static SECStatus
00621 get_keyandcert( LDAPSSLSessionInfo *ssip,
00622        CERTCertificate **pRetCert, SECKEYPrivateKey **pRetKey,
00623        char **errmsgp )
00624 {
00625     CERTCertificate  *cert;
00626     SECKEYPrivateKey *key;
00627 
00628     if (( cert = PK11_FindCertFromNickname( ssip->lssei_certnickname, NULL ))
00629               == NULL ) {
00630        if ( errmsgp != NULL ) {
00631            *errmsgp = "unable to find certificate";
00632        }
00633        return( SECFailure );
00634     }
00635 
00636     if (!ssip->lssei_using_pcks_fns)
00637     {
00638        PK11_SetPasswordFunc( get_keypassword );
00639     }
00640     
00641 
00642 
00643     if (( key = PK11_FindKeyByAnyCert( cert, (void *)ssip )) == NULL ) {
00644        CERT_DestroyCertificate( cert );
00645        if ( errmsgp != NULL ) {
00646            *errmsgp = "bad key or key password";
00647        }
00648        return( SECFailure );
00649     }
00650 
00651     *pRetCert = cert;
00652     *pRetKey = key;
00653     return( SECSuccess );
00654 }
00655 
00656 
00657 /* 
00658  * This function returns the password to NSS.
00659  * This function is enable through PK11_SetPasswordFunc
00660  * only if pkcs functions are not being used.
00661  */ 
00662 
00663 static char *
00664 get_keypassword( PK11SlotInfo *slot, PRBool retry, void *sessionarg )
00665 {
00666     LDAPSSLSessionInfo      *ssip;
00667 
00668     if ( retry)
00669       return (NULL);
00670 
00671     ssip = (LDAPSSLSessionInfo *)sessionarg;
00672     if ( NULL == ssip ) {
00673        return( NULL );
00674     }
00675 
00676     return( PL_strdup(ssip->lssei_keypasswd) );
00677 }
00678 
00679 
00680 /*
00681  * performs some basic checks on clientauth cert and key/password
00682  *
00683  * XXXmcs: could perform additional checks... see servers/slapd/ssl.c
00684  *     1) check expiration
00685  *     2) check that public key in cert matches private key
00686  * see ns/netsite/ldap/servers/slapd/ssl.c:slapd_ssl_init() for example code.
00687  */
00688 static SECStatus
00689 check_clientauth_nicknames_and_passwd( LDAP *ld, LDAPSSLSessionInfo *ssip )
00690 {
00691     char             *errmsg = NULL;
00692     CERTCertificate  *cert = NULL;
00693     SECKEYPrivateKey *key = NULL;
00694     SECStatus        rv;
00695 
00696     rv = get_keyandcert( ssip, &cert, &key, &errmsg );
00697 
00698     if ( rv != SECSuccess ) {
00699        if ( errmsg != NULL ) {
00700            errmsg = strdup( errmsg );
00701        }
00702        ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, errmsg );
00703        return( rv );
00704     }
00705 
00706     if ( cert != NULL ) {
00707        CERT_DestroyCertificate( cert );
00708     }
00709     if ( key != NULL ) {
00710        SECKEY_DestroyPrivateKey( key );
00711     }
00712     return( SECSuccess );
00713 }
00714 
00715 
00716 /* there are patches and kludges.  this is both.  force some linkers to 
00717  * link this stuff in
00718  */
00719 int stubs_o_stuff( void )
00720 {
00721     PRExplodedTime exploded;
00722     PLArenaPool pool;
00723   
00724     const char *name ="t";
00725     PRUint32 size = 0, align = 0;
00726 
00727     PR_ImplodeTime( &exploded );
00728     PL_InitArenaPool( &pool, name, size, align);
00729     PR_Cleanup();
00730     PR_fprintf((PRFileDesc*)stderr, "Bad IDEA!!");
00731 
00732     return 0;
00733 
00734 }
00735 #endif /* NET_SSL */