17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate /*
77c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the Netscape Public
87c478bd9Sstevel@tonic-gate  * License Version 1.1 (the "License"); you may not use this file
97c478bd9Sstevel@tonic-gate  * except in compliance with the License. You may obtain a copy of
107c478bd9Sstevel@tonic-gate  * the License at http://www.mozilla.org/NPL/
117c478bd9Sstevel@tonic-gate  *
127c478bd9Sstevel@tonic-gate  * Software distributed under the License is distributed on an "AS
137c478bd9Sstevel@tonic-gate  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
147c478bd9Sstevel@tonic-gate  * implied. See the License for the specific language governing
157c478bd9Sstevel@tonic-gate  * rights and limitations under the License.
167c478bd9Sstevel@tonic-gate  *
177c478bd9Sstevel@tonic-gate  * The Original Code is Mozilla Communicator client code, released
187c478bd9Sstevel@tonic-gate  * March 31, 1998.
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * The Initial Developer of the Original Code is Netscape
217c478bd9Sstevel@tonic-gate  * Communications Corporation. Portions created by Netscape are
227c478bd9Sstevel@tonic-gate  * Copyright (C) 1998-1999 Netscape Communications Corporation. All
237c478bd9Sstevel@tonic-gate  * Rights Reserved.
247c478bd9Sstevel@tonic-gate  *
257c478bd9Sstevel@tonic-gate  * Contributor(s):
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * ldapsinit.c
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #if defined(NET_SSL)
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #if defined( _WINDOWS )
357c478bd9Sstevel@tonic-gate #include <windows.h>
367c478bd9Sstevel@tonic-gate #endif
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate /* XXX:mhein The following is a workaround for the redefinition of */
397c478bd9Sstevel@tonic-gate /*           const problem on OSF.  Fix to be provided by NSS */
407c478bd9Sstevel@tonic-gate /*           This is a pretty benign workaround for us which */
417c478bd9Sstevel@tonic-gate /*           should not cause problems in the future even if */
427c478bd9Sstevel@tonic-gate /*           we forget to take it out :-) */
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate #ifdef OSF1V4D
457c478bd9Sstevel@tonic-gate #ifndef __STDC__
467c478bd9Sstevel@tonic-gate #  define __STDC__
477c478bd9Sstevel@tonic-gate #endif /* __STDC__ */
487c478bd9Sstevel@tonic-gate #endif /* OSF1V4D */
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate #include <errno.h>
517c478bd9Sstevel@tonic-gate #include <nspr.h>
527c478bd9Sstevel@tonic-gate #include <cert.h>
537c478bd9Sstevel@tonic-gate #include <key.h>
547c478bd9Sstevel@tonic-gate #include <ssl.h>
557c478bd9Sstevel@tonic-gate #include <sslproto.h>
567c478bd9Sstevel@tonic-gate #include <sslerr.h>
577c478bd9Sstevel@tonic-gate #include <prnetdb.h>
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate #include <ldap.h>
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate #include <ldappr.h>
627c478bd9Sstevel@tonic-gate #include <pk11func.h>
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate #ifdef _SOLARIS_SDK
657c478bd9Sstevel@tonic-gate #include "solaris-int.h"
667c478bd9Sstevel@tonic-gate #include <libintl.h>
677c478bd9Sstevel@tonic-gate #include <syslog.h>
687c478bd9Sstevel@tonic-gate #include <nsswitch.h>
697c478bd9Sstevel@tonic-gate #include <synch.h>
707c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h>
717c478bd9Sstevel@tonic-gate #include <netinet/in.h>
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate #define	HOST_BUF_SIZE	2048
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate #ifndef INADDR_NONE
767c478bd9Sstevel@tonic-gate #define	INADDR_NONE (-1)
777c478bd9Sstevel@tonic-gate #endif
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate extern int
807c478bd9Sstevel@tonic-gate str2hostent(const char *instr, int lenstr, void *ent, char *buffer,
817c478bd9Sstevel@tonic-gate 		int buflen);
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate extern int
847c478bd9Sstevel@tonic-gate str2hostent6(const char *instr, int lenstr, void *ent, char *buffer,
857c478bd9Sstevel@tonic-gate 		int buflen);
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate extern LDAPHostEnt *
887c478bd9Sstevel@tonic-gate _ns_gethostbyaddr(LDAP *ld, const char *addr, int length, int type,
897c478bd9Sstevel@tonic-gate 	LDAPHostEnt *result, char *buffer, int buflen, int *statusp,
907c478bd9Sstevel@tonic-gate 	void *extradata);
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate static char *host_service = NULL;
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(db_root_hosts);
957c478bd9Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(db_root_ipnodes);
967c478bd9Sstevel@tonic-gate #endif
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate /*
997c478bd9Sstevel@tonic-gate  * Data structure to hold the standard NSPR I/O function pointers set by
1007c478bd9Sstevel@tonic-gate  * libprldap.   We save them in our session data structure so we can call
1017c478bd9Sstevel@tonic-gate  * them from our own I/O functions (we add functionality to support SSL
1027c478bd9Sstevel@tonic-gate  * while using libprldap's functions as much as possible).
1037c478bd9Sstevel@tonic-gate  */
1047c478bd9Sstevel@tonic-gate typedef struct ldapssl_std_functions {
1057c478bd9Sstevel@tonic-gate     LDAP_X_EXTIOF_CLOSE_CALLBACK		*lssf_close_fn;
1067c478bd9Sstevel@tonic-gate     LDAP_X_EXTIOF_CONNECT_CALLBACK		*lssf_connect_fn;
1077c478bd9Sstevel@tonic-gate     LDAP_X_EXTIOF_DISPOSEHANDLE_CALLBACK	*lssf_disposehdl_fn;
1087c478bd9Sstevel@tonic-gate } LDAPSSLStdFunctions;
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate /*
1137c478bd9Sstevel@tonic-gate  * LDAP session data structure.
1147c478bd9Sstevel@tonic-gate  */
1157c478bd9Sstevel@tonic-gate typedef struct ldapssl_session_info {
1167c478bd9Sstevel@tonic-gate     int                 lssei_using_pcks_fns;
1177c478bd9Sstevel@tonic-gate     int                 lssei_ssl_strength;
1187c478bd9Sstevel@tonic-gate     char                *lssei_certnickname;
1197c478bd9Sstevel@tonic-gate     char                *lssei_keypasswd;
1207c478bd9Sstevel@tonic-gate     LDAPSSLStdFunctions lssei_std_functions;
1217c478bd9Sstevel@tonic-gate     CERTCertDBHandle    *lssei_certdbh;
1227c478bd9Sstevel@tonic-gate #ifdef _SOLARIS_SDK
1237c478bd9Sstevel@tonic-gate 	/*
1247c478bd9Sstevel@tonic-gate 	 * This is a hack.
1257c478bd9Sstevel@tonic-gate 	 * ld is used so that we can use libldap's gethostbyaddr
1267c478bd9Sstevel@tonic-gate 	 * resolver. This is needed to prevent recursion with libsldap.
1277c478bd9Sstevel@tonic-gate 	 */
1287c478bd9Sstevel@tonic-gate     LDAP		*ld;
1297c478bd9Sstevel@tonic-gate #endif	/* _SOLARIS_SDK */
1307c478bd9Sstevel@tonic-gate } LDAPSSLSessionInfo;
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate /*
1347c478bd9Sstevel@tonic-gate  * LDAP socket data structure.
1357c478bd9Sstevel@tonic-gate  */
1367c478bd9Sstevel@tonic-gate typedef struct ldapssl_socket_info {
1377c478bd9Sstevel@tonic-gate     LDAPSSLSessionInfo	*soi_sessioninfo;	/* session info */
1387c478bd9Sstevel@tonic-gate } LDAPSSLSocketInfo;
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 
141*1da57d55SToomas Soome /*
1427c478bd9Sstevel@tonic-gate  * XXXceb  This is a hack until the new IO functions are done.
1437c478bd9Sstevel@tonic-gate  * this function MUST be called before ldap_enable_clienauth.
1447c478bd9Sstevel@tonic-gate  * right now, this function is called in ldapssl_pkcs_init();
1457c478bd9Sstevel@tonic-gate  */
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate static int using_pkcs_functions = 0;
1487c478bd9Sstevel@tonic-gate 
set_using_pkcs_functions(int val)1497c478bd9Sstevel@tonic-gate void set_using_pkcs_functions( int val )
1507c478bd9Sstevel@tonic-gate {
1517c478bd9Sstevel@tonic-gate     using_pkcs_functions = val;
1527c478bd9Sstevel@tonic-gate }
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate /*
1567c478bd9Sstevel@tonic-gate  * Utility functions:
1577c478bd9Sstevel@tonic-gate  */
1587c478bd9Sstevel@tonic-gate static void ldapssl_free_session_info( LDAPSSLSessionInfo **ssipp );
1597c478bd9Sstevel@tonic-gate static void ldapssl_free_socket_info( LDAPSSLSocketInfo **soipp );
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate /*
163*1da57d55SToomas Soome  *  SSL Stuff
1647c478bd9Sstevel@tonic-gate  */
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate static int ldapssl_AuthCertificate(void *sessionarg, PRFileDesc *fd,
1677c478bd9Sstevel@tonic-gate         PRBool checkSig, PRBool isServer);
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate /*
1707c478bd9Sstevel@tonic-gate  * client auth stuff
1717c478bd9Sstevel@tonic-gate  */
1727c478bd9Sstevel@tonic-gate static int get_clientauth_data( void *sessionarg, PRFileDesc *prfd,
1737c478bd9Sstevel@tonic-gate 	CERTDistNames *caNames,  CERTCertificate **pRetCert,
1747c478bd9Sstevel@tonic-gate 	SECKEYPrivateKey **pRetKey );
1757c478bd9Sstevel@tonic-gate static int get_keyandcert( LDAPSSLSessionInfo *ssip,
1767c478bd9Sstevel@tonic-gate 	CERTCertificate **pRetCert, SECKEYPrivateKey **pRetKey,
1777c478bd9Sstevel@tonic-gate 	char **errmsgp );
1787c478bd9Sstevel@tonic-gate static int check_clientauth_nicknames_and_passwd( LDAP *ld,
1797c478bd9Sstevel@tonic-gate 	LDAPSSLSessionInfo *ssip );
1807c478bd9Sstevel@tonic-gate static char *get_keypassword( PK11SlotInfo *slot, PRBool retry,
1817c478bd9Sstevel@tonic-gate 	void *sessionarg );
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate /*
1847c478bd9Sstevel@tonic-gate  * Static variables.
1857c478bd9Sstevel@tonic-gate  */
1867c478bd9Sstevel@tonic-gate #ifdef _SOLARIS_SDK
1877c478bd9Sstevel@tonic-gate static int default_ssl_strength = LDAPSSL_AUTH_CNCHECK;
1887c478bd9Sstevel@tonic-gate #else
1897c478bd9Sstevel@tonic-gate static int default_ssl_strength = LDAPSSL_AUTH_CERT;
1907c478bd9Sstevel@tonic-gate #endif
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate /*
1937c478bd9Sstevel@tonic-gate  * Like ldap_init(), except also install I/O routines from libsec so we
1947c478bd9Sstevel@tonic-gate  * can support SSL.  If defsecure is non-zero, SSL is enabled for the
1957c478bd9Sstevel@tonic-gate  * default connection as well.
1967c478bd9Sstevel@tonic-gate  */
1977c478bd9Sstevel@tonic-gate LDAP *
1987c478bd9Sstevel@tonic-gate LDAP_CALL
ldapssl_init(const char * defhost,int defport,int defsecure)1997c478bd9Sstevel@tonic-gate ldapssl_init( const char *defhost, int defport, int defsecure )
2007c478bd9Sstevel@tonic-gate {
2017c478bd9Sstevel@tonic-gate     LDAP	*ld;
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate #ifndef LDAP_SSLIO_HOOKS
2057c478bd9Sstevel@tonic-gate     return( NULL );
2067c478bd9Sstevel@tonic-gate #else
2077c478bd9Sstevel@tonic-gate     if (0 ==defport)
2087c478bd9Sstevel@tonic-gate 	defport = LDAPS_PORT;
209*1da57d55SToomas Soome 
2107c478bd9Sstevel@tonic-gate     if (( ld = ldap_init( defhost, defport )) == NULL ) {
2117c478bd9Sstevel@tonic-gate 	return( NULL );
2127c478bd9Sstevel@tonic-gate     }
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate     if ( ldapssl_install_routines( ld ) < 0 || ldap_set_option( ld,
2157c478bd9Sstevel@tonic-gate 		LDAP_OPT_SSL, defsecure ? LDAP_OPT_ON : LDAP_OPT_OFF ) != 0 ) {
2167c478bd9Sstevel@tonic-gate 	PR_SetError( PR_UNKNOWN_ERROR, EINVAL );  /* XXXmcs: just a guess! */
2177c478bd9Sstevel@tonic-gate 	ldap_unbind( ld );
2187c478bd9Sstevel@tonic-gate 	return( NULL );
2197c478bd9Sstevel@tonic-gate     }
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate     return( ld );
2227c478bd9Sstevel@tonic-gate #endif
2237c478bd9Sstevel@tonic-gate }
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate static int
ldapssl_close(int s,struct lextiof_socket_private * socketarg)2277c478bd9Sstevel@tonic-gate ldapssl_close(int s, struct lextiof_socket_private *socketarg)
2287c478bd9Sstevel@tonic-gate {
2297c478bd9Sstevel@tonic-gate     PRLDAPSocketInfo	soi;
2307c478bd9Sstevel@tonic-gate     LDAPSSLSocketInfo	*ssoip;
2317c478bd9Sstevel@tonic-gate     LDAPSSLSessionInfo	*sseip;
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate     memset( &soi, 0, sizeof(soi));
2347c478bd9Sstevel@tonic-gate     soi.soinfo_size = PRLDAP_SOCKETINFO_SIZE;
2357c478bd9Sstevel@tonic-gate     if ( prldap_get_socket_info( s, socketarg, &soi ) != LDAP_SUCCESS ) {
2367c478bd9Sstevel@tonic-gate 	return( -1 );
2377c478bd9Sstevel@tonic-gate     }
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate     ssoip = (LDAPSSLSocketInfo *)soi.soinfo_appdata;
2407c478bd9Sstevel@tonic-gate     sseip = ssoip->soi_sessioninfo;
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate     ldapssl_free_socket_info( (LDAPSSLSocketInfo **)&soi.soinfo_appdata );
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate     return( (*(sseip->lssei_std_functions.lssf_close_fn))( s, socketarg ));
2457c478bd9Sstevel@tonic-gate }
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate static int
do_ldapssl_connect(const char * hostlist,int defport,int timeout,unsigned long options,struct lextiof_session_private * sessionarg,struct lextiof_socket_private ** socketargp,int clientauth)2487c478bd9Sstevel@tonic-gate do_ldapssl_connect(const char *hostlist, int defport, int timeout,
2497c478bd9Sstevel@tonic-gate 	unsigned long options, struct lextiof_session_private *sessionarg,
2507c478bd9Sstevel@tonic-gate 	struct lextiof_socket_private **socketargp, int clientauth )
2517c478bd9Sstevel@tonic-gate {
2527c478bd9Sstevel@tonic-gate     int			intfd = -1;
2537c478bd9Sstevel@tonic-gate     PRBool		secure;
2547c478bd9Sstevel@tonic-gate     PRLDAPSessionInfo	sei;
2557c478bd9Sstevel@tonic-gate     PRLDAPSocketInfo	soi;
2567c478bd9Sstevel@tonic-gate     LDAPSSLSocketInfo	*ssoip = NULL;
2577c478bd9Sstevel@tonic-gate     LDAPSSLSessionInfo	*sseip;
2587c478bd9Sstevel@tonic-gate     PRFileDesc		*sslfd = NULL;
2597c478bd9Sstevel@tonic-gate #ifdef _SOLARIS_SDK
2607c478bd9Sstevel@tonic-gate     int			port;
2617c478bd9Sstevel@tonic-gate     int			parse_err;
2627c478bd9Sstevel@tonic-gate     char		*host = NULL;
2637c478bd9Sstevel@tonic-gate     char		*name;
2647c478bd9Sstevel@tonic-gate     struct ldap_x_hostlist_status
2657c478bd9Sstevel@tonic-gate 			*status = NULL;
2667c478bd9Sstevel@tonic-gate     in_addr_t		addr_ipv4;
2677c478bd9Sstevel@tonic-gate     in6_addr_t		addr_ipv6;
2687c478bd9Sstevel@tonic-gate     char		*host_buf;
2697c478bd9Sstevel@tonic-gate     LDAPHostEnt		*hent;
2707c478bd9Sstevel@tonic-gate     LDAPHostEnt		host_ent;
2717c478bd9Sstevel@tonic-gate     int			stat;
2727c478bd9Sstevel@tonic-gate     int			type;
2737c478bd9Sstevel@tonic-gate #endif	/* _SOLARIS_SDK */
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate     /*
2767c478bd9Sstevel@tonic-gate      * Determine if secure option is set.  Also, clear secure bit in options
2777c478bd9Sstevel@tonic-gate      * the we pass to the standard connect() function (since it doesn't know
2787c478bd9Sstevel@tonic-gate      * how to handle the secure option).
2797c478bd9Sstevel@tonic-gate      */
2807c478bd9Sstevel@tonic-gate     if ( 0 != ( options & LDAP_X_EXTIOF_OPT_SECURE )) {
2817c478bd9Sstevel@tonic-gate 	secure = PR_TRUE;
2827c478bd9Sstevel@tonic-gate 	options &= ~LDAP_X_EXTIOF_OPT_SECURE;
2837c478bd9Sstevel@tonic-gate     } else {
2847c478bd9Sstevel@tonic-gate 	secure = PR_FALSE;
2857c478bd9Sstevel@tonic-gate     }
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate     /*
2887c478bd9Sstevel@tonic-gate      * Retrieve session info. so we can store a pointer to our session info.
2897c478bd9Sstevel@tonic-gate      * in our socket info. later.
2907c478bd9Sstevel@tonic-gate      */
2917c478bd9Sstevel@tonic-gate     memset( &sei, 0, sizeof(sei));
2927c478bd9Sstevel@tonic-gate     sei.seinfo_size = PRLDAP_SESSIONINFO_SIZE;
2937c478bd9Sstevel@tonic-gate     if ( prldap_get_session_info( NULL, sessionarg, &sei ) != LDAP_SUCCESS ) {
2947c478bd9Sstevel@tonic-gate 	return( -1 );
2957c478bd9Sstevel@tonic-gate     }
2967c478bd9Sstevel@tonic-gate     sseip = (LDAPSSLSessionInfo *)sei.seinfo_appdata;
297*1da57d55SToomas Soome 
2987c478bd9Sstevel@tonic-gate     /*
2997c478bd9Sstevel@tonic-gate      * Call the standard connect() callback to make the TCP connection.
3007c478bd9Sstevel@tonic-gate      * If it succeeds, *socketargp is set.
3017c478bd9Sstevel@tonic-gate      */
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate     intfd = (*(sseip->lssei_std_functions.lssf_connect_fn))( hostlist, defport,
3047c478bd9Sstevel@tonic-gate 		timeout, options, sessionarg, socketargp
3057c478bd9Sstevel@tonic-gate #ifdef _SOLARIS_SDK
3067c478bd9Sstevel@tonic-gate 		, &host );
3077c478bd9Sstevel@tonic-gate #else
3087c478bd9Sstevel@tonic-gate 		);
3097c478bd9Sstevel@tonic-gate #endif	/* _SOLARIS_SDK */
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate     if ( intfd < 0 ) {
3127c478bd9Sstevel@tonic-gate 	return( intfd );
3137c478bd9Sstevel@tonic-gate     }
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate #ifdef _SOLARIS_SDK
3167c478bd9Sstevel@tonic-gate         /*
3177c478bd9Sstevel@tonic-gate          * Determine if the "host name" is an ip address. If so,
3187c478bd9Sstevel@tonic-gate          * we must look up the actual host name corresponding to
3197c478bd9Sstevel@tonic-gate          * it.
3207c478bd9Sstevel@tonic-gate          */
3217c478bd9Sstevel@tonic-gate 	if ( NULL == host ) {
3227c478bd9Sstevel@tonic-gate 		goto close_socket_and_exit_with_error;
3237c478bd9Sstevel@tonic-gate 	}
3247c478bd9Sstevel@tonic-gate         type = AF_UNSPEC;
3257c478bd9Sstevel@tonic-gate         if (strlen(host) < INET6_ADDRSTRLEN &&
3267c478bd9Sstevel@tonic-gate                         inet_pton(AF_INET6, host, &addr_ipv6) == 1) {
3277c478bd9Sstevel@tonic-gate                 type = AF_INET6;
3287c478bd9Sstevel@tonic-gate         } else if (strlen(host) < INET_ADDRSTRLEN &&
3297c478bd9Sstevel@tonic-gate                         inet_pton(AF_INET, host, &addr_ipv4) == 1) {
3307c478bd9Sstevel@tonic-gate                 type = AF_INET;
3317c478bd9Sstevel@tonic-gate         }
3327c478bd9Sstevel@tonic-gate         if (type == AF_INET || type == AF_INET6) {
3337c478bd9Sstevel@tonic-gate                 host_buf = malloc(HOST_BUF_SIZE);
3347c478bd9Sstevel@tonic-gate                 if (host_buf == NULL) {
3357c478bd9Sstevel@tonic-gate 			/* will free host in close_socket_and_exit_with_error */
3367c478bd9Sstevel@tonic-gate                         goto close_socket_and_exit_with_error;
3377c478bd9Sstevel@tonic-gate 		}
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate                 /* Call ldap layer's gethostbyaddr resolver */
3407c478bd9Sstevel@tonic-gate                 hent = _ns_gethostbyaddr(sseip->ld, host, strlen(host), type,
3417c478bd9Sstevel@tonic-gate                         &host_ent, host_buf, HOST_BUF_SIZE, &stat, NULL);
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate                 /* If we are unable to lookup the host addr, we fail! */
3447c478bd9Sstevel@tonic-gate                 if (hent == NULL) {
3457c478bd9Sstevel@tonic-gate                         syslog(LOG_WARNING,
3467c478bd9Sstevel@tonic-gate                                 "libldap: do_ldapssl_connect: "
3477c478bd9Sstevel@tonic-gate                                 "Unable to resolve '%s'", host);
3487c478bd9Sstevel@tonic-gate                         free(host_buf);
3497c478bd9Sstevel@tonic-gate 			/* will free host in close_socket_and_exit_with_error */
3507c478bd9Sstevel@tonic-gate 			goto close_socket_and_exit_with_error;
3517c478bd9Sstevel@tonic-gate                 }
3527c478bd9Sstevel@tonic-gate                 /* We support only the primary host name */
3537c478bd9Sstevel@tonic-gate                 else {
3547c478bd9Sstevel@tonic-gate 			if (hent->ldaphe_name != NULL)
3557c478bd9Sstevel@tonic-gate                         	name = strdup(hent->ldaphe_name);
3567c478bd9Sstevel@tonic-gate                 	free(host_buf);
3577c478bd9Sstevel@tonic-gate                 	if (name == NULL)
3587c478bd9Sstevel@tonic-gate                         	goto close_socket_and_exit_with_error;
3597c478bd9Sstevel@tonic-gate 			else
3607c478bd9Sstevel@tonic-gate                 		ldap_memfree(host); host = NULL;
3617c478bd9Sstevel@tonic-gate                 	host = name;
3627c478bd9Sstevel@tonic-gate 		}
3637c478bd9Sstevel@tonic-gate         }
3647c478bd9Sstevel@tonic-gate #endif	/* _SOLARIS_SDK */
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate     /*
3677c478bd9Sstevel@tonic-gate      * Retrieve socket info. so we have the PRFileDesc.
3687c478bd9Sstevel@tonic-gate      */
3697c478bd9Sstevel@tonic-gate     memset( &soi, 0, sizeof(soi));
3707c478bd9Sstevel@tonic-gate     soi.soinfo_size = PRLDAP_SOCKETINFO_SIZE;
3717c478bd9Sstevel@tonic-gate     if ( prldap_get_socket_info( intfd, *socketargp, &soi ) != LDAP_SUCCESS ) {
3727c478bd9Sstevel@tonic-gate 	goto close_socket_and_exit_with_error;
3737c478bd9Sstevel@tonic-gate     }
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate     /*
3767c478bd9Sstevel@tonic-gate      * Allocate a structure to hold our socket-specific data.
3777c478bd9Sstevel@tonic-gate      */
3787c478bd9Sstevel@tonic-gate     if ( NULL == ( ssoip = PR_Calloc( 1, sizeof( LDAPSSLSocketInfo )))) {
3797c478bd9Sstevel@tonic-gate 	goto close_socket_and_exit_with_error;
3807c478bd9Sstevel@tonic-gate     }
3817c478bd9Sstevel@tonic-gate     ssoip->soi_sessioninfo = sseip;
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate     /*
3847c478bd9Sstevel@tonic-gate      * Add SSL layer and let the standard NSPR to LDAP layer and enable SSL.
3857c478bd9Sstevel@tonic-gate      */
3867c478bd9Sstevel@tonic-gate     if (( sslfd = SSL_ImportFD( NULL, soi.soinfo_prfd )) == NULL ) {
3877c478bd9Sstevel@tonic-gate 	goto close_socket_and_exit_with_error;
3887c478bd9Sstevel@tonic-gate     }
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate     if ( SSL_OptionSet( sslfd, SSL_SECURITY, secure ) != SECSuccess ||
3917c478bd9Sstevel@tonic-gate 		SSL_OptionSet( sslfd, SSL_HANDSHAKE_AS_CLIENT, secure )
3927c478bd9Sstevel@tonic-gate 		!= SECSuccess || ( secure && SSL_ResetHandshake( sslfd,
3937c478bd9Sstevel@tonic-gate 		PR_FALSE ) != SECSuccess )) {
3947c478bd9Sstevel@tonic-gate 	goto close_socket_and_exit_with_error;
3957c478bd9Sstevel@tonic-gate     }
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate     /*
3987c478bd9Sstevel@tonic-gate      * Let the standard NSPR to LDAP layer know about the new socket and
3997c478bd9Sstevel@tonic-gate      * our own socket-specific data.
4007c478bd9Sstevel@tonic-gate      */
4017c478bd9Sstevel@tonic-gate     soi.soinfo_prfd = sslfd;
4027c478bd9Sstevel@tonic-gate     soi.soinfo_appdata = (void *)ssoip;
4037c478bd9Sstevel@tonic-gate     if ( prldap_set_socket_info( intfd, *socketargp, &soi ) != LDAP_SUCCESS ) {
4047c478bd9Sstevel@tonic-gate 	goto close_socket_and_exit_with_error;
4057c478bd9Sstevel@tonic-gate     }
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate #ifdef _SOLARIS_SDK
4087c478bd9Sstevel@tonic-gate     /*
4097c478bd9Sstevel@tonic-gate      * Set hostname which will be retrieved (depending on ssl strength) when
4107c478bd9Sstevel@tonic-gate      * using client or server auth.
4117c478bd9Sstevel@tonic-gate      */
4127c478bd9Sstevel@tonic-gate     if (SSL_SetURL(sslfd, host) != SECSuccess)
4137c478bd9Sstevel@tonic-gate 	goto close_socket_and_exit_with_error;
4147c478bd9Sstevel@tonic-gate     ldap_memfree(host);
4157c478bd9Sstevel@tonic-gate     host = NULL;
4167c478bd9Sstevel@tonic-gate #endif /* _SOLARIS_SDK */
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate     sslfd = NULL;	/* so we don't close the socket twice upon error */
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate     /*
4217c478bd9Sstevel@tonic-gate      * Install certificate hook function.
4227c478bd9Sstevel@tonic-gate      */
4237c478bd9Sstevel@tonic-gate     SSL_AuthCertificateHook( soi.soinfo_prfd,
424*1da57d55SToomas Soome 			     (SSLAuthCertificate)ldapssl_AuthCertificate,
4257c478bd9Sstevel@tonic-gate                              (void *)sseip);
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate     if ( SSL_GetClientAuthDataHook( soi.soinfo_prfd,
4287c478bd9Sstevel@tonic-gate 		get_clientauth_data, clientauth ? sseip : NULL ) != 0 ) {
4297c478bd9Sstevel@tonic-gate 	goto close_socket_and_exit_with_error;
4307c478bd9Sstevel@tonic-gate     }
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate     return( intfd );	/* success */
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate close_socket_and_exit_with_error:
4357c478bd9Sstevel@tonic-gate #ifdef _SOLARIS_SDK
4367c478bd9Sstevel@tonic-gate     if ( NULL != host ) ldap_memfree(host);
4377c478bd9Sstevel@tonic-gate #endif /* _SOLARIS_SDK */
4387c478bd9Sstevel@tonic-gate     if ( NULL != sslfd ) {
4397c478bd9Sstevel@tonic-gate 	PR_Close( sslfd );
4407c478bd9Sstevel@tonic-gate     }
4417c478bd9Sstevel@tonic-gate     if ( NULL != ssoip ) {
4427c478bd9Sstevel@tonic-gate 	ldapssl_free_socket_info( &ssoip );
4437c478bd9Sstevel@tonic-gate     }
4447c478bd9Sstevel@tonic-gate     if ( intfd >= 0 && NULL != *socketargp ) {
4457c478bd9Sstevel@tonic-gate 	(*(sseip->lssei_std_functions.lssf_close_fn))( intfd, *socketargp );
4467c478bd9Sstevel@tonic-gate     }
4477c478bd9Sstevel@tonic-gate     return( -1 );
4487c478bd9Sstevel@tonic-gate }
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate static int
ldapssl_connect(const char * hostlist,int defport,int timeout,unsigned long options,struct lextiof_session_private * sessionarg,struct lextiof_socket_private ** socketargp)4527c478bd9Sstevel@tonic-gate ldapssl_connect(const char *hostlist, int defport, int timeout,
4537c478bd9Sstevel@tonic-gate 	unsigned long options, struct lextiof_session_private *sessionarg,
4547c478bd9Sstevel@tonic-gate 	struct lextiof_socket_private **socketargp )
4557c478bd9Sstevel@tonic-gate {
4567c478bd9Sstevel@tonic-gate     return( do_ldapssl_connect( hostlist, defport, timeout, options,
4577c478bd9Sstevel@tonic-gate 		sessionarg, socketargp, 0 ));
4587c478bd9Sstevel@tonic-gate }
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate static int
ldapssl_clientauth_connect(const char * hostlist,int defport,int timeout,unsigned long options,struct lextiof_session_private * sessionarg,struct lextiof_socket_private ** socketargp)4627c478bd9Sstevel@tonic-gate ldapssl_clientauth_connect(const char *hostlist, int defport, int timeout,
4637c478bd9Sstevel@tonic-gate 	unsigned long options, struct lextiof_session_private *sessionarg,
4647c478bd9Sstevel@tonic-gate 	struct lextiof_socket_private **socketargp )
4657c478bd9Sstevel@tonic-gate {
4667c478bd9Sstevel@tonic-gate     return( do_ldapssl_connect( hostlist, defport, timeout, options,
4677c478bd9Sstevel@tonic-gate 		sessionarg, socketargp, 1 ));
4687c478bd9Sstevel@tonic-gate }
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate static void
ldapssl_disposehandle(LDAP * ld,struct lextiof_session_private * sessionarg)4727c478bd9Sstevel@tonic-gate ldapssl_disposehandle(LDAP *ld, struct lextiof_session_private *sessionarg)
4737c478bd9Sstevel@tonic-gate {
4747c478bd9Sstevel@tonic-gate     PRLDAPSessionInfo				sei;
4757c478bd9Sstevel@tonic-gate     LDAPSSLSessionInfo				*sseip;
4767c478bd9Sstevel@tonic-gate     LDAP_X_EXTIOF_DISPOSEHANDLE_CALLBACK	*disposehdl_fn;
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate     memset( &sei, 0, sizeof( sei ));
4797c478bd9Sstevel@tonic-gate     sei.seinfo_size = PRLDAP_SESSIONINFO_SIZE;
4807c478bd9Sstevel@tonic-gate     if ( prldap_get_session_info( ld, NULL, &sei ) == LDAP_SUCCESS ) {
4817c478bd9Sstevel@tonic-gate 	sseip = (LDAPSSLSessionInfo *)sei.seinfo_appdata;
4827c478bd9Sstevel@tonic-gate 	disposehdl_fn = sseip->lssei_std_functions.lssf_disposehdl_fn;
4837c478bd9Sstevel@tonic-gate 	ldapssl_free_session_info( &sseip );
4847c478bd9Sstevel@tonic-gate 	(*disposehdl_fn)( ld, sessionarg );
4857c478bd9Sstevel@tonic-gate     }
4867c478bd9Sstevel@tonic-gate }
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate /*
4907c478bd9Sstevel@tonic-gate  * Install I/O routines from libsec and NSPR into libldap to allow libldap
4917c478bd9Sstevel@tonic-gate  * to do SSL.
4927c478bd9Sstevel@tonic-gate  *
4937c478bd9Sstevel@tonic-gate  * We rely on libprldap to provide most of the functions, and then we override
4947c478bd9Sstevel@tonic-gate  * a few of them to support SSL.
4957c478bd9Sstevel@tonic-gate  */
4967c478bd9Sstevel@tonic-gate int
4977c478bd9Sstevel@tonic-gate LDAP_CALL
ldapssl_install_routines(LDAP * ld)4987c478bd9Sstevel@tonic-gate ldapssl_install_routines( LDAP *ld )
4997c478bd9Sstevel@tonic-gate {
5007c478bd9Sstevel@tonic-gate #ifndef LDAP_SSLIO_HOOKS
5017c478bd9Sstevel@tonic-gate     ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL );
5027c478bd9Sstevel@tonic-gate     return( -1 );
5037c478bd9Sstevel@tonic-gate #else
5047c478bd9Sstevel@tonic-gate     struct ldap_x_ext_io_fns	iofns;
5057c478bd9Sstevel@tonic-gate     LDAPSSLSessionInfo		*ssip;
5067c478bd9Sstevel@tonic-gate     PRLDAPSessionInfo		sei;
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate /*
5097c478bd9Sstevel@tonic-gate  * This is done within ldap_init() and
5107c478bd9Sstevel@tonic-gate  * ldap_init() is called from ldapssl_init()
5117c478bd9Sstevel@tonic-gate  */
5127c478bd9Sstevel@tonic-gate #ifndef _SOLARIS_SDK
5137c478bd9Sstevel@tonic-gate     if ( prldap_install_routines(
5147c478bd9Sstevel@tonic-gate 		ld,
5157c478bd9Sstevel@tonic-gate 		1 /* shared -- we have to assume it is */ )
5167c478bd9Sstevel@tonic-gate 		!= LDAP_SUCCESS ) {
5177c478bd9Sstevel@tonic-gate 	return( -1 );
5187c478bd9Sstevel@tonic-gate     }
5197c478bd9Sstevel@tonic-gate #endif /*_SOLARIS_SDK*/
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate     /*
5227c478bd9Sstevel@tonic-gate      * Allocate our own session information.
5237c478bd9Sstevel@tonic-gate      */
5247c478bd9Sstevel@tonic-gate     if ( NULL == ( ssip = (LDAPSSLSessionInfo *)PR_Calloc( 1,
5257c478bd9Sstevel@tonic-gate 		sizeof( LDAPSSLSessionInfo )))) {
5267c478bd9Sstevel@tonic-gate 	ldap_set_lderrno( ld, LDAP_NO_MEMORY, NULL, NULL );
5277c478bd9Sstevel@tonic-gate 	return( -1 );
5287c478bd9Sstevel@tonic-gate     }
5297c478bd9Sstevel@tonic-gate     /*
5307c478bd9Sstevel@tonic-gate      * Initialize session info.
5317c478bd9Sstevel@tonic-gate      * XXX: it would be nice to be able to set these on a per-session basis:
5327c478bd9Sstevel@tonic-gate      *          lssei_using_pcks_fns
5337c478bd9Sstevel@tonic-gate      *          lssei_certdbh
5347c478bd9Sstevel@tonic-gate      */
5357c478bd9Sstevel@tonic-gate     ssip->lssei_ssl_strength = default_ssl_strength;
5367c478bd9Sstevel@tonic-gate     ssip->lssei_using_pcks_fns = using_pkcs_functions;
5377c478bd9Sstevel@tonic-gate     ssip->lssei_certdbh = CERT_GetDefaultCertDB();
5387c478bd9Sstevel@tonic-gate #ifdef _SOLARIS_SDK
5397c478bd9Sstevel@tonic-gate     /*
5407c478bd9Sstevel@tonic-gate      * This is part of a hack to allow the ssl portion of the
5417c478bd9Sstevel@tonic-gate      * library to call the ldap library gethostbyaddr resolver.
5427c478bd9Sstevel@tonic-gate      */
5437c478bd9Sstevel@tonic-gate     ssip->ld = ld;
5447c478bd9Sstevel@tonic-gate #endif	/* _SOLARIS_SDK */
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate     /*
5477c478bd9Sstevel@tonic-gate      * override a few functions, saving a pointer to the standard function
5487c478bd9Sstevel@tonic-gate      * in each case so we can call it from our SSL savvy functions.
5497c478bd9Sstevel@tonic-gate      */
5507c478bd9Sstevel@tonic-gate     memset( &iofns, 0, sizeof(iofns));
5517c478bd9Sstevel@tonic-gate     iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
5527c478bd9Sstevel@tonic-gate     if ( ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns ) < 0 ) {
5537c478bd9Sstevel@tonic-gate 	ldapssl_free_session_info( &ssip );
5547c478bd9Sstevel@tonic-gate 	return( -1 );
5557c478bd9Sstevel@tonic-gate     }
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate     /* override socket, connect, and ioctl */
5587c478bd9Sstevel@tonic-gate     ssip->lssei_std_functions.lssf_connect_fn = iofns.lextiof_connect;
5597c478bd9Sstevel@tonic-gate     iofns.lextiof_connect = ldapssl_connect;
5607c478bd9Sstevel@tonic-gate     ssip->lssei_std_functions.lssf_close_fn = iofns.lextiof_close;
5617c478bd9Sstevel@tonic-gate     iofns.lextiof_close = ldapssl_close;
5627c478bd9Sstevel@tonic-gate     ssip->lssei_std_functions.lssf_disposehdl_fn = iofns.lextiof_disposehandle;
5637c478bd9Sstevel@tonic-gate     iofns.lextiof_disposehandle = ldapssl_disposehandle;
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate     if ( ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns ) < 0 ) {
5667c478bd9Sstevel@tonic-gate 	ldapssl_free_session_info( &ssip );
5677c478bd9Sstevel@tonic-gate 	return( -1 );
5687c478bd9Sstevel@tonic-gate     }
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate     /*
5717c478bd9Sstevel@tonic-gate      * Store session info. for later retrieval.
5727c478bd9Sstevel@tonic-gate      */
5737c478bd9Sstevel@tonic-gate     sei.seinfo_size = PRLDAP_SESSIONINFO_SIZE;
5747c478bd9Sstevel@tonic-gate     sei.seinfo_appdata = (void *)ssip;
5757c478bd9Sstevel@tonic-gate     if ( prldap_set_session_info( ld, NULL, &sei ) != LDAP_SUCCESS ) {
5767c478bd9Sstevel@tonic-gate 	return( -1 );
5777c478bd9Sstevel@tonic-gate     }
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate     return( 0 );
5807c478bd9Sstevel@tonic-gate #endif
5817c478bd9Sstevel@tonic-gate }
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate /*
5857c478bd9Sstevel@tonic-gate  * Set the SSL strength for an existing SSL-enabled LDAP session handle.
5867c478bd9Sstevel@tonic-gate  *
5877c478bd9Sstevel@tonic-gate  * See the description of ldapssl_serverauth_init() above for valid
5887c478bd9Sstevel@tonic-gate  * sslstrength values. If ld is NULL, the default for new LDAP session
5897c478bd9Sstevel@tonic-gate  * handles is set.
5907c478bd9Sstevel@tonic-gate  *
5917c478bd9Sstevel@tonic-gate  * Returns 0 if all goes well and -1 if an error occurs.
5927c478bd9Sstevel@tonic-gate  */
5937c478bd9Sstevel@tonic-gate int
5947c478bd9Sstevel@tonic-gate LDAP_CALL
ldapssl_set_strength(LDAP * ld,int sslstrength)5957c478bd9Sstevel@tonic-gate ldapssl_set_strength( LDAP *ld, int sslstrength )
5967c478bd9Sstevel@tonic-gate {
5977c478bd9Sstevel@tonic-gate     int                 rc = 0; /* assume success */
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate     if ( sslstrength != LDAPSSL_AUTH_WEAK &&
6007c478bd9Sstevel@tonic-gate                 sslstrength != LDAPSSL_AUTH_CERT &&
6017c478bd9Sstevel@tonic-gate                 sslstrength != LDAPSSL_AUTH_CNCHECK ) {
6027c478bd9Sstevel@tonic-gate         rc = -1;
6037c478bd9Sstevel@tonic-gate     } else {
6047c478bd9Sstevel@tonic-gate         if ( NULL == ld ) {     /* set default strength */
6057c478bd9Sstevel@tonic-gate             default_ssl_strength = sslstrength;
6067c478bd9Sstevel@tonic-gate         } else {                /* set session-specific strength */
6077c478bd9Sstevel@tonic-gate             PRLDAPSessionInfo   sei;
6087c478bd9Sstevel@tonic-gate             LDAPSSLSessionInfo  *sseip;
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate             memset( &sei, 0, sizeof( sei ));
6117c478bd9Sstevel@tonic-gate             sei.seinfo_size = PRLDAP_SESSIONINFO_SIZE;
6127c478bd9Sstevel@tonic-gate             if ( prldap_get_session_info( ld, NULL, &sei ) == LDAP_SUCCESS )
6137c478bd9Sstevel@tonic-gate {
6147c478bd9Sstevel@tonic-gate                 sseip = (LDAPSSLSessionInfo *)sei.seinfo_appdata;
6157c478bd9Sstevel@tonic-gate                 sseip->lssei_ssl_strength = sslstrength;
6167c478bd9Sstevel@tonic-gate             } else {
6177c478bd9Sstevel@tonic-gate                 rc = -1;
6187c478bd9Sstevel@tonic-gate             }
6197c478bd9Sstevel@tonic-gate         }
6207c478bd9Sstevel@tonic-gate     }
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate     return( rc );
6237c478bd9Sstevel@tonic-gate }
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate int
6267c478bd9Sstevel@tonic-gate LDAP_CALL
ldapssl_enable_clientauth(LDAP * ld,char * keynickname,char * keypasswd,char * certnickname)6277c478bd9Sstevel@tonic-gate ldapssl_enable_clientauth( LDAP *ld, char *keynickname,
6287c478bd9Sstevel@tonic-gate         char *keypasswd, char *certnickname )
6297c478bd9Sstevel@tonic-gate {
6307c478bd9Sstevel@tonic-gate #ifndef LDAP_SSLIO_HOOKS
6317c478bd9Sstevel@tonic-gate     ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL );
6327c478bd9Sstevel@tonic-gate     return( -1 );
6337c478bd9Sstevel@tonic-gate #else
6347c478bd9Sstevel@tonic-gate     struct ldap_x_ext_io_fns	iofns;
6357c478bd9Sstevel@tonic-gate     LDAPSSLSessionInfo		*ssip;
6367c478bd9Sstevel@tonic-gate     PRLDAPSessionInfo		sei;
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate     /*
6397c478bd9Sstevel@tonic-gate      * Check parameters
6407c478bd9Sstevel@tonic-gate      */
6417c478bd9Sstevel@tonic-gate     if ( certnickname == NULL || keypasswd == NULL ) {
6427c478bd9Sstevel@tonic-gate 	ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
6437c478bd9Sstevel@tonic-gate 	return( -1 );
6447c478bd9Sstevel@tonic-gate     }
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate     /*
6477c478bd9Sstevel@tonic-gate      * Update session info. data structure.
6487c478bd9Sstevel@tonic-gate      */
6497c478bd9Sstevel@tonic-gate     sei.seinfo_size = PRLDAP_SESSIONINFO_SIZE;
6507c478bd9Sstevel@tonic-gate     if ( prldap_get_session_info( ld, NULL, &sei ) != LDAP_SUCCESS ) {
6517c478bd9Sstevel@tonic-gate 	return( -1 );
6527c478bd9Sstevel@tonic-gate     }
6537c478bd9Sstevel@tonic-gate     ssip = (LDAPSSLSessionInfo *)sei.seinfo_appdata;
6547c478bd9Sstevel@tonic-gate     if ( NULL == ssip ) {
6557c478bd9Sstevel@tonic-gate 	ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
6567c478bd9Sstevel@tonic-gate 	return( -1 );
6577c478bd9Sstevel@tonic-gate     }
6587c478bd9Sstevel@tonic-gate     ssip->lssei_certnickname = PL_strdup( certnickname );
6597c478bd9Sstevel@tonic-gate     ssip->lssei_keypasswd = PL_strdup( keypasswd );
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate     if ( NULL == ssip->lssei_certnickname || NULL == ssip->lssei_keypasswd ) {
6627c478bd9Sstevel@tonic-gate 	ldap_set_lderrno( ld, LDAP_NO_MEMORY, NULL, NULL );
6637c478bd9Sstevel@tonic-gate 	return( -1 );
6647c478bd9Sstevel@tonic-gate     }
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate     if ( check_clientauth_nicknames_and_passwd( ld, ssip ) != 0 ) {
6677c478bd9Sstevel@tonic-gate 	return( -1 );
6687c478bd9Sstevel@tonic-gate     }
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate     /*
6717c478bd9Sstevel@tonic-gate      * replace standard SSL CONNECT function with client auth aware one
6727c478bd9Sstevel@tonic-gate      */
6737c478bd9Sstevel@tonic-gate     memset( &iofns, 0, sizeof(iofns));
6747c478bd9Sstevel@tonic-gate     iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
6757c478bd9Sstevel@tonic-gate     if ( ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns )
6767c478bd9Sstevel@tonic-gate 		!= 0 ) {
6777c478bd9Sstevel@tonic-gate 	return( -1 );
6787c478bd9Sstevel@tonic-gate     }
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate     if ( iofns.lextiof_connect != ldapssl_connect ) {
6817c478bd9Sstevel@tonic-gate 	/* standard SSL setup has not done */
6827c478bd9Sstevel@tonic-gate 	ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL );
6837c478bd9Sstevel@tonic-gate 	return( -1 );
6847c478bd9Sstevel@tonic-gate     }
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate     iofns.lextiof_connect = ldapssl_clientauth_connect;
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate     if ( ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns )
6897c478bd9Sstevel@tonic-gate 		!= 0 ) {
6907c478bd9Sstevel@tonic-gate 	return( -1 );
6917c478bd9Sstevel@tonic-gate     }
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate     return( 0 );
6947c478bd9Sstevel@tonic-gate #endif
6957c478bd9Sstevel@tonic-gate }
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate static void
ldapssl_free_session_info(LDAPSSLSessionInfo ** ssipp)6997c478bd9Sstevel@tonic-gate ldapssl_free_session_info( LDAPSSLSessionInfo **ssipp )
7007c478bd9Sstevel@tonic-gate {
7017c478bd9Sstevel@tonic-gate     if ( NULL != ssipp && NULL != *ssipp ) {
7027c478bd9Sstevel@tonic-gate 	if ( NULL != (*ssipp)->lssei_certnickname ) {
7037c478bd9Sstevel@tonic-gate 	    PL_strfree( (*ssipp)->lssei_certnickname );
7047c478bd9Sstevel@tonic-gate 	    (*ssipp)->lssei_certnickname = NULL;
7057c478bd9Sstevel@tonic-gate 	}
7067c478bd9Sstevel@tonic-gate 	if ( NULL != (*ssipp)->lssei_keypasswd ) {
7077c478bd9Sstevel@tonic-gate 	    PL_strfree( (*ssipp)->lssei_keypasswd );
7087c478bd9Sstevel@tonic-gate 	    (*ssipp)->lssei_keypasswd = NULL;
7097c478bd9Sstevel@tonic-gate 	}
7107c478bd9Sstevel@tonic-gate 	PR_Free( *ssipp );
7117c478bd9Sstevel@tonic-gate 	*ssipp = NULL;
7127c478bd9Sstevel@tonic-gate     }
7137c478bd9Sstevel@tonic-gate }
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate static void
ldapssl_free_socket_info(LDAPSSLSocketInfo ** soipp)7177c478bd9Sstevel@tonic-gate ldapssl_free_socket_info( LDAPSSLSocketInfo **soipp )
7187c478bd9Sstevel@tonic-gate {
7197c478bd9Sstevel@tonic-gate     if ( NULL != soipp && NULL != *soipp ) {
7207c478bd9Sstevel@tonic-gate 	PR_Free( *soipp );
7217c478bd9Sstevel@tonic-gate 	*soipp = NULL;
7227c478bd9Sstevel@tonic-gate     }
7237c478bd9Sstevel@tonic-gate }
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 
726*1da57d55SToomas Soome /* this function provides cert authentication.  This is called during
7277c478bd9Sstevel@tonic-gate  * the SSL_Handshake process.  Once the cert has been retrieved from
728*1da57d55SToomas Soome  * the server, the it is checked, using VerifyCertNow(), then
7297c478bd9Sstevel@tonic-gate  * the cn is checked against the host name, set with SSL_SetURL()
7307c478bd9Sstevel@tonic-gate  */
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate static int
ldapssl_AuthCertificate(void * sessionarg,PRFileDesc * fd,PRBool checkSig,PRBool isServer)7337c478bd9Sstevel@tonic-gate ldapssl_AuthCertificate(void *sessionarg, PRFileDesc *fd, PRBool checkSig,
7347c478bd9Sstevel@tonic-gate 	PRBool isServer)
7357c478bd9Sstevel@tonic-gate {
7367c478bd9Sstevel@tonic-gate     SECStatus		rv = SECFailure;
7377c478bd9Sstevel@tonic-gate     LDAPSSLSessionInfo	*sseip;
7387c478bd9Sstevel@tonic-gate     CERTCertificate	*cert;
7397c478bd9Sstevel@tonic-gate     SECCertUsage	certUsage;
7407c478bd9Sstevel@tonic-gate     char		*hostname = (char *)0;
741*1da57d55SToomas Soome 
7427c478bd9Sstevel@tonic-gate     if (!sessionarg || !socket)
7437c478bd9Sstevel@tonic-gate 	return rv;
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate     sseip = (LDAPSSLSessionInfo *)sessionarg;
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate     if (LDAPSSL_AUTH_WEAK == sseip->lssei_ssl_strength ) { /* no check */
7487c478bd9Sstevel@tonic-gate         return SECSuccess;
7497c478bd9Sstevel@tonic-gate     }
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate     if ( isServer ) {
7527c478bd9Sstevel@tonic-gate 	certUsage = certUsageSSLClient;
7537c478bd9Sstevel@tonic-gate     } else {
7547c478bd9Sstevel@tonic-gate 	certUsage = certUsageSSLServer;
7557c478bd9Sstevel@tonic-gate     }
7567c478bd9Sstevel@tonic-gate     cert = SSL_PeerCertificate( fd );
757*1da57d55SToomas Soome 
7587c478bd9Sstevel@tonic-gate     rv = CERT_VerifyCertNow(sseip->lssei_certdbh, cert, checkSig,
7597c478bd9Sstevel@tonic-gate 			certUsage, NULL);
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate     if ( rv != SECSuccess || isServer )
7627c478bd9Sstevel@tonic-gate 	return rv;
763*1da57d55SToomas Soome 
7647c478bd9Sstevel@tonic-gate     if ( LDAPSSL_AUTH_CNCHECK == sseip->lssei_ssl_strength )
7657c478bd9Sstevel@tonic-gate       {
7667c478bd9Sstevel@tonic-gate 	/* cert is OK.  This is the client side of an SSL connection.
7677c478bd9Sstevel@tonic-gate 	 * Now check the name field in the cert against the desired hostname.
768*1da57d55SToomas Soome 	 * NB: This is our only defense against Man-In-The-Middle (MITM)
7697c478bd9Sstevel@tonic-gate 	 * attacks!
7707c478bd9Sstevel@tonic-gate 	 */
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate 	hostname = SSL_RevealURL( fd );
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 	if (hostname && hostname[0]) {
7757c478bd9Sstevel@tonic-gate 	  rv = CERT_VerifyCertName(cert, hostname);
7767c478bd9Sstevel@tonic-gate 	} else  {
7777c478bd9Sstevel@tonic-gate 	  rv = SECFailure;
7787c478bd9Sstevel@tonic-gate      	}
7797c478bd9Sstevel@tonic-gate 	if (hostname)
7807c478bd9Sstevel@tonic-gate 		PORT_Free(hostname);
7817c478bd9Sstevel@tonic-gate 	if (rv != SECSuccess)
7827c478bd9Sstevel@tonic-gate 	  PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
7837c478bd9Sstevel@tonic-gate       }
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate     return((int)rv);
7867c478bd9Sstevel@tonic-gate }
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate /*
7907c478bd9Sstevel@tonic-gate  * called during SSL client auth. when server wants our cert and key.
7917c478bd9Sstevel@tonic-gate  * return 0 if we succeeded and set *pRetCert and *pRetKey, -1 otherwise.
7927c478bd9Sstevel@tonic-gate  * if -1 is returned SSL will proceed without sending a cert.
7937c478bd9Sstevel@tonic-gate  */
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate static int
get_clientauth_data(void * sessionarg,PRFileDesc * prfd,CERTDistNames * caNames,CERTCertificate ** pRetCert,SECKEYPrivateKey ** pRetKey)7967c478bd9Sstevel@tonic-gate get_clientauth_data( void *sessionarg, PRFileDesc *prfd,
7977c478bd9Sstevel@tonic-gate         CERTDistNames *caNames,  CERTCertificate **pRetCert,
7987c478bd9Sstevel@tonic-gate         SECKEYPrivateKey **pRetKey )
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate {
8017c478bd9Sstevel@tonic-gate     LDAPSSLSessionInfo	*ssip;
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate     if (( ssip = (LDAPSSLSessionInfo *)sessionarg ) == NULL ) {
8047c478bd9Sstevel@tonic-gate 	return( -1 );       /* client auth. not enabled */
8057c478bd9Sstevel@tonic-gate     }
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate     return( get_keyandcert( ssip, pRetCert, pRetKey, NULL ));
8087c478bd9Sstevel@tonic-gate }
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate static int
get_keyandcert(LDAPSSLSessionInfo * ssip,CERTCertificate ** pRetCert,SECKEYPrivateKey ** pRetKey,char ** errmsgp)8117c478bd9Sstevel@tonic-gate get_keyandcert( LDAPSSLSessionInfo *ssip,
8127c478bd9Sstevel@tonic-gate 	CERTCertificate **pRetCert, SECKEYPrivateKey **pRetKey,
8137c478bd9Sstevel@tonic-gate 	char **errmsgp )
8147c478bd9Sstevel@tonic-gate {
8157c478bd9Sstevel@tonic-gate     CERTCertificate	*cert;
8167c478bd9Sstevel@tonic-gate     SECKEYPrivateKey	*key;
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate     if (( cert = PK11_FindCertFromNickname( ssip->lssei_certnickname, NULL ))
8197c478bd9Sstevel@tonic-gate 		== NULL ) {
8207c478bd9Sstevel@tonic-gate 	if ( errmsgp != NULL ) {
8217c478bd9Sstevel@tonic-gate 	    *errmsgp = dgettext(TEXT_DOMAIN, "unable to find certificate");
8227c478bd9Sstevel@tonic-gate 	}
8237c478bd9Sstevel@tonic-gate 	return( -1 );
8247c478bd9Sstevel@tonic-gate     }
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate     {
8277c478bd9Sstevel@tonic-gate 	PK11_SetPasswordFunc( get_keypassword );
8287c478bd9Sstevel@tonic-gate     }
829*1da57d55SToomas Soome 
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate     if (( key = PK11_FindKeyByAnyCert( cert, (void *)ssip )) == NULL ) {
8337c478bd9Sstevel@tonic-gate 	CERT_DestroyCertificate( cert );
8347c478bd9Sstevel@tonic-gate 	if ( errmsgp != NULL ) {
8357c478bd9Sstevel@tonic-gate 	    *errmsgp = dgettext(TEXT_DOMAIN, "bad key or key password");
8367c478bd9Sstevel@tonic-gate 	}
8377c478bd9Sstevel@tonic-gate 	return( -1 );
8387c478bd9Sstevel@tonic-gate     }
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate     *pRetCert = cert;
8417c478bd9Sstevel@tonic-gate     *pRetKey = key;
8427c478bd9Sstevel@tonic-gate     return( 0 );
8437c478bd9Sstevel@tonic-gate }
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 
846*1da57d55SToomas Soome /*
8477c478bd9Sstevel@tonic-gate  * This function returns the password to NSS.
8487c478bd9Sstevel@tonic-gate  * This function is enable through PK11_SetPasswordFunc
8497c478bd9Sstevel@tonic-gate  * only if pkcs functions are not being used.
850*1da57d55SToomas Soome  */
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate static char *
get_keypassword(PK11SlotInfo * slot,PRBool retry,void * sessionarg)8537c478bd9Sstevel@tonic-gate get_keypassword( PK11SlotInfo *slot, PRBool retry, void *sessionarg )
8547c478bd9Sstevel@tonic-gate {
8557c478bd9Sstevel@tonic-gate     LDAPSSLSessionInfo	*ssip;
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate     if ( retry)
8587c478bd9Sstevel@tonic-gate       return (NULL);
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate     ssip = (LDAPSSLSessionInfo *)sessionarg;
8617c478bd9Sstevel@tonic-gate     if ( NULL == ssip ) {
8627c478bd9Sstevel@tonic-gate 	return( NULL );
8637c478bd9Sstevel@tonic-gate     }
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate     return( ssip->lssei_keypasswd );
8667c478bd9Sstevel@tonic-gate }
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 
8697c478bd9Sstevel@tonic-gate /*
8707c478bd9Sstevel@tonic-gate  * performs some basic checks on clientauth cert and key/password
8717c478bd9Sstevel@tonic-gate  *
8727c478bd9Sstevel@tonic-gate  * XXXmcs: could perform additional checks... see servers/slapd/ssl.c
8737c478bd9Sstevel@tonic-gate  *	1) check expiration
8747c478bd9Sstevel@tonic-gate  *	2) check that public key in cert matches private key
8757c478bd9Sstevel@tonic-gate  * see ns/netsite/ldap/servers/slapd/ssl.c:slapd_ssl_init() for example code.
8767c478bd9Sstevel@tonic-gate  */
8777c478bd9Sstevel@tonic-gate static int
check_clientauth_nicknames_and_passwd(LDAP * ld,LDAPSSLSessionInfo * ssip)8787c478bd9Sstevel@tonic-gate check_clientauth_nicknames_and_passwd( LDAP *ld, LDAPSSLSessionInfo *ssip )
8797c478bd9Sstevel@tonic-gate {
8807c478bd9Sstevel@tonic-gate     char		*errmsg = NULL;
8817c478bd9Sstevel@tonic-gate     CERTCertificate	*cert = NULL;
8827c478bd9Sstevel@tonic-gate     SECKEYPrivateKey	*key = NULL;
8837c478bd9Sstevel@tonic-gate     int rv;
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate     rv = get_keyandcert( ssip, &cert, &key, &errmsg );
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate     if ( rv != 0 ) {
8887c478bd9Sstevel@tonic-gate     	if ( errmsg != NULL ) {
8897c478bd9Sstevel@tonic-gate 	    errmsg = strdup( errmsg );
8907c478bd9Sstevel@tonic-gate 	}
8917c478bd9Sstevel@tonic-gate 	ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, errmsg );
8927c478bd9Sstevel@tonic-gate 	return( -1 );
8937c478bd9Sstevel@tonic-gate     }
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate     if ( cert != NULL ) {
8967c478bd9Sstevel@tonic-gate 	CERT_DestroyCertificate( cert );
8977c478bd9Sstevel@tonic-gate     }
8987c478bd9Sstevel@tonic-gate     if ( key != NULL ) {
8997c478bd9Sstevel@tonic-gate 	SECKEY_DestroyPrivateKey( key );
9007c478bd9Sstevel@tonic-gate     }
9017c478bd9Sstevel@tonic-gate     return( 0 );
9027c478bd9Sstevel@tonic-gate }
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate #if 0	/* NOT_NEEDED_IN_LIBLDAP */
906*1da57d55SToomas Soome /* there are patches and kludges.  this is both.  force some linkers to
9077c478bd9Sstevel@tonic-gate  * link this stuff in
9087c478bd9Sstevel@tonic-gate  */
9097c478bd9Sstevel@tonic-gate int stubs_o_stuff( void )
9107c478bd9Sstevel@tonic-gate {
9117c478bd9Sstevel@tonic-gate     PRExplodedTime exploded;
9127c478bd9Sstevel@tonic-gate     PLArenaPool pool;
913*1da57d55SToomas Soome 
9147c478bd9Sstevel@tonic-gate     const char *name ="t";
9157c478bd9Sstevel@tonic-gate     PRUint32 size = 0, align = 0;
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate     PR_ImplodeTime( &exploded );
9187c478bd9Sstevel@tonic-gate     PL_InitArenaPool( &pool, name, size, align);
9197c478bd9Sstevel@tonic-gate     PR_Cleanup();
9207c478bd9Sstevel@tonic-gate     PR_fprintf((PRFileDesc*)stderr, "Bad IDEA!!");
9217c478bd9Sstevel@tonic-gate 
9227c478bd9Sstevel@tonic-gate     return 0;
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate }
9257c478bd9Sstevel@tonic-gate #endif	/* NOT_NEEDED_IN_LIBLDAP */
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate /*
9297c478bd9Sstevel@tonic-gate  * Import the file descriptor corresponding to the socket of an already
9307c478bd9Sstevel@tonic-gate  * open LDAP connection into SSL, and update the socket and session
9317c478bd9Sstevel@tonic-gate  * information accordingly.
9327c478bd9Sstevel@tonic-gate  */
ldapssl_import_fd(LDAP * ld,int secure)9337c478bd9Sstevel@tonic-gate int ldapssl_import_fd ( LDAP *ld, int secure )
9347c478bd9Sstevel@tonic-gate {
9357c478bd9Sstevel@tonic-gate     PRLDAPSessionInfo   sei;
9367c478bd9Sstevel@tonic-gate     PRLDAPSocketInfo    soi;
9377c478bd9Sstevel@tonic-gate     LDAPSSLSocketInfo   *ssoip = NULL;
9387c478bd9Sstevel@tonic-gate     LDAPSSLSessionInfo  *sseip;
9397c478bd9Sstevel@tonic-gate     PRFileDesc          *sslfd = NULL;
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate     /*
9437c478bd9Sstevel@tonic-gate      * Retrieve session info. so we can store a pointer to our session info.
9447c478bd9Sstevel@tonic-gate      * in our socket info. later.
9457c478bd9Sstevel@tonic-gate      */
9467c478bd9Sstevel@tonic-gate     memset( &sei, 0, sizeof(sei));
9477c478bd9Sstevel@tonic-gate     sei.seinfo_size = PRLDAP_SESSIONINFO_SIZE;
9487c478bd9Sstevel@tonic-gate     if ( prldap_get_session_info( ld, NULL, &sei ) != LDAP_SUCCESS ) {
9497c478bd9Sstevel@tonic-gate         return( -1 );
9507c478bd9Sstevel@tonic-gate     }
9517c478bd9Sstevel@tonic-gate     sseip = (LDAPSSLSessionInfo *)sei.seinfo_appdata;
9527c478bd9Sstevel@tonic-gate 
9537c478bd9Sstevel@tonic-gate 
9547c478bd9Sstevel@tonic-gate     /*
9557c478bd9Sstevel@tonic-gate      * Retrieve socket info. so we have the PRFileDesc.
9567c478bd9Sstevel@tonic-gate      */
9577c478bd9Sstevel@tonic-gate     memset( &soi, 0, sizeof(soi));
9587c478bd9Sstevel@tonic-gate     soi.soinfo_size = PRLDAP_SOCKETINFO_SIZE;
9597c478bd9Sstevel@tonic-gate     if ( prldap_get_default_socket_info( ld, &soi ) != LDAP_SUCCESS ) {
9607c478bd9Sstevel@tonic-gate         return( -1 );
9617c478bd9Sstevel@tonic-gate     }
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate     /*
9647c478bd9Sstevel@tonic-gate      * Allocate a structure to hold our socket-specific data.
9657c478bd9Sstevel@tonic-gate      */
9667c478bd9Sstevel@tonic-gate     if ( NULL == ( ssoip = PR_Calloc( 1, sizeof( LDAPSSLSocketInfo )))) {
9677c478bd9Sstevel@tonic-gate         goto reset_socket_and_exit_with_error;
9687c478bd9Sstevel@tonic-gate     }
9697c478bd9Sstevel@tonic-gate     ssoip->soi_sessioninfo = sseip;
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate     /*
9727c478bd9Sstevel@tonic-gate      * Add SSL layer and let the standard NSPR to LDAP layer and enable SSL.
9737c478bd9Sstevel@tonic-gate      */
9747c478bd9Sstevel@tonic-gate     if (( sslfd = SSL_ImportFD( NULL, soi.soinfo_prfd )) == NULL ) {
9757c478bd9Sstevel@tonic-gate         goto reset_socket_and_exit_with_error;
9767c478bd9Sstevel@tonic-gate     }
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate     if ( SSL_OptionSet( sslfd, SSL_SECURITY, secure ) != SECSuccess ||
9797c478bd9Sstevel@tonic-gate                 SSL_OptionSet( sslfd, SSL_HANDSHAKE_AS_CLIENT, secure )
9807c478bd9Sstevel@tonic-gate                 != SECSuccess || ( secure && SSL_ResetHandshake( sslfd,
9817c478bd9Sstevel@tonic-gate                 PR_FALSE ) != SECSuccess )) {
9827c478bd9Sstevel@tonic-gate         goto reset_socket_and_exit_with_error;
9837c478bd9Sstevel@tonic-gate     }
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate     /*
9867c478bd9Sstevel@tonic-gate      * Let the standard NSPR to LDAP layer know about the new socket and
9877c478bd9Sstevel@tonic-gate      * our own socket-specific data.
9887c478bd9Sstevel@tonic-gate      */
9897c478bd9Sstevel@tonic-gate     soi.soinfo_prfd = sslfd;
9907c478bd9Sstevel@tonic-gate     soi.soinfo_appdata = (void *)ssoip;
9917c478bd9Sstevel@tonic-gate     if ( prldap_set_default_socket_info( ld, &soi ) != LDAP_SUCCESS ) {
9927c478bd9Sstevel@tonic-gate         goto reset_socket_and_exit_with_error;
9937c478bd9Sstevel@tonic-gate     }
9947c478bd9Sstevel@tonic-gate 
9957c478bd9Sstevel@tonic-gate     /*
9967c478bd9Sstevel@tonic-gate      * Install certificate hook function.
9977c478bd9Sstevel@tonic-gate      */
9987c478bd9Sstevel@tonic-gate     if ( SSL_AuthCertificateHook( soi.soinfo_prfd,
9997c478bd9Sstevel@tonic-gate                                   (SSLAuthCertificate)ldapssl_AuthCertificate,
10007c478bd9Sstevel@tonic-gate                                   (void *)CERT_GetDefaultCertDB()) != 0 ) {
10017c478bd9Sstevel@tonic-gate         goto reset_socket_and_exit_with_error;
10027c478bd9Sstevel@tonic-gate     }
10037c478bd9Sstevel@tonic-gate 
10047c478bd9Sstevel@tonic-gate     if ( SSL_GetClientAuthDataHook( soi.soinfo_prfd,
10057c478bd9Sstevel@tonic-gate                 get_clientauth_data, sseip->lssei_certnickname ? sseip : NULL )
10067c478bd9Sstevel@tonic-gate 		!= 0 ) {
10077c478bd9Sstevel@tonic-gate         goto reset_socket_and_exit_with_error;
10087c478bd9Sstevel@tonic-gate     }
10097c478bd9Sstevel@tonic-gate 
10107c478bd9Sstevel@tonic-gate     return 0;
10117c478bd9Sstevel@tonic-gate 
10127c478bd9Sstevel@tonic-gate  reset_socket_and_exit_with_error:
10137c478bd9Sstevel@tonic-gate     if ( NULL != sslfd ) {
10147c478bd9Sstevel@tonic-gate         /*
10157c478bd9Sstevel@tonic-gate          * "Unimport" the socket from SSL, i.e. get rid of the upper layer of
10167c478bd9Sstevel@tonic-gate          * the file descriptor stack, which represents SSL.
10177c478bd9Sstevel@tonic-gate          */
10187c478bd9Sstevel@tonic-gate         soi.soinfo_prfd = sslfd;
10197c478bd9Sstevel@tonic-gate         sslfd = PR_PopIOLayer( soi.soinfo_prfd, PR_TOP_IO_LAYER );
10207c478bd9Sstevel@tonic-gate         sslfd->dtor( sslfd );
10217c478bd9Sstevel@tonic-gate     }
10227c478bd9Sstevel@tonic-gate     if ( NULL != ssoip ) {
10237c478bd9Sstevel@tonic-gate         ldapssl_free_socket_info( &ssoip );
10247c478bd9Sstevel@tonic-gate         soi.soinfo_appdata = NULL;
10257c478bd9Sstevel@tonic-gate     }
10267c478bd9Sstevel@tonic-gate     prldap_set_default_socket_info( ld, &soi );
10277c478bd9Sstevel@tonic-gate 
10287c478bd9Sstevel@tonic-gate     return( -1 );
10297c478bd9Sstevel@tonic-gate }
10307c478bd9Sstevel@tonic-gate 
10317c478bd9Sstevel@tonic-gate 
10327c478bd9Sstevel@tonic-gate /*
10337c478bd9Sstevel@tonic-gate  * Reset an LDAP session from SSL to a non-secure status.
10347c478bd9Sstevel@tonic-gate  * Basically, this function undoes the work done by ldapssl_install_routines.
10357c478bd9Sstevel@tonic-gate  */
ldapssl_reset_to_nonsecure(LDAP * ld)10367c478bd9Sstevel@tonic-gate int ldapssl_reset_to_nonsecure ( LDAP *ld )
10377c478bd9Sstevel@tonic-gate {
10387c478bd9Sstevel@tonic-gate     PRLDAPSessionInfo   sei;
10397c478bd9Sstevel@tonic-gate     LDAPSSLSessionInfo  *sseip;
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate     struct ldap_x_ext_io_fns    iofns;
10427c478bd9Sstevel@tonic-gate     int rc = 0;
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate     /*
10457c478bd9Sstevel@tonic-gate      * Retrieve session info.
10467c478bd9Sstevel@tonic-gate      */
10477c478bd9Sstevel@tonic-gate     memset( &sei, 0, sizeof(sei));
10487c478bd9Sstevel@tonic-gate     sei.seinfo_size = PRLDAP_SESSIONINFO_SIZE;
10497c478bd9Sstevel@tonic-gate     if ( prldap_get_session_info( ld, NULL, &sei ) != LDAP_SUCCESS ) {
10507c478bd9Sstevel@tonic-gate         return( -1 );
10517c478bd9Sstevel@tonic-gate     }
10527c478bd9Sstevel@tonic-gate     sseip = (LDAPSSLSessionInfo *)sei.seinfo_appdata;
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate     if ( sseip != NULL ) {
10557c478bd9Sstevel@tonic-gate         /*
10567c478bd9Sstevel@tonic-gate          * Reset the standard extended io functions.
10577c478bd9Sstevel@tonic-gate          */
10587c478bd9Sstevel@tonic-gate         memset( &iofns, 0, sizeof(iofns));
10597c478bd9Sstevel@tonic-gate         iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE;
10607c478bd9Sstevel@tonic-gate         if ( ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns )
10617c478bd9Sstevel@tonic-gate 		< 0) {
10627c478bd9Sstevel@tonic-gate             rc = -1;
10637c478bd9Sstevel@tonic-gate             goto free_session_info;
10647c478bd9Sstevel@tonic-gate         }
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate         /* reset socket, connect, and ioctl */
10677c478bd9Sstevel@tonic-gate         iofns.lextiof_connect = sseip->lssei_std_functions.lssf_connect_fn;
10687c478bd9Sstevel@tonic-gate         iofns.lextiof_close = sseip->lssei_std_functions.lssf_close_fn;
10697c478bd9Sstevel@tonic-gate         iofns.lextiof_disposehandle =
10707c478bd9Sstevel@tonic-gate 			sseip->lssei_std_functions.lssf_disposehdl_fn;
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate         if ( ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns )
10737c478bd9Sstevel@tonic-gate 		< 0) {
10747c478bd9Sstevel@tonic-gate             rc = -1;
10757c478bd9Sstevel@tonic-gate             goto free_session_info;
10767c478bd9Sstevel@tonic-gate         }
10777c478bd9Sstevel@tonic-gate 
10787c478bd9Sstevel@tonic-gate free_session_info:
10797c478bd9Sstevel@tonic-gate         ldapssl_free_session_info( &sseip );
10807c478bd9Sstevel@tonic-gate         sei.seinfo_appdata = NULL;
10817c478bd9Sstevel@tonic-gate         if ( prldap_set_session_info( ld, NULL, &sei ) != LDAP_SUCCESS ) {
10827c478bd9Sstevel@tonic-gate             rc = -1;
10837c478bd9Sstevel@tonic-gate         }
10847c478bd9Sstevel@tonic-gate     } /* if ( sseip && *sseip ) */
1085*1da57d55SToomas Soome 
10867c478bd9Sstevel@tonic-gate     if ( ldap_set_option( ld, LDAP_OPT_SSL, LDAP_OPT_OFF ) < 0 ) {
10877c478bd9Sstevel@tonic-gate         return (-1);
10887c478bd9Sstevel@tonic-gate     }
10897c478bd9Sstevel@tonic-gate 
10907c478bd9Sstevel@tonic-gate     return rc;
10917c478bd9Sstevel@tonic-gate }
10927c478bd9Sstevel@tonic-gate 
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate #ifdef _SOLARIS_SDK
10957c478bd9Sstevel@tonic-gate static void
_nss_initf_ipnodes(nss_db_params_t * p)10967c478bd9Sstevel@tonic-gate _nss_initf_ipnodes(nss_db_params_t *p)
10977c478bd9Sstevel@tonic-gate {
10987c478bd9Sstevel@tonic-gate 	static char *no_service = "";
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 	p->name = NSS_DBNAM_IPNODES;
11017c478bd9Sstevel@tonic-gate         p->flags |= NSS_USE_DEFAULT_CONFIG;
11027c478bd9Sstevel@tonic-gate         p->default_config = host_service == NULL ? no_service : host_service;
11037c478bd9Sstevel@tonic-gate }
11047c478bd9Sstevel@tonic-gate 
11057c478bd9Sstevel@tonic-gate static void
_nss_initf_hosts(nss_db_params_t * p)11067c478bd9Sstevel@tonic-gate _nss_initf_hosts(nss_db_params_t *p)
11077c478bd9Sstevel@tonic-gate {
11087c478bd9Sstevel@tonic-gate 	static char *no_service = "";
11097c478bd9Sstevel@tonic-gate 
11107c478bd9Sstevel@tonic-gate 	p->name = NSS_DBNAM_HOSTS;
11117c478bd9Sstevel@tonic-gate         p->flags |= NSS_USE_DEFAULT_CONFIG;
11127c478bd9Sstevel@tonic-gate         p->default_config = host_service == NULL ? no_service : host_service;
11137c478bd9Sstevel@tonic-gate }
11147c478bd9Sstevel@tonic-gate 
11157c478bd9Sstevel@tonic-gate static struct hostent *
_switch_gethostbyaddr_r(const char * addr,int len,int type,struct hostent * result,char * buffer,int buflen,int * h_errnop)11167c478bd9Sstevel@tonic-gate _switch_gethostbyaddr_r(const char *addr, int len, int type,
11177c478bd9Sstevel@tonic-gate 	struct hostent *result, char *buffer, int buflen,
11187c478bd9Sstevel@tonic-gate 	int *h_errnop)
11197c478bd9Sstevel@tonic-gate {
11207c478bd9Sstevel@tonic-gate         nss_XbyY_args_t arg;
11217c478bd9Sstevel@tonic-gate         nss_status_t    res;
11227c478bd9Sstevel@tonic-gate 	int		(*str2ent)();
11237c478bd9Sstevel@tonic-gate 	void		(*nss_initf)();
11247c478bd9Sstevel@tonic-gate 	nss_db_root_t	*nss_db_root;
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate 	if (AF_INET == type) {
11277c478bd9Sstevel@tonic-gate 		str2ent		= str2hostent;
11287c478bd9Sstevel@tonic-gate 		nss_initf	= _nss_initf_hosts;
1129*1da57d55SToomas Soome 		nss_db_root	= &db_root_hosts;
11307c478bd9Sstevel@tonic-gate 	} else if (AF_INET6 == type) {
11317c478bd9Sstevel@tonic-gate 		str2ent		= str2hostent6;
11327c478bd9Sstevel@tonic-gate 		nss_initf	= _nss_initf_ipnodes;
11337c478bd9Sstevel@tonic-gate 		nss_db_root	= &db_root_ipnodes;
11347c478bd9Sstevel@tonic-gate 	} else {
11357c478bd9Sstevel@tonic-gate 		return NULL;
11367c478bd9Sstevel@tonic-gate 	}
11377c478bd9Sstevel@tonic-gate 
11387c478bd9Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2ent);
11397c478bd9Sstevel@tonic-gate 
11407c478bd9Sstevel@tonic-gate         arg.key.hostaddr.addr	= addr;
11417c478bd9Sstevel@tonic-gate         arg.key.hostaddr.len	= len;
11427c478bd9Sstevel@tonic-gate         arg.key.hostaddr.type	= type;
11437c478bd9Sstevel@tonic-gate         arg.stayopen		= 0;
11447c478bd9Sstevel@tonic-gate 
11457c478bd9Sstevel@tonic-gate         res = nss_search(nss_db_root, nss_initf,
11467c478bd9Sstevel@tonic-gate         	NSS_DBOP_HOSTS_BYADDR, &arg);
11477c478bd9Sstevel@tonic-gate         arg.status = res;
11487c478bd9Sstevel@tonic-gate         *h_errnop = arg.h_errno;
11497c478bd9Sstevel@tonic-gate         return (struct hostent *)NSS_XbyY_FINI(&arg);
11507c478bd9Sstevel@tonic-gate }
11517c478bd9Sstevel@tonic-gate 
11527c478bd9Sstevel@tonic-gate /*
11537c478bd9Sstevel@tonic-gate  * ns_gethostbyaddr is used to be a substitute gethostbyaddr for
11547c478bd9Sstevel@tonic-gate  * libldap when ssl will need to determine the fully qualified
11557c478bd9Sstevel@tonic-gate  * host name from an address when it is unsafe to use the normal
11567c478bd9Sstevel@tonic-gate  * nameservice functions.
11577c478bd9Sstevel@tonic-gate  *
11587c478bd9Sstevel@tonic-gate  * Note that the ldap name service resolver calls this with the address as
11597c478bd9Sstevel@tonic-gate  * a character string - which we must convert into address form.
11607c478bd9Sstevel@tonic-gate  */
11617c478bd9Sstevel@tonic-gate 
11627c478bd9Sstevel@tonic-gate /*ARGSUSED*/
11637c478bd9Sstevel@tonic-gate static LDAPHostEnt *
ns_gethostbyaddr(const char * addr,int len,int type,LDAPHostEnt * result,char * buffer,int buflen,int * statusp,void * extradata)11647c478bd9Sstevel@tonic-gate ns_gethostbyaddr(const char *addr, int len, int type,
11657c478bd9Sstevel@tonic-gate 	LDAPHostEnt *result, char *buffer, int buflen, int *statusp,
11667c478bd9Sstevel@tonic-gate 	void *extradata)
11677c478bd9Sstevel@tonic-gate {
11687c478bd9Sstevel@tonic-gate 	LDAPHostEnt	*ldap_hent;
11697c478bd9Sstevel@tonic-gate 	int		h_errno;
11707c478bd9Sstevel@tonic-gate 	struct hostent	h_ent;
11717c478bd9Sstevel@tonic-gate 	struct hostent	*h_e = NULL;
11727c478bd9Sstevel@tonic-gate 	struct in_addr	a;
11737c478bd9Sstevel@tonic-gate 	struct in6_addr	a6;
11747c478bd9Sstevel@tonic-gate 	int		inet_error;	/* error returned by inet_pton */
11757c478bd9Sstevel@tonic-gate 
11767c478bd9Sstevel@tonic-gate 
11777c478bd9Sstevel@tonic-gate 	if (addr == NULL || result == NULL || buffer == NULL ||
11787c478bd9Sstevel@tonic-gate 			(type != AF_INET && type != AF_INET6))
11797c478bd9Sstevel@tonic-gate 		return (NULL);
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate 
11827c478bd9Sstevel@tonic-gate 	(void) memset(&h_ent, 0, sizeof (h_ent));
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate 	if (AF_INET == type) {
11857c478bd9Sstevel@tonic-gate 		if (inet_pton(type, addr, &a.s_addr) == 1) {
11867c478bd9Sstevel@tonic-gate 			h_e = _switch_gethostbyaddr_r((char *)&a,
11877c478bd9Sstevel@tonic-gate 				sizeof (a.s_addr), type, &h_ent,
11887c478bd9Sstevel@tonic-gate 				buffer, buflen, &h_errno);
11897c478bd9Sstevel@tonic-gate 		}
11907c478bd9Sstevel@tonic-gate 	} else if (AF_INET6 == type) {
11917c478bd9Sstevel@tonic-gate 		if (inet_pton(type, addr, &a6.s6_addr) == 1) {
11927c478bd9Sstevel@tonic-gate 			h_e = _switch_gethostbyaddr_r((char *)&a6,
11937c478bd9Sstevel@tonic-gate 				sizeof (a6.s6_addr), type, &h_ent,
11947c478bd9Sstevel@tonic-gate 				buffer, buflen, &h_errno);
11957c478bd9Sstevel@tonic-gate 		}
11967c478bd9Sstevel@tonic-gate 	}
11977c478bd9Sstevel@tonic-gate 
11987c478bd9Sstevel@tonic-gate 	if (h_e == NULL) {
11997c478bd9Sstevel@tonic-gate 		ldap_hent = NULL;
12007c478bd9Sstevel@tonic-gate 	} else {
12017c478bd9Sstevel@tonic-gate 		(void) memset(result, 0, sizeof (LDAPHostEnt));
12027c478bd9Sstevel@tonic-gate 		ldap_hent = result;
12037c478bd9Sstevel@tonic-gate 		result->ldaphe_name = h_e->h_name;
12047c478bd9Sstevel@tonic-gate  		result->ldaphe_aliases = h_e->h_aliases;
12057c478bd9Sstevel@tonic-gate  		result->ldaphe_addrtype = h_e->h_addrtype;
12067c478bd9Sstevel@tonic-gate  		result->ldaphe_length = h_e->h_length;
12077c478bd9Sstevel@tonic-gate  		result->ldaphe_addr_list = h_e->h_addr_list;
12087c478bd9Sstevel@tonic-gate 	}
12097c478bd9Sstevel@tonic-gate 	return (ldap_hent);
12107c478bd9Sstevel@tonic-gate }
12117c478bd9Sstevel@tonic-gate 
12127c478bd9Sstevel@tonic-gate /*
12137c478bd9Sstevel@tonic-gate  * ldapssl_install_gethostbyaddr attempts to prevent recursion in
12147c478bd9Sstevel@tonic-gate  * gethostbyaddr calls when an ip address is given to ssl. This ip address
12157c478bd9Sstevel@tonic-gate  * must be resolved to a host name.
1216*1da57d55SToomas Soome  *
12177c478bd9Sstevel@tonic-gate  * For example, libsldap cannot use LDAP to resolve this address to a
12187c478bd9Sstevel@tonic-gate  * name because of recursion. The caller is instructing libldap to skip
12197c478bd9Sstevel@tonic-gate  * the specified name service when resolving addresses for the specified
12207c478bd9Sstevel@tonic-gate  * ldap connection.
12217c478bd9Sstevel@tonic-gate  *
12227c478bd9Sstevel@tonic-gate  * Currently only ldap and dns name services always return fully qualified
12237c478bd9Sstevel@tonic-gate  * names. The other name services (files, nis, and nisplus) will returned
12247c478bd9Sstevel@tonic-gate  * fully qualified names if the host names are stored as fully qualified names
12257c478bd9Sstevel@tonic-gate  * in these name services.
12267c478bd9Sstevel@tonic-gate  *
12277c478bd9Sstevel@tonic-gate  * Note:
12287c478bd9Sstevel@tonic-gate  *
12297c478bd9Sstevel@tonic-gate  *	Since host_service applies to all connections, calling
12307c478bd9Sstevel@tonic-gate  *	ldapssl_install_gethostbyaddr with different name services to
12317c478bd9Sstevel@tonic-gate  *	skip will lead to unpredictable results.
12327c478bd9Sstevel@tonic-gate  *
12337c478bd9Sstevel@tonic-gate  * Returns:
12347c478bd9Sstevel@tonic-gate  *	0	if success
12357c478bd9Sstevel@tonic-gate  *	-1	if failure
12367c478bd9Sstevel@tonic-gate  */
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate int
ldapssl_install_gethostbyaddr(LDAP * ld,const char * skip)12397c478bd9Sstevel@tonic-gate ldapssl_install_gethostbyaddr(LDAP *ld, const char *skip)
12407c478bd9Sstevel@tonic-gate {
12417c478bd9Sstevel@tonic-gate 	enum __nsw_parse_err		pserr;
12427c478bd9Sstevel@tonic-gate 	struct __nsw_switchconfig	*conf;
12437c478bd9Sstevel@tonic-gate 	struct __nsw_lookup		*lkp;
12447c478bd9Sstevel@tonic-gate 	struct ldap_dns_fns		dns_fns;
12457c478bd9Sstevel@tonic-gate 	char				*name_list = NULL;
12467c478bd9Sstevel@tonic-gate 	char				*tmp;
12477c478bd9Sstevel@tonic-gate 	const char			*name;
12487c478bd9Sstevel@tonic-gate 	int				len;
12497c478bd9Sstevel@tonic-gate 	boolean_t			got_skip = B_FALSE;
12507c478bd9Sstevel@tonic-gate 
12517c478bd9Sstevel@tonic-gate 	/*
12527c478bd9Sstevel@tonic-gate 	 * db_root_hosts.lock mutex is used to ensure that the name list
12537c478bd9Sstevel@tonic-gate 	 * is not in use by the name service switch while we are updating
12547c478bd9Sstevel@tonic-gate 	 * the host_service
12557c478bd9Sstevel@tonic-gate 	 */
12567c478bd9Sstevel@tonic-gate 
12577c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&db_root_hosts.lock);
12587c478bd9Sstevel@tonic-gate 	conf = __nsw_getconfig("hosts", &pserr);
12597c478bd9Sstevel@tonic-gate 	if (conf == NULL) {
12607c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&db_root_hosts.lock);
12617c478bd9Sstevel@tonic-gate 		return (0);
12627c478bd9Sstevel@tonic-gate 	}
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate 	/* check for ldap and count other backends */
12657c478bd9Sstevel@tonic-gate 	for (lkp = conf->lookups; lkp != NULL; lkp = lkp->next) {
12667c478bd9Sstevel@tonic-gate 		name = lkp->service_name;
12677c478bd9Sstevel@tonic-gate 		if (strcmp(name, skip) == 0) {
12687c478bd9Sstevel@tonic-gate 			got_skip = B_TRUE;
12697c478bd9Sstevel@tonic-gate 			continue;
12707c478bd9Sstevel@tonic-gate 		}
12717c478bd9Sstevel@tonic-gate 		if (name_list == NULL)
12727c478bd9Sstevel@tonic-gate 			name_list = strdup(name);
12737c478bd9Sstevel@tonic-gate 		else {
12747c478bd9Sstevel@tonic-gate 			len = strlen(name_list);
12757c478bd9Sstevel@tonic-gate 			tmp = realloc(name_list, len + strlen(name) + 2);
12767c478bd9Sstevel@tonic-gate 			if (tmp == NULL) {
12777c478bd9Sstevel@tonic-gate 				free(name_list);
12787c478bd9Sstevel@tonic-gate 				name_list = NULL;
12797c478bd9Sstevel@tonic-gate 			} else {
12807c478bd9Sstevel@tonic-gate 				name_list = tmp;
12817c478bd9Sstevel@tonic-gate 				name_list[len++] = ' ';
12827c478bd9Sstevel@tonic-gate 				(void) strcpy(name_list+len, name);
12837c478bd9Sstevel@tonic-gate 			}
12847c478bd9Sstevel@tonic-gate 		}
12857c478bd9Sstevel@tonic-gate 		if (name_list == NULL) {	/* alloc error */
12867c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&db_root_hosts.lock);
12877c478bd9Sstevel@tonic-gate 			__nsw_freeconfig(conf);
12887c478bd9Sstevel@tonic-gate 			return (-1);
12897c478bd9Sstevel@tonic-gate 		}
12907c478bd9Sstevel@tonic-gate 	}
12917c478bd9Sstevel@tonic-gate 	__nsw_freeconfig(conf);
12927c478bd9Sstevel@tonic-gate 	if (!got_skip) {
12937c478bd9Sstevel@tonic-gate 		/*
12947c478bd9Sstevel@tonic-gate 		 * Since skip name service not used for hosts, we do not need
12957c478bd9Sstevel@tonic-gate 		 * to install our private address resolution function
12967c478bd9Sstevel@tonic-gate 		 */
12977c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&db_root_hosts.lock);
12987c478bd9Sstevel@tonic-gate 		if (name_list != NULL)
12997c478bd9Sstevel@tonic-gate 			free(name_list);
13007c478bd9Sstevel@tonic-gate 		return (0);
13017c478bd9Sstevel@tonic-gate 	}
13027c478bd9Sstevel@tonic-gate 	if (host_service != NULL)
13037c478bd9Sstevel@tonic-gate 		free(host_service);
13047c478bd9Sstevel@tonic-gate 	host_service = name_list;
13057c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&db_root_hosts.lock);
13067c478bd9Sstevel@tonic-gate 
13077c478bd9Sstevel@tonic-gate 	if (ldap_get_option(ld, LDAP_OPT_DNS_FN_PTRS, &dns_fns) != 0)
13087c478bd9Sstevel@tonic-gate 		return (-1);
13097c478bd9Sstevel@tonic-gate 	dns_fns.lddnsfn_gethostbyaddr = ns_gethostbyaddr;
13107c478bd9Sstevel@tonic-gate 	if (ldap_set_option(ld, LDAP_OPT_DNS_FN_PTRS, &dns_fns) != 0)
13117c478bd9Sstevel@tonic-gate 		return (-1);
13127c478bd9Sstevel@tonic-gate 	return (0);
13137c478bd9Sstevel@tonic-gate }
13147c478bd9Sstevel@tonic-gate #endif	/* _SOLARIS_SDK */
13157c478bd9Sstevel@tonic-gate #endif /* NET_SSL */
1316